#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 Dictionary> ranks; public Dictionary> Ranks { get { return ranks; } set { ranks = value; } } protected GenealogyGraph(GenealogyGraph original, Cloner cloner) : base(original, cloner) { Ranks = new Dictionary>(original.Ranks); contentMap = new Dictionary(original.contentMap); idMap = new Dictionary(original.idMap); } public override IDeepCloneable Clone(Cloner cloner) { return new GenealogyGraph(this, cloner); } [StorableConstructor] protected GenealogyGraph(bool deserializing) : base(deserializing) { } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { 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 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); if (!Ranks[node.Rank].Any()) Ranks.Remove(node.Rank); } base.RemoveVertex(vertex); } 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(); } public void ExportDot(string path) { var sb = new StringBuilder(); sb.AppendLine("graph fragmentgraph {"); foreach (var v in Vertices) { sb.AppendLine("\"" + v.Id + "\"[shape=circle, style = filled, width = " + v.Degree / 2.0 + ", label = " + v.Rank + ", fillcolor = \"" + ColorTranslator.ToHtml(GetColor(v)) + "\"]"); } foreach (var a in Arcs.Select(x => (IGenealogyGraphArc)x)) { 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 { 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); } } }