Index: branches/HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/VariableInteractionNetwork.cs
===================================================================
--- branches/HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/VariableInteractionNetwork.cs	(revision 14622)
+++ branches/HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/VariableInteractionNetwork.cs	(revision 14655)
@@ -23,4 +23,5 @@
 using System.Collections;
 using System.Collections.Generic;
+using System.Diagnostics.Eventing.Reader;
 using System.Linq;
 using System.Text;
@@ -46,16 +47,16 @@
     /// <returns></returns>
     public static VariableInteractionNetwork FromNmseAndVariableImpacts(double[] nmse, DoubleMatrix variableImpacts, double nmseThreshold = 0.2, double varImpactThreshold = 0.0) {
-      if(variableImpacts.Rows != variableImpacts.Columns) throw new ArgumentException();
+      if (variableImpacts.Rows != variableImpacts.Columns) throw new ArgumentException();
       var network = new VariableInteractionNetwork();
 
       Dictionary<string, IVertex> name2funVertex = new Dictionary<string, IVertex>(); // store vertexes representing the function for each target so we can easily add incoming arcs later on
       string[] varNames = variableImpacts.RowNames.ToArray();
-      if(nmse.Length != varNames.Length) throw new ArgumentException();
-
-      for(int i = 0; i < varNames.Length; i++) {
+      if (nmse.Length != varNames.Length) throw new ArgumentException();
+
+      for (int i = 0; i < varNames.Length; i++) {
         var name = varNames[i];
         var varVertex = new VariableNetworkNode() { Label = name };
         network.AddVertex(varVertex);
-        if(nmse[i] < nmseThreshold) {
+        if (nmse[i] < nmseThreshold) {
           var functionVertex = new JunctionNetworkNode() { Label = "f_" + name };
           name2funVertex.Add(name, functionVertex);
@@ -69,10 +70,10 @@
       var rel = variableImpacts.CloneAsMatrix();
       // make sure the diagonal is not considered
-      for(int i = 0; i < rel.GetLength(0); i++) rel[i, i] = double.NegativeInfinity;
+      for (int i = 0; i < rel.GetLength(0); i++) rel[i, i] = double.NegativeInfinity;
 
       var addedArcs = AddArcs(network, rel, varNames, name2funVertex, varImpactThreshold);
-      while(addedArcs.Any()) {
+      while (addedArcs.Any()) {
         var cycles = network.FindShortestCycles().ToList();
-        while(cycles.Any()) {
+        while (cycles.Any()) {
           // delete weakest link
           var weakestArc = cycles.SelectMany(cycle => network.ArcsForCycle(cycle)).OrderBy(a => a.Weight).First();
@@ -88,12 +89,76 @@
     }
 
+    /// <summary>
+    /// Produces a combined network from two networks. 
+    /// The set of nodes of the new network is the union of the node sets of the two input networks.
+    /// The set of edges of the new network is the union of the edge sets of the two input networks.
+    /// Added and removed nodes and edges are marked so that it is possible to visualize the network difference using graphviz
+    /// </summary>
+    /// <returns></returns>
+    public static VariableInteractionNetwork CalculateNetworkDiff(
+      VariableInteractionNetwork from,
+      VariableInteractionNetwork to) {
+      var g = new VariableInteractionNetwork();
+
+      // add nodes which are in both networks
+      foreach (var node in from.Vertices.Intersect(to.Vertices, new VertexLabelComparer())) {
+        g.AddVertex((IVertex)node.Clone());
+      }
+      // add nodes only in from network
+      foreach (var node in from.Vertices.Except(to.Vertices, new VertexLabelComparer())) {
+        var fromVertex = (IVertex)node.Clone();
+        fromVertex.Label += " (removed)";
+        g.AddVertex(fromVertex);
+      }
+      // add nodes only in to network
+      foreach (var node in to.Vertices.Except(from.Vertices, new VertexLabelComparer())) {
+        var fromVertex = (IVertex)node.Clone();
+        fromVertex.Label += " (added)";
+        g.AddVertex(fromVertex);
+      }
+
+      // add edges which are in both networks
+      foreach (var arc in from.Arcs.Intersect(to.Arcs, new ArcComparer())) {
+        g.AddArc(
+          g.Vertices.Single(v => arc.Source.Label == v.Label),
+          g.Vertices.Single(v => arc.Target.Label == v.Label)
+        );
+      }
+      // add edges only in from network
+      foreach (var arc in from.Arcs.Except(to.Arcs, new ArcComparer())) {
+        var fromVertex =
+          g.Vertices.Single(v => v.Label == arc.Source.Label || v.Label == arc.Source.Label + " (removed)");
+        var toVertex =
+          g.Vertices.Single(v => v.Label == arc.Target.Label || v.Label == arc.Target.Label + " (removed)");
+        var newArc = g.AddArc(
+          fromVertex,
+          toVertex
+        );
+        newArc.Label += " (removed)";
+      }
+      // add arcs only in to network
+      foreach (var arc in to.Arcs.Except(from.Arcs, new ArcComparer())) {
+        var fromVertex =
+          g.Vertices.Single(v => v.Label == arc.Source.Label || v.Label == arc.Source.Label + " (added)");
+        var toVertex =
+          g.Vertices.Single(v => v.Label == arc.Target.Label || v.Label == arc.Target.Label + " (added)");
+        var newArc = g.AddArc(
+          fromVertex,
+          toVertex
+        );
+        newArc.Label += " (added)";
+      }
+      return g;
+    }
+
+
     private static List<IArc> AddArcs(VariableInteractionNetwork network, double[,] impacts, string[] varNames, Dictionary<string, IVertex> name2funVertex, double threshold = 0.0) {
       var newArcs = new List<IArc>();
-      for(int row = 0; row < impacts.GetLength(0); row++) {
-        if(!name2funVertex.ContainsKey(varNames[row])) continue; // this variable does not have an associated function (considered as independent)
+      for (int row = 0; row < impacts.GetLength(0); row++) {
+        if (!name2funVertex.ContainsKey(varNames[row])) continue; // this variable does not have an associated function (considered as independent)
 
         var rowVector = Enumerable.Range(0, impacts.GetLength(0)).Select(col => impacts[row, col]).ToArray();
         var max = rowVector.Max();
-        if(max > threshold) {
+        if (max > threshold) {
           var idxOfMax = Array.IndexOf<double>(rowVector, max);
           impacts[row, idxOfMax] = double.NegativeInfinity; // edge is not considered anymore
@@ -121,5 +186,5 @@
     private IList<IArc> ArcsForCycle(IList<IVertex> cycle) {
       var res = new List<IArc>();
-      foreach(var t in cycle.Zip(cycle.Skip(1), Tuple.Create)) {
+      foreach (var t in cycle.Zip(cycle.Skip(1), Tuple.Create)) {
         var src = t.Item1;
         var dst = t.Item2;
@@ -133,6 +198,6 @@
     // finds the shortest cycles in the graph and returns all sub-graphs containing only the nodes / edges within the cycle
     public IEnumerable<IList<IVertex>> FindShortestCycles() {
-      foreach(var startVariable in base.Vertices.OfType<VariableNetworkNode>()) {
-        foreach(var cycle in FindShortestCycles(startVariable))
+      foreach (var startVariable in base.Vertices.OfType<VariableNetworkNode>()) {
+        foreach (var cycle in FindShortestCycles(startVariable))
           yield return cycle;
       }
@@ -154,14 +219,14 @@
     // TODO efficiency
     private void FindShortestCycles(Queue<List<IVertex>> queue, int maxPathLength, List<List<IVertex>> cycles) {
-      while(queue.Any()) {
+      while (queue.Any()) {
         var path = queue.Dequeue();
-        if(path.Count > 1 && path.First() == path.Last()) {
+        if (path.Count > 1 && path.First() == path.Last()) {
           cycles.Add(new List<IVertex>(path)); // found a cycle
-        } else if(path.Count >= maxPathLength) {
+        } else if (path.Count >= maxPathLength) {
           continue;
         } else {
           var lastVert = path.Last();
           var neighbours = base.Arcs.Where(a => a.Source == lastVert).Select(a => a.Target);
-          foreach(var neighbour in neighbours) {
+          foreach (var neighbour in neighbours) {
             queue.Enqueue(new List<IVertex>(path.Concat(new IVertex[] { neighbour })));
           }
@@ -177,13 +242,12 @@
 
       var name2idx = new Dictionary<string, int>();
-      for(int i = 0; i < names.Length; i++) {
+      for (int i = 0; i < names.Length; i++) {
         name2idx.Add(names[i], i);
       }
 
-      foreach(var arc in Arcs) {
+      foreach (var arc in Arcs) {
         // only consider arcs going into a junction node
         var target = arc.Target as JunctionNetworkNode;
-        if(target != null)
-        {
+        if (target != null) {
           var srcVarName = arc.Source.Label;
           // each function node must have exactly one outgoing arc
@@ -199,18 +263,52 @@
 
     public string ToGraphVizString() {
+      Func<string, string> NodeAndEdgeColor = (str) =>
+      {
+        if (string.IsNullOrEmpty(str)) return "black";
+        else if (str.Contains("removed")) return "red";
+        else if (str.Contains("added")) return "green";
+        else return "black";
+      };
+
       var sb = new StringBuilder();
       sb.AppendLine("digraph {");
       sb.AppendLine("rankdir=LR");
-      foreach(var v in Vertices.OfType<VariableNetworkNode>()) {
-        sb.AppendFormat("\"{0}\" [shape=oval]", v.Label).AppendLine();
-      }
-      foreach(var v in Vertices.OfType<JunctionNetworkNode>()) {
-        sb.AppendFormat("\"{0}\" [shape=box]", v.Label).AppendLine();
-      }
-      foreach(var arc in Arcs) {
-        sb.AppendFormat("\"{0}\"->\"{1}\"", arc.Source.Label, arc.Target.Label).AppendLine();
+      foreach (var v in Vertices.OfType<VariableNetworkNode>()) {
+        sb.AppendFormat("\"{0}\" [shape=oval, color={1}]", v.Label, NodeAndEdgeColor(v.Label)).AppendLine();
+      }
+      foreach (var v in Vertices.OfType<JunctionNetworkNode>()) {
+        sb.AppendFormat("\"{0}\" [shape=box, color={1}]", v.Label, NodeAndEdgeColor(v.Label)).AppendLine();
+      }
+      foreach (var arc in Arcs) {
+        sb.AppendFormat("\"{0}\"->\"{1}\" [color=\"{3}\"]", arc.Source.Label, arc.Target.Label, arc.Label, NodeAndEdgeColor(arc.Label)).AppendLine();
       }
       sb.AppendLine("}");
       return sb.ToString();
+    }
+  }
+
+  public class VertexLabelComparer : IEqualityComparer<IVertex> {
+    public bool Equals(IVertex x, IVertex y) {
+      if (x == null && y == null) return true;
+      if (x != null && y != null) {
+        return x.Label == y.Label;
+      } else return false;
+    }
+
+    public int GetHashCode(IVertex obj) {
+      return obj.Label.GetHashCode();
+    }
+  }
+
+  public class ArcComparer : IEqualityComparer<IArc> {
+    public bool Equals(IArc x, IArc y) {
+      if (x == null && y == null) return true;
+      if (x != null && y != null) {
+        return x.Source.Label == y.Source.Label && x.Target.Label == y.Target.Label;
+      } else return false;
+    }
+
+    public int GetHashCode(IArc obj) {
+      return obj.Source.Label.GetHashCode() ^ obj.Target.Label.GetHashCode();
     }
   }
