#region License Information /* HeuristicLab * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Text; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.EvolutionTracking { [StorableClass] [Item("GenealogyGraph", "A class representing a genealogy graph")] public class GenealogyGraph : DirectedGraph, IGenealogyGraph { private Dictionary contentMap; private Dictionary idMap; private readonly Comparison> compareArcs = (a, b) => { var da = a.Data; var db = b.Data; if ((da == null && db == null) || (da != null && db != null)) return 0; if (da == null) return -1; return 1; }; protected Dictionary> ranks; public IEnumerable>> Ranks { get { return ranks.Select(x => new KeyValuePair>(x.Key, x.Value)); } } public IEnumerable GetByRank(double rank) { return ranks.ContainsKey(rank) ? ranks[rank] : Enumerable.Empty(); } protected GenealogyGraph(GenealogyGraph original, Cloner cloner) : base(original, cloner) { RebuildDictionaries(); // sort arcs so that in the case of crossover (child vertex with two parents) // the arc which holds the fragment information is always last foreach (var arcList in base.Vertices.Select(v => (List)v.InArcs)) { arcList.Sort((a, b) => compareArcs((IGenealogyGraphArc)a, (IGenealogyGraphArc)b)); } } public override IDeepCloneable Clone(Cloner cloner) { return new GenealogyGraph(this, cloner); } [StorableConstructor] protected GenealogyGraph(bool deserializing) : base(deserializing) { } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { RebuildDictionaries(); foreach (var arcList in base.Vertices.Select(v => (List)v.InArcs)) { arcList.Sort((a, b) => compareArcs((IGenealogyGraphArc)a, (IGenealogyGraphArc)b)); } } public GenealogyGraph() { ranks = new Dictionary>(); contentMap = new Dictionary(); idMap = new Dictionary(); } new public IEnumerable Vertices { get { return base.Vertices.Select(x => (IGenealogyGraphNode)x); } } new public IEnumerable Arcs { get { return base.Arcs.Select(x => (IGenealogyGraphArc)x); } } public override IArc AddArc(IVertex source, IVertex target) { var arc = new GenealogyGraphArc((IGenealogyGraphNode)source, (IGenealogyGraphNode)target); base.AddArc(arc); return arc; } public override void AddVertex(IVertex vertex) { base.AddVertex(vertex); var genealogyGraphNode = (IGenealogyGraphNode)vertex; if (contentMap.ContainsKey(genealogyGraphNode.Data)) throw new InvalidOperationException("Duplicate content is not allowed in the genealogy graph."); contentMap[genealogyGraphNode.Data] = genealogyGraphNode; if (idMap.ContainsKey(genealogyGraphNode.Id)) throw new InvalidOperationException("Duplicate ids are not allowed in the genealogy graph."); idMap[genealogyGraphNode.Id] = genealogyGraphNode; if (!ranks.ContainsKey(genealogyGraphNode.Rank)) ranks[genealogyGraphNode.Rank] = new List(); ranks[genealogyGraphNode.Rank].Add(genealogyGraphNode); } public override void RemoveVertex(IVertex vertex) { var node = (IGenealogyGraphNode)vertex; contentMap.Remove(node.Data); idMap.Remove(node.Id); if (ranks.ContainsKey(node.Rank)) { ranks[node.Rank].Remove(node); // this call will be slow, use with caution if (!ranks[node.Rank].Any()) ranks.Remove(node.Rank); } base.RemoveVertex(vertex); } public override void RemoveVertices(IEnumerable vertices) { foreach (var v in vertices) this.RemoveVertex(v); } public IGenealogyGraphNode GetByContent(object content) { IGenealogyGraphNode result; contentMap.TryGetValue(content, out result); return result; } public IGenealogyGraphNode GetById(string id) { IGenealogyGraphNode result; idMap.TryGetValue(id, out result); return result; } public bool Contains(object content) { return contentMap.ContainsKey(content); } public event EventHandler GraphUpdated; private void OnGraphUpdated(object sender, EventArgs args) { var updated = GraphUpdated; if (updated != null) updated(sender, args); } public override void Clear() { base.Clear(); ranks.Clear(); contentMap.Clear(); idMap.Clear(); } private void RebuildDictionaries() { contentMap = new Dictionary(); idMap = new Dictionary(); ranks = new Dictionary>(); foreach (var v in Vertices) { contentMap[v.Data] = v; idMap[v.Id] = v; if (ranks.ContainsKey(v.Rank)) { ranks[v.Rank].Add(v); } else { ranks[v.Rank] = new List { v }; } } } public void ExportDot(string path) { var sb = new StringBuilder(); sb.AppendLine("graph fragmentgraph {"); foreach (var v in Vertices) { double width = Math.Max(0.5, v.Degree); sb.AppendLine("\"" + v.Id + "\"[shape=circle, style = filled, width = " + width + ", label = " + v.Rank + "\n" + String.Format("{0:00}", v.Quality) + ", fillcolor = \"" + ColorTranslator.ToHtml(GetColor(v)) + "\"]"); } foreach (var a in Arcs) { sb.AppendLine("\"" + a.Source.Id + "\" -- \"" + a.Target.Id + "\""); } sb.AppendLine("}"); File.WriteAllText(path, sb.ToString()); } private Color GetColor(IGenealogyGraphNode node) { var colorIndex = (int)Math.Round(node.Quality * ColorGradient.Colors.Count); if (colorIndex >= ColorGradient.Colors.Count) return ColorGradient.Colors.Last(); return ColorGradient.Colors[colorIndex]; } } [Item("GenealogyGraph", "A genealogy graph in which the vertex data is of type T")] [StorableClass] public class GenealogyGraph : GenealogyGraph, IGenealogyGraph where T : class, IItem { public GenealogyGraph() { } private GenealogyGraph(GenealogyGraph original, Cloner cloner) : base(original, cloner) { } public override IDeepCloneable Clone(Cloner cloner) { return new GenealogyGraph(this, cloner); } new public IEnumerable> Vertices { get { return base.Vertices.Select(x => (IGenealogyGraphNode)x); } } new public IGenealogyGraphNode GetByContent(object content) { return (IGenealogyGraphNode)base.GetByContent(content); } new public IGenealogyGraphNode GetById(string id) { return (IGenealogyGraphNode)base.GetById(id); } new public IEnumerable> GetByRank(double rank) { return base.GetByRank(rank).Select(x => (IGenealogyGraphNode)x); } public new IEnumerable>>> Ranks { get { return base.Ranks.Select(x => new KeyValuePair>>(x.Key, x.Value.Select(n => (IGenealogyGraphNode)n))); } } } }