Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/Build.cmd
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/Build.cmd	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/Build.cmd	(revision 15929)
@@ -0,0 +1,104 @@
+@ECHO OFF
+
+SET CLEANBEFOREBUILD=
+
+SET SELECTED=
+SET CONFIGURATION=
+SET PLATFORM=
+
+IF "%~1"=="" GOTO :prompt_solution
+
+SET SELECTED=%1
+IF NOT EXIST %SELECTED% (
+  ECHO Solution file %SELECTED% could not be found.
+  GOTO :end
+)
+ECHO Building solution %SELECTED% ...
+GOTO :config_selection
+
+:prompt_solution
+SET /A COUNT=0
+FOR /F "tokens=*" %%A IN ('dir /B *.sln') DO (
+  CALL :forloopbody "%%A"
+)
+
+IF "%COUNT%"=="1" (
+  SET SELECTED=%SOLUTIONS.1%
+  ECHO Building %SOLUTIONS.1% as it is the only solution that was found ...
+  GOTO :config_selection
+)
+
+ECHO Found the following solutions:
+FOR /F "tokens=2* delims=.=" %%A IN ('SET SOLUTIONS.') DO ECHO %%A = %%B
+ECHO.
+SET /P SOLUTIONINDEX=Which solution to build? Type the number: 
+
+SET SELECTED=""
+FOR /F "tokens=2* delims=.=" %%A IN ('SET SOLUTIONS.') DO (
+  IF "%%A"=="%SOLUTIONINDEX%" SET SELECTED=%%B
+)
+
+IF %SELECTED%=="" GOTO :eof
+
+:config_selection
+IF "%~2"==""  GOTO :prompt_config
+
+SET CONFIGURATION=%~2
+ECHO Building configuration %CONFIGURATION% ...
+GOTO :platform_selection
+
+:prompt_config
+SET /P CONFIGURATION=Which configuration to build [Release]: 
+IF "%CONFIGURATION%"=="" SET CONFIGURATION=Release
+
+:platform_selection
+IF "%~3"=="" GOTO :prompt_platform
+  
+SET PLATFORM=%~3
+ECHO Building platform %PLATFORM% ...
+GOTO :clean
+
+:prompt_platform
+SET /P PLATFORM=Which platform to build [Any CPU]: 
+IF "%PLATFORM%"=="" SET PLATFORM=Any CPU
+
+:clean
+IF "%~4"=="" GOTO :prompt_clean
+
+SET CLEANBEFOREBUILD=%~4
+GOTO :main
+
+:prompt_clean
+SET /P CLEANBEFOREBUILD=Would you like to clean before building [n]: 
+IF "%CLEANBEFOREBUILD%"=="" SET CLEANBEFOREBUILD=n
+
+:main
+REM First find the path to the msbuild.exe by performing a registry query
+FOR /F "tokens=1,3 delims=	 " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0"') DO (
+  IF "%%A"=="MSBuildToolsPath" SET MSBUILDPATH=%%B)
+
+REM Then execute msbuild to clean and build the solution
+REM Disable that msbuild creates a cache file of the solution
+SET MSBuildUseNoSolutionCache=1
+REM Run msbuild to clean and then build
+IF "%CLEANBEFOREBUILD%" NEQ "n" (
+  ECHO Cleaning ...
+  %MSBUILDPATH%msbuild.exe %SELECTED% /target:Clean /p:Configuration="%CONFIGURATION%",Platform="%PLATFORM%" /m:2 /nologo /verbosity:q /clp:ErrorsOnly
+)
+ECHO Building ...
+%MSBUILDPATH%msbuild.exe %SELECTED% /target:Build /p:Configuration="%CONFIGURATION%",Platform="%PLATFORM%" /m:2 /nologo /verbosity:q /clp:ErrorsOnly
+
+ECHO.
+ECHO DONE.
+
+:end
+
+PAUSE
+
+GOTO :eof
+
+REM This workaround is necessary so that COUNT gets reevaluated
+:forloopbody
+SET /A COUNT+=1
+SET SOLUTIONS.%COUNT%=%1
+GOTO :eof
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/CreateTargetVariationExperiment.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/CreateTargetVariationExperiment.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/CreateTargetVariationExperiment.cs	(revision 15929)
@@ -0,0 +1,71 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+using HeuristicLab.MainForm;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimizer;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.VariableInteractionNetworks {
+  internal class CreateTargetVariationExperiment : HeuristicLab.MainForm.WindowsForms.MenuItem, IOptimizerUserInterfaceItemProvider {
+    public override string Name {
+      get { return "Create Target Variation &Experiment"; }
+    }
+    public override IEnumerable<string> Structure {
+      get { return new string[] { "&Edit" }; }
+    }
+    public override int Position {
+      get { return 2300; }
+    }
+    public override string ToolTipText {
+      get { return "Create an experiment for varying the target variable"; }
+    }
+
+    protected override void OnToolStripItemSet(EventArgs e) {
+      ToolStripItem.Enabled = false;
+    }
+    protected override void OnActiveViewChanged(object sender, EventArgs e) {
+      IContentView activeView = MainFormManager.MainForm.ActiveView as IContentView;
+      bool enabled = false;
+      if (activeView != null && !activeView.Locked && activeView.Content != null) {
+        var algorithm = activeView.Content as IAlgorithm;
+        if (algorithm != null) {
+          var problem = algorithm.Problem;
+          // make sure the problem data specifies a target variable
+          enabled = problem is IRegressionProblem || problem is IClassificationProblem;
+        }
+      }
+      ToolStripItem.Enabled = enabled;
+    }
+
+    public override void Execute() {
+      IContentView activeView = MainFormManager.MainForm.ActiveView as IContentView;
+      if ((activeView != null) && (activeView.Content != null) && (activeView.Content is IOptimizer) && !activeView.Locked) {
+        using (CreateTargetVariationExperimentDialog dialog = new CreateTargetVariationExperimentDialog((IAlgorithm)activeView.Content)) {
+          if (dialog.ShowDialog() == DialogResult.OK) MainFormManager.MainForm.ShowContent(dialog.Experiment);
+        }
+      }
+    }
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/CreateTargetVariationExperimentDialog.Designer.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/CreateTargetVariationExperimentDialog.Designer.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/CreateTargetVariationExperimentDialog.Designer.cs	(revision 15929)
@@ -0,0 +1,217 @@
+﻿namespace HeuristicLab.VariableInteractionNetworks
+{
+    partial class CreateTargetVariationExperimentDialog
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+      this.repetitionsNumericUpDown = new System.Windows.Forms.NumericUpDown();
+      this.repetitionsLabel = new System.Windows.Forms.Label();
+      this.cancelButton = new System.Windows.Forms.Button();
+      this.okButton = new System.Windows.Forms.Button();
+      this.combinationGroupSizeNumericUpDown = new System.Windows.Forms.NumericUpDown();
+      this.label1 = new System.Windows.Forms.Label();
+      this.combinationsLabel = new System.Windows.Forms.Label();
+      this.combinationCountLabel = new System.Windows.Forms.Label();
+      this.progressBar = new System.Windows.Forms.ProgressBar();
+      this.worker = new System.ComponentModel.BackgroundWorker();
+      ((System.ComponentModel.ISupportInitialize)(this.repetitionsNumericUpDown)).BeginInit();
+      ((System.ComponentModel.ISupportInitialize)(this.combinationGroupSizeNumericUpDown)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // repetitionsNumericUpDown
+      // 
+      this.repetitionsNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.repetitionsNumericUpDown.Location = new System.Drawing.Point(81, 12);
+      this.repetitionsNumericUpDown.Maximum = new decimal(new int[] {
+            1000000,
+            0,
+            0,
+            0});
+      this.repetitionsNumericUpDown.Minimum = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+      this.repetitionsNumericUpDown.Name = "repetitionsNumericUpDown";
+      this.repetitionsNumericUpDown.Size = new System.Drawing.Size(240, 20);
+      this.repetitionsNumericUpDown.TabIndex = 4;
+      this.repetitionsNumericUpDown.ThousandsSeparator = true;
+      this.repetitionsNumericUpDown.Value = new decimal(new int[] {
+            10,
+            0,
+            0,
+            0});
+      this.repetitionsNumericUpDown.Validated += new System.EventHandler(this.repetitionsNumericUpDown_Validated);
+      // 
+      // repetitionsLabel
+      // 
+      this.repetitionsLabel.AutoSize = true;
+      this.repetitionsLabel.Location = new System.Drawing.Point(12, 12);
+      this.repetitionsLabel.Name = "repetitionsLabel";
+      this.repetitionsLabel.Size = new System.Drawing.Size(63, 13);
+      this.repetitionsLabel.TabIndex = 5;
+      this.repetitionsLabel.Text = "&Repetitions:";
+      // 
+      // cancelButton
+      // 
+      this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+      this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+      this.cancelButton.Location = new System.Drawing.Point(246, 66);
+      this.cancelButton.Name = "cancelButton";
+      this.cancelButton.Size = new System.Drawing.Size(75, 23);
+      this.cancelButton.TabIndex = 9;
+      this.cancelButton.Text = "&Cancel";
+      this.cancelButton.UseVisualStyleBackColor = true;
+      this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
+      // 
+      // okButton
+      // 
+      this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+      this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
+      this.okButton.Location = new System.Drawing.Point(165, 66);
+      this.okButton.Name = "okButton";
+      this.okButton.Size = new System.Drawing.Size(75, 23);
+      this.okButton.TabIndex = 10;
+      this.okButton.Text = "&Ok";
+      this.okButton.UseVisualStyleBackColor = true;
+      this.okButton.Click += new System.EventHandler(this.okButton_Click);
+      // 
+      // combinationGroupSizeNumericUpDown
+      // 
+      this.combinationGroupSizeNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.combinationGroupSizeNumericUpDown.Location = new System.Drawing.Point(81, 38);
+      this.combinationGroupSizeNumericUpDown.Maximum = new decimal(new int[] {
+            1000000,
+            0,
+            0,
+            0});
+      this.combinationGroupSizeNumericUpDown.Minimum = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+      this.combinationGroupSizeNumericUpDown.Name = "combinationGroupSizeNumericUpDown";
+      this.combinationGroupSizeNumericUpDown.Size = new System.Drawing.Size(240, 20);
+      this.combinationGroupSizeNumericUpDown.TabIndex = 4;
+      this.combinationGroupSizeNumericUpDown.ThousandsSeparator = true;
+      this.combinationGroupSizeNumericUpDown.Value = new decimal(new int[] {
+            10,
+            0,
+            0,
+            0});
+      this.combinationGroupSizeNumericUpDown.ValueChanged += new System.EventHandler(this.combinationGroupSizeNumericUpDown_Validated);
+      this.combinationGroupSizeNumericUpDown.Validating += new System.ComponentModel.CancelEventHandler(this.combinationGroupSizeNumericUpDown_Validating);
+      this.combinationGroupSizeNumericUpDown.Validated += new System.EventHandler(this.combinationGroupSizeNumericUpDown_Validated);
+      // 
+      // label1
+      // 
+      this.label1.AutoSize = true;
+      this.label1.Location = new System.Drawing.Point(12, 40);
+      this.label1.Name = "label1";
+      this.label1.Size = new System.Drawing.Size(60, 13);
+      this.label1.TabIndex = 5;
+      this.label1.Text = "&Group size:";
+      // 
+      // combinationsLabel
+      // 
+      this.combinationsLabel.AutoSize = true;
+      this.combinationsLabel.Location = new System.Drawing.Point(12, 71);
+      this.combinationsLabel.Name = "combinationsLabel";
+      this.combinationsLabel.Size = new System.Drawing.Size(73, 13);
+      this.combinationsLabel.TabIndex = 11;
+      this.combinationsLabel.Text = "Combinations:";
+      // 
+      // combinationCountLabel
+      // 
+      this.combinationCountLabel.AutoSize = true;
+      this.combinationCountLabel.Location = new System.Drawing.Point(91, 71);
+      this.combinationCountLabel.Name = "combinationCountLabel";
+      this.combinationCountLabel.Size = new System.Drawing.Size(0, 13);
+      this.combinationCountLabel.TabIndex = 12;
+      // 
+      // progressBar
+      // 
+      this.progressBar.Location = new System.Drawing.Point(15, 66);
+      this.progressBar.Name = "progressBar";
+      this.progressBar.Size = new System.Drawing.Size(144, 23);
+      this.progressBar.Step = 1;
+      this.progressBar.TabIndex = 13;
+      this.progressBar.Visible = false;
+      // 
+      // worker
+      // 
+      this.worker.WorkerReportsProgress = true;
+      this.worker.WorkerSupportsCancellation = true;
+      this.worker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.worker_DoWork);
+      this.worker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.worker_ProgressChanged);
+      this.worker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.worker_RunWorkerCompleted);
+      // 
+      // CreateTargetVariationExperimentDialog
+      // 
+      this.AcceptButton = this.okButton;
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.CancelButton = this.cancelButton;
+      this.ClientSize = new System.Drawing.Size(333, 101);
+      this.Controls.Add(this.progressBar);
+      this.Controls.Add(this.combinationCountLabel);
+      this.Controls.Add(this.combinationsLabel);
+      this.Controls.Add(this.okButton);
+      this.Controls.Add(this.cancelButton);
+      this.Controls.Add(this.label1);
+      this.Controls.Add(this.repetitionsLabel);
+      this.Controls.Add(this.combinationGroupSizeNumericUpDown);
+      this.Controls.Add(this.repetitionsNumericUpDown);
+      this.MaximizeBox = false;
+      this.MinimizeBox = false;
+      this.Name = "CreateTargetVariationExperimentDialog";
+      this.ShowIcon = false;
+      this.Text = "Create Target Variation Experiment";
+      this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.CreateTargetVariationExperimentDialog_FormClosing);
+      ((System.ComponentModel.ISupportInitialize)(this.repetitionsNumericUpDown)).EndInit();
+      ((System.ComponentModel.ISupportInitialize)(this.combinationGroupSizeNumericUpDown)).EndInit();
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.NumericUpDown repetitionsNumericUpDown;
+        private System.Windows.Forms.Label repetitionsLabel;
+        private System.Windows.Forms.Button cancelButton;
+        private System.Windows.Forms.Button okButton;
+    private System.Windows.Forms.NumericUpDown combinationGroupSizeNumericUpDown;
+    private System.Windows.Forms.Label label1;
+    private System.Windows.Forms.Label combinationsLabel;
+    private System.Windows.Forms.Label combinationCountLabel;
+    private System.Windows.Forms.ProgressBar progressBar;
+    private System.ComponentModel.BackgroundWorker worker;
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/CreateTargetVariationExperimentDialog.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/CreateTargetVariationExperimentDialog.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/CreateTargetVariationExperimentDialog.cs	(revision 15929)
@@ -0,0 +1,213 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Windows.Forms;
+using HeuristicLab.Common;
+using HeuristicLab.MainForm;
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.VariableInteractionNetworks {
+  public partial class CreateTargetVariationExperimentDialog : Form {
+    public Experiment Experiment { get; private set; }
+
+    public CreateTargetVariationExperimentDialog() : this(null) { }
+    public CreateTargetVariationExperimentDialog(IAlgorithm alg) {
+      InitializeComponent();
+
+      var problem = alg.Problem as IDataAnalysisProblem;
+      var inputCount = problem.ProblemData.AllowedInputVariables.Count() - 1; // -1 because one will be the target
+      if (combinationGroupSizeNumericUpDown.Value > inputCount)
+        combinationGroupSizeNumericUpDown.Value = inputCount;
+      var combinationGroupSize = (int)combinationGroupSizeNumericUpDown.Value;
+      combinationCountLabel.Text = ((inputCount + 1) * EnumerableExtensions.BinomialCoefficient(inputCount, combinationGroupSize)).ToString();
+
+      Experiment = null;
+      okButton.Enabled = alg != null;
+    }
+
+    public static IEnumerable<IOptimizer> CreateVariableCombinations(IAlgorithm algorithm, int combinationGroupSize, int repetitions) {
+      if (algorithm == null)
+        throw new ArgumentNullException("The algorithm parameter must be a valid IAlgorithm instance.");
+
+      var problem = (IDataAnalysisProblem)algorithm.Problem;
+      var problemData = problem.ProblemData;
+
+      var variables = problemData.AllowedInputVariables.ToList();
+      int count = 1;
+      foreach (var target in variables) {
+        var inputs = variables.Where(x => x != target).ToList();
+        var combinations = inputs.Combinations(combinationGroupSize);
+
+        foreach (var combination in combinations) {
+          var h = new HashSet<string>(combination);
+          var alg = (IAlgorithm)algorithm.Clone();
+          alg.Name += " {Target = " + target + ", Inputs = (" + combination.Aggregate((a, b) => a + "," + b) + ")}";
+          problem = (IDataAnalysisProblem)alg.Problem;
+          problemData = problem.ProblemData;
+          foreach (var item in problemData.InputVariables) {
+            problemData.InputVariables.SetItemCheckedState(item, h.Contains(item.Value));
+          }
+          SetTargetName(problemData, target);
+
+          var batchRun = new BatchRun(string.Format("Batchrun {0}", count++)) {
+            Repetitions = repetitions,
+            Optimizer = alg
+          };
+          yield return batchRun;
+        }
+      }
+    }
+
+    private static string GetTargetName(IDataAnalysisProblemData problemData) {
+      var regressionProblemData = problemData as IRegressionProblemData;
+      if (regressionProblemData != null)
+        return regressionProblemData.TargetVariable;
+      var classificationProblemData = problemData as IClassificationProblemData;
+      if (classificationProblemData != null)
+        return classificationProblemData.TargetVariable;
+      throw new ArgumentException("The provided argument must be either a regression or classification problem data.");
+    }
+
+    private static void SetTargetName(IDataAnalysisProblemData problemData, string targetName) {
+      var regressionProblemData = problemData as IRegressionProblemData;
+      if (regressionProblemData != null) {
+        regressionProblemData.TargetVariable = targetName;
+        return;
+      }
+      var classificationProblemData = problemData as IClassificationProblemData;
+      if (classificationProblemData != null) {
+        classificationProblemData.TargetVariable = targetName;
+        return;
+      }
+      throw new ArgumentException("The provided argument must be either a regression or classification problem data.");
+    }
+
+    #region events
+    private void CreateTargetVariationExperimentDialog_FormClosing(object sender, FormClosingEventArgs e) {
+      if (worker.IsBusy) {
+        if (DialogResult != DialogResult.OK) {
+          if (worker.IsBusy) worker.CancelAsync();
+        }
+        e.Cancel = true;
+      }
+    }
+
+    private void repetitionsNumericUpDown_Validated(object sender, EventArgs e) {
+      if (repetitionsNumericUpDown.Text == string.Empty)
+        repetitionsNumericUpDown.Text = repetitionsNumericUpDown.Value.ToString();
+    }
+
+    private void combinationGroupSizeNumericUpDown_Validating(object sender, System.ComponentModel.CancelEventArgs e) {
+      IContentView activeView = MainFormManager.MainForm.ActiveView as IContentView;
+      if (activeView == null) return;
+      var algorithm = (IAlgorithm)activeView.Content;
+      var problem = algorithm.Problem as IDataAnalysisProblem;
+      if (problem == null) return;
+      var inputCount = problem.ProblemData.AllowedInputVariables.Count() - 1;
+      if (combinationGroupSizeNumericUpDown.Value > inputCount)
+        combinationGroupSizeNumericUpDown.Value = inputCount;
+    }
+
+    private void combinationGroupSizeNumericUpDown_Validated(object sender, EventArgs e) {
+      if (combinationGroupSizeNumericUpDown.Text == string.Empty)
+        combinationGroupSizeNumericUpDown.Text = combinationGroupSizeNumericUpDown.Value.ToString();
+
+      IContentView activeView = MainFormManager.MainForm.ActiveView as IContentView;
+      if (activeView == null) return;
+      var algorithm = (IAlgorithm)activeView.Content;
+      var problem = (IDataAnalysisProblem)algorithm.Problem;
+      var inputCount = problem.ProblemData.AllowedInputVariables.Count() - 1;
+      if (combinationGroupSizeNumericUpDown.Value > inputCount)
+        combinationGroupSizeNumericUpDown.Value = inputCount;
+      combinationCountLabel.Text = ((inputCount + 1) * EnumerableExtensions.BinomialCoefficient(inputCount, (int)combinationGroupSizeNumericUpDown.Value)).ToString();
+    }
+
+    private void worker_DoWork(object sender, DoWorkEventArgs e) {
+      IContentView activeView = (IContentView)MainFormManager.MainForm.ActiveView;
+      var algorithm = (IAlgorithm)activeView.Content;
+      var problem = (IDataAnalysisProblem)algorithm.Problem;
+      var experiment = new Experiment("Target Variation Experiment");
+      var repetitions = (int)repetitionsNumericUpDown.Value;
+      var inputCount = problem.ProblemData.AllowedInputVariables.Count() - 1;
+      var combinationGroupSize = (int)combinationGroupSizeNumericUpDown.Value;
+      var totalNumberOfCombinations = (inputCount + 1) * EnumerableExtensions.BinomialCoefficient(inputCount, combinationGroupSize);
+      int progress = 0;
+      try {
+        foreach (var optimizer in CreateVariableCombinations(algorithm, combinationGroupSize, repetitions)) {
+          if (worker.CancellationPending)
+            throw new OperationCanceledException();
+          experiment.Optimizers.Add(optimizer);
+          progress++;
+          worker.ReportProgress((int)Math.Round(100d * progress / totalNumberOfCombinations));
+        }
+        Experiment = experiment;
+      } catch (OperationCanceledException) {
+        e.Cancel = true;
+        UpdateProgress(0);
+        progressBar.Visible = false;
+        okButton.Enabled = true;
+        combinationsLabel.Visible = true;
+        combinationCountLabel.Visible = true;
+      }
+    }
+
+    private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
+      if (InvokeRequired) {
+        Invoke((Action<int>)UpdateProgress, e.ProgressPercentage);
+      } else {
+        UpdateProgress(e.ProgressPercentage);
+      }
+    }
+
+    private void UpdateProgress(int percentage) {
+      progressBar.Value = percentage;
+    }
+
+    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
+      if (e.Cancelled || e.Error != null)
+        return;
+      DialogResult = DialogResult.OK;
+      Close();
+    }
+
+    private void okButton_Click(object sender, EventArgs args) {
+      IContentView activeView = MainFormManager.MainForm.ActiveView as IContentView;
+      if ((activeView != null) && (activeView.Content != null) && (activeView.Content is IAlgorithm) && !activeView.Locked) {
+        okButton.Enabled = false;
+        combinationsLabel.Visible = false;
+        combinationCountLabel.Visible = false;
+        progressBar.Visible = true;
+        worker.RunWorkerAsync();
+      }
+    }
+
+    private void cancelButton_Click(object sender, EventArgs e) {
+      if (worker.IsBusy)
+        worker.CancelAsync();
+    }
+    #endregion
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/DirectedGraphChart.Designer.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/DirectedGraphChart.Designer.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/DirectedGraphChart.Designer.cs	(revision 15929)
@@ -0,0 +1,54 @@
+﻿namespace HeuristicLab.VariableInteractionNetworks.Views {
+  partial class DirectedGraphChart {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DirectedGraphChart));
+      ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).BeginInit();
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
+      this.splitContainer.Panel2.SuspendLayout();
+      this.splitContainer.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // toolTip
+      // 
+      this.toolTip.ShowAlways = true;
+      // 
+      // splitContainer
+      // 
+      // 
+      // DirectedGraphChart
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Name = "DirectedGraphChart";
+      this.Controls.SetChildIndex(this.splitContainer, 0);
+      ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).EndInit();
+      this.splitContainer.Panel2.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
+      this.splitContainer.ResumeLayout(false);
+      this.ResumeLayout(false);
+
+    }
+    #endregion
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/DirectedGraphChart.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/DirectedGraphChart.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/DirectedGraphChart.cs	(revision 15929)
@@ -0,0 +1,275 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Linq;
+using System.Windows.Forms;
+using HeuristicLab.Core;
+using HeuristicLab.Random;
+using HeuristicLab.Visualization;
+using Pen = System.Drawing.Pen;
+using Rectangle = HeuristicLab.Visualization.Rectangle;
+using Routing = HeuristicLab.VariableInteractionNetworks.Views.ConstrainedForceDirectedLayout.EdgeRouting;
+
+
+namespace HeuristicLab.VariableInteractionNetworks.Views {
+  public partial class DirectedGraphChart : ChartControl {
+    public new Bitmap Picture { get { return base.Picture; } }
+
+    private readonly ConstrainedForceDirectedLayout layout;
+    // provide direct and reverse mapping between graph objects and layout shapes
+    private Dictionary<IPrimitive, IVertex> vertexMap;
+    private Dictionary<IPrimitive, IArc> arcMap;
+    private Dictionary<IArc, LinearPrimitiveBase> arcShapes;
+    private Dictionary<IVertex, RectangularPrimitiveBase> vertexShapes;
+
+    // graph layout options
+    public double DefaultEdgeLength {
+      get { return layout.DefaultEdgeLength; }
+      set { layout.DefaultEdgeLength = value; }
+    }
+
+    public bool PerformEdgeRouting {
+      get { return layout.PerformEdgeRouting; }
+      set { layout.PerformEdgeRouting = value; }
+    }
+
+    public Routing RoutingMode {
+      get { return layout.EdgeRoutingMode; }
+      set { layout.EdgeRoutingMode = value; }
+    }
+
+    public IVertex GetVertex(IPrimitive primitive) {
+      IVertex v;
+      vertexMap.TryGetValue(primitive, out v);
+      return v;
+    }
+
+    public IArc GetArc(IPrimitive primitive) {
+      IArc a;
+      arcMap.TryGetValue(primitive, out a);
+      return a;
+    }
+
+    public RectangularPrimitiveBase GetVertexShape(IVertex v) {
+      RectangularPrimitiveBase p;
+      vertexShapes.TryGetValue(v, out p);
+      return p;
+    }
+
+    public LinearPrimitiveBase GetArcShape(IArc arc) {
+      LinearPrimitiveBase l;
+      arcShapes.TryGetValue(arc, out l);
+      return l;
+    }
+
+    public ToolTip ToolTip {
+      get { return toolTip; }
+    }
+
+    public DirectedGraphChart() {
+      InitializeComponent();
+
+      var directedGraphChartMode = new DirectedGraphChartMode(this);
+
+      this.AddChartModes(directedGraphChartMode, new PanChartMode(this), new ZoomInChartMode(this), new ZoomOutChartMode(this));
+      shapes = new Dictionary<Type, LabeledPrimitive>();
+      SmoothingMode = SmoothingMode.HighQuality; // set antialiasing for nicer rendering
+
+      layout = new ConstrainedForceDirectedLayout {
+        LayoutWidth = (int)Chart.Size.Width,
+        LayoutHeight = (int)Chart.Size.Height,
+        MinHorizontalSpacing = 0,
+        MinVerticalSpacing = 0,
+      };
+    }
+
+    private IDirectedGraph graph;
+    public IDirectedGraph Graph {
+      get { return graph; }
+      set {
+        if (value == null || graph == value || !value.Vertices.Any()) return;
+        graph = value;
+        Draw();
+      }
+    }
+
+    private void RegisterEvents() { }
+
+    private void DeregisterEvents() { }
+
+    public void Draw() {
+      SuspendRendering();
+      Chart.Group.Clear();
+      vertexMap = new Dictionary<IPrimitive, IVertex>();
+      arcMap = new Dictionary<IPrimitive, IArc>();
+      var rng = new MersenneTwister();
+      vertexShapes = new Dictionary<IVertex, RectangularPrimitiveBase>();
+      arcShapes = new Dictionary<IArc, LinearPrimitiveBase>();
+      var vertexRectangles = new Dictionary<IVertex, RectangleF>();
+      foreach (var v in graph.Vertices) {
+        var shape = CreateShape(v);
+        shape.ToolTipText = v.Label;
+        vertexMap[shape] = v;
+        vertexShapes[v] = shape;
+        var width = (float)shape.Size.Width;
+        var height = (float)shape.Size.Height;
+        var x = (float)(rng.NextDouble() * (Chart.Size.Width - width));
+        var y = (float)(rng.NextDouble() * (Chart.Size.Height - height));
+        vertexRectangles[v] = new RectangleF(x, y, width, height);
+      }
+
+      var arcs = graph.Vertices.SelectMany(x => x.InArcs).ToList();
+      if (arcs.Count != graph.Arcs.Count())
+        throw new Exception("Arcs count does not match!");
+
+      layout.Run(vertexRectangles);
+      var vertexPositions = layout.VertexPositions;
+      var arcRoutes = layout.ArcRoutes;
+
+      var max = arcRoutes.Keys.Max(x => x.Weight);
+
+      // move shapes to the positions computed by the layout
+      foreach (var pair in vertexPositions) {
+        var shape = vertexShapes[pair.Key];
+        var pos = vertexPositions[pair.Key];
+        shape.Move(new Offset(pos.X, pos.Y));
+      }
+
+      foreach (var pair in arcRoutes) {
+        var arc = pair.Key;
+        var weight = arc.Weight;
+        var points = pair.Value;
+        var target = (LabeledPrimitive)vertexShapes[pair.Key.Target];
+        var len = points.Length; // len = 2 when no edge routingMode is performed
+        Pen pen;
+        var penWidth = weight / max * 3;
+        var penColor = Color.Black;
+        if (len == 2) {
+          if (double.IsInfinity(penWidth) || double.IsNaN(penWidth))
+            penWidth = 1;
+
+          pen = new Pen(penColor, (float)penWidth) { CustomEndCap = new AdjustableArrowCap(5, 3) };
+          var start = points[0];
+          var end = points[1];
+          var line = new Line(Chart, new PointD(start.X, start.Y), new PointD(end.X, end.Y));
+          var rect = target.Primitive as Rectangle;
+          var ell = target.Primitive as Ellipse;
+
+          // calculate intersection point
+          PointD intersectionPoint;
+          if (rect != null)
+            intersectionPoint = rect.ComputeIntersect(line).FirstOrDefault();
+          else if (ell != null)
+            intersectionPoint = ell.ComputeIntersect(line).FirstOrDefault();
+          else
+            throw new InvalidOperationException("Unknown vertex shape.");
+
+          if (intersectionPoint == default(PointD))
+            intersectionPoint = end;
+
+          line = new Line(Chart, new PointD(start.X, start.Y), intersectionPoint, pen) { ToolTipText = arc.Label };
+          Chart.Group.Add(line);
+          arcShapes[arc] = line;
+          arcMap[line] = arc;
+        } else {
+          for (int i = 0; i < points.Length - 1; ++i) {
+            var start = points[i];
+            var end = points[i + 1];
+
+            var segment = new Line(Chart, new PointD(start.X, start.Y), new PointD(end.X, end.Y));
+            var rect = target.Primitive as Rectangle;
+            var ell = target.Primitive as Ellipse;
+
+            PointD endPoint;
+            List<PointD> intersectionPoints;
+            if (rect != null) {
+              intersectionPoints = rect.ComputeIntersect(segment);
+            } else if (ell != null) {
+              intersectionPoints = ell.ComputeIntersect(segment);
+            } else {
+              throw new InvalidOperationException("Unknown vertex shape.");
+            }
+            if (intersectionPoints.Any()) {
+              endPoint = intersectionPoints.First();
+              pen = new Pen(penColor, (float)penWidth) { CustomEndCap = new AdjustableArrowCap(5, 3) };
+            } else {
+              endPoint = end;
+              pen = new Pen(penColor, (float)penWidth);
+            }
+            var startPoint = new PointD(start.X, start.Y);
+            var line = new Line(Chart, startPoint, endPoint, pen) { ToolTipText = arc.Label };
+            Chart.Group.Add(line);
+            if (intersectionPoints.Any()) {
+              arcShapes[arc] = line;
+              arcMap[line] = arc;
+              break;
+            }
+          }
+        }
+      }
+      // draw vertex shapes after the arcs so they appear on top
+      foreach (var pair in vertexPositions) {
+        var shape = vertexShapes[pair.Key];
+        shape.RedrawRequired += ShapeRedrawRequired;
+        Chart.Group.Add(shape);
+      }
+      ResumeRendering();
+    }
+
+    private void ShapeRedrawRequired(object sender, EventArgs args) {
+    }
+
+    private readonly Dictionary<Type, LabeledPrimitive> shapes;
+    public void AddShape(Type t, LabeledPrimitive shape) {
+      shapes[t] = shape;
+    }
+
+    public void ClearShapes() {
+      shapes.Clear();
+    }
+
+    private LabeledPrimitive CreateShape(IVertex v) {
+      var type = v.GetType();
+      if (!shapes.ContainsKey(type))
+        throw new ArgumentException(string.Format("No shape was associated with vertex type {0}", type));
+      var shape = shapes[type];
+      var p = shape.Primitive;
+      var rectangle = p as Rectangle;
+      var ellipse = p as Ellipse;
+      var pen = new Pen(shape.Pen.Color);
+      var brush = new SolidBrush(((SolidBrush)shape.Brush).Color);
+
+      if (rectangle != null) {
+        var r = new Rectangle(this.Chart, shape.LowerLeft, shape.UpperRight, pen, brush);
+        return new LabeledPrimitive(r, v.Label, shape.Font);
+      }
+      if (ellipse != null) {
+        var e = new Ellipse(this.Chart, shape.LowerLeft, shape.UpperRight, pen, brush);
+        return new LabeledPrimitive(e, v.Label, shape.Font);
+      }
+      throw new Exception(string.Format("Unknown shape {0}.", shape));
+    }
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/DirectedGraphChartMode.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/DirectedGraphChartMode.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/DirectedGraphChartMode.cs	(revision 15929)
@@ -0,0 +1,115 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Linq;
+using System.Windows.Forms;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.MainForm;
+using HeuristicLab.Visualization;
+
+namespace HeuristicLab.VariableInteractionNetworks.Views {
+  public class DirectedGraphChartMode : SelectChartMode {
+    public DirectedGraphChartMode(DirectedGraphChart control) : base(control) { }
+
+    public DirectedGraphChart Control {
+      get { return (DirectedGraphChart)chartControl; }
+    }
+
+    public override void HandleOnMouseDoubleClick(object sender, MouseEventArgs e) {
+      try {
+        switch (e.Button) {
+          case MouseButtons.Left:
+            try {
+              chartControl.SuspendRendering();
+              var worldLocation = chartControl.Chart.TransformPixelToWorld(e.Location);
+              foreach (var p in chartControl.Chart.Group.SelectedPrimitives.Where(x => !x.ContainsPoint(worldLocation)))
+                p.Selected = false;
+              var sp = chartControl.Chart.GetPrimitive(e.Location);
+              if (sp != null) sp.Selected = true;
+              if (sp is RectangularPrimitiveBase) {
+                var vertex = Control.GetVertex(sp) as IVertex<IDeepCloneable>;
+                if (vertex != null) {
+                  var content = vertex.Data as IContent;
+                  if (content != null) {
+                    MainFormManager.MainForm.ShowContent(content);
+                  }
+                }
+              }
+            }
+            finally { chartControl.ResumeRendering(); }
+            break;
+        }
+      }
+      finally {
+        base.HandleOnMouseDown(sender, e);
+      }
+    }
+
+    public override void HandleOnMouseMove(object sender, MouseEventArgs e) {
+      try {
+        switch (e.Button) {
+          case MouseButtons.Left:
+            var previousWorldLocation = chartControl.Chart.TransformPixelToWorld(previousLocation);
+            var worldLocation = chartControl.Chart.TransformPixelToWorld(e.Location);
+            var offset = worldLocation - previousWorldLocation;
+            try {
+              chartControl.SuspendRendering();
+              foreach (var p in chartControl.Chart.Group.SelectedPrimitives.Where(p => p.ContainsPoint(previousWorldLocation))) {
+                var lp = p as LabeledPrimitive;
+                if (lp == null) continue;
+                p.Move(previousWorldLocation, offset);
+                var rect = lp.Primitive as Rectangle;
+                var ell = lp.Primitive as Ellipse;
+                if (rect == null && ell == null) continue;
+                var v = Control.GetVertex(p);
+                if (v == null) continue;
+                // ends of outgoing arcs need to be properly adjusted
+                foreach (var arc in v.InArcs) {
+                  var r = (LabeledPrimitive)Control.GetVertexShape(arc.Source);
+                  var line = (Line)Control.GetArcShape(arc);
+                  var tmp = new Line(this.chartControl.Chart, r.Primitive.Center(), lp.Primitive.Center());
+                  var intersect = rect == null ? ell.ComputeIntersect(tmp) : rect.ComputeIntersect(tmp);
+                  if (intersect.Any())
+                    line.SetPosition(tmp.Start, intersect.First());
+                }
+                foreach (var arc in v.OutArcs) {
+                  var r = (LabeledPrimitive)Control.GetVertexShape(arc.Target);
+                  rect = r.Primitive as Rectangle;
+                  ell = r.Primitive as Ellipse;
+                  var line = (Line)Control.GetArcShape(arc);
+                  var tmp = new Line(this.chartControl.Chart, lp.Primitive.Center(), r.Primitive.Center());
+                  var intersect = rect == null ? ell.ComputeIntersect(tmp) : rect.ComputeIntersect(tmp);
+                  if (intersect.Any())
+                    line.SetPosition(tmp.Start, intersect.First());
+                }
+              }
+            }
+            finally { chartControl.ResumeRendering(); }
+            break;
+        }
+      }
+      finally {
+        base.HandleOnMouseMove(sender, e);
+      }
+    }
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/HeuristicLab.VariableInteractionNetworks.Views-3.3.csproj
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/HeuristicLab.VariableInteractionNetworks.Views-3.3.csproj	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/HeuristicLab.VariableInteractionNetworks.Views-3.3.csproj	(revision 15929)
@@ -0,0 +1,260 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{EA1A0A27-A38D-4086-812A-9CE0FF557103}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.VariableInteractionNetworks.Views</RootNamespace>
+    <AssemblyName>HeuristicLab.VariableInteractionNetworks.Views-3.3</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Cola, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\Cola.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Analysis-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Analysis-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Collections-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Collections-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Common-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Common-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Common.Resources-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Common.Resources-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Core-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Core-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Core.Views-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Core.Views-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Data-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Data-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Data.Views-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Data.Views-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.MainForm-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.MainForm-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.MainForm.WindowsForms-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.MainForm.WindowsForms-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Optimization-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimizer-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Optimizer-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.PluginInfrastructure-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Problems.DataAnalysis-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic.Classification-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Problems.DataAnalysis.Symbolic.Classification-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Random-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Random-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Visualization-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Visualization-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="PresentationCore" />
+    <Reference Include="PresentationFramework" />
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xaml" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+    <Reference Include="UIAutomationProvider" />
+    <Reference Include="WindowsBase" />
+    <Reference Include="WindowsFormsIntegration" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="CreateTargetVariationExperiment.cs" />
+    <Compile Include="CreateTargetVariationExperimentDialog.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="CreateTargetVariationExperimentDialog.Designer.cs">
+      <DependentUpon>CreateTargetVariationExperimentDialog.cs</DependentUpon>
+    </Compile>
+    <Compile Include="DirectedGraphChart.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="DirectedGraphChart.Designer.cs">
+      <DependentUpon>DirectedGraphChart.cs</DependentUpon>
+    </Compile>
+    <Compile Include="DirectedGraphChartMode.cs" />
+    <Compile Include="Layout\ConstrainedForceDirectedLayout.cs" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="RunCollectionVariableInteractionNetworkView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="RunCollectionVariableInteractionNetworkView.Designer.cs">
+      <DependentUpon>RunCollectionVariableInteractionNetworkView.cs</DependentUpon>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\HeuristicLab.VariableInteractionNetworks\3.3\HeuristicLab.VariableInteractionNetworks-3.3.csproj">
+      <Project>{d891ed5c-77eb-4a24-9967-decadbf15ce9}</Project>
+      <Name>HeuristicLab.VariableInteractionNetworks-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="Plugin.cs.frame" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="RunCollectionVariableInteractionNetworkView.resx">
+      <DependentUpon>RunCollectionVariableInteractionNetworkView.cs</DependentUpon>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="adaptagrams32.dll">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="adaptagrams64.dll">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="Cola.dll">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Adaptagrams\" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd</PreBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/Layout/ConstrainedForceDirectedLayout.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/Layout/ConstrainedForceDirectedLayout.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/Layout/ConstrainedForceDirectedLayout.cs	(revision 15929)
@@ -0,0 +1,325 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using Cola;
+using HeuristicLab.Core;
+using Point = Cola.Point;
+
+namespace HeuristicLab.VariableInteractionNetworks.Views {
+  public class ConstrainedForceDirectedLayout {
+    #region edge routing modes 
+    public enum EdgeRouting : uint {
+      None,
+      Polyline,
+      Orthogonal
+    }
+    #endregion
+
+    #region layout-related private members 
+    private ConstrainedFDLayout alg;
+    // graph and constraint definitions
+    private TopologyNodePtrs topologyNodes;
+    private TopologyEdgePtrs topologyRoutes;
+    private RectanglePtrs rectangles;
+    private ColaEdges edges;
+    private Cola.Doubles edgeLengths;
+    //private int topologyNodeCount;
+    private Dictionary<uint, uint> idMap;
+    private Dictionary<IVertex, int> indexMap;
+    #endregion
+
+    #region public properties
+    public double IdealEdgeLength { get; set; }
+    public double DefaultEdgeLength { get; set; }
+    public bool PreventOverlaps { get; set; }
+    public int LayoutWidth { get; set; }
+    public int LayoutHeight { get; set; }
+    public bool PerformEdgeRouting { get; set; }
+    public int MinHorizontalSpacing { get; set; }
+    public int MinVerticalSpacing { get; set; }
+    public EdgeRouting EdgeRoutingMode { get; set; }
+
+    public Dictionary<IVertex, PointF> VertexPositions {
+      get {
+        var dict = new Dictionary<IVertex, PointF>();
+        foreach (var pair in indexMap) {
+          var node = topologyNodes[pair.Value];
+          var point = new PointF((float)node.rect.getMinX(), (float)node.rect.getMinY());
+          dict[pair.Key] = point;
+        }
+        return dict;
+      }
+    }
+
+    private List<IArc> arcs;
+    public Dictionary<IArc, PointF[]> ArcRoutes {
+      get {
+        var dict = new Dictionary<IArc, PointF[]>();
+        for (int i = 0; i < arcs.Count; ++i) {
+          var arc = arcs[i];
+          var route = topologyRoutes[i];
+          var vs = new TopologyEdgePointConstPtrs();
+          route.getPath(vs);
+          dict[arc] = vs.Select(x => new PointF((float)x.posX(), (float)x.posY())).ToArray();
+        }
+        return dict;
+      }
+    }
+    #endregion
+
+    public ConstrainedForceDirectedLayout() {
+      IdealEdgeLength = 1;
+      DefaultEdgeLength = 200;
+      PreventOverlaps = true;
+      LayoutWidth = 800;
+      LayoutHeight = 600;
+      MinHorizontalSpacing = 0;
+      MinVerticalSpacing = 0;
+      EdgeRoutingMode = EdgeRouting.None;
+    }
+
+    /// <summary>
+    /// This method accepts a dictionary mapping each vertex to a rectangular shape, so that the layout is aware of each node's width and height
+    /// </summary>
+    /// <param name="nodeShapes">The dictionary mapping graph vertices to rectangular shapes.</param>
+    public void Run(Dictionary<IVertex, RectangleF> nodeShapes) {
+      if (nodeShapes.Count == 0) return;
+      // map vertices to node indices required by cola
+      indexMap = new Dictionary<IVertex, int>();
+      idMap = new Dictionary<uint, uint>();
+      rectangles = new Cola.RectanglePtrs();
+      int i = 0;
+      arcs = new List<IArc>();
+      topologyNodes = new TopologyNodePtrs();
+      foreach (var pair in nodeShapes) {
+        var v = pair.Key;
+        arcs.AddRange(v.InArcs);
+        var p = pair.Value;
+        var rect = new Cola.Rectangle(p.X, p.X + p.Width, p.Y, p.Y + p.Height);
+        rectangles.Add(rect);
+
+        indexMap[v] = i;
+        topologyNodes.Add(new Cola.Node((uint)i, rect));
+
+        ++i;
+      }
+      //topologyNodeCount = i;
+      edges = new ColaEdges(arcs.Select(x => new ColaEdge((uint)indexMap[x.Source], (uint)indexMap[x.Target])).ToList());
+      edgeLengths = new Cola.Doubles(Enumerable.Range(0, edges.Count).Select(x => DefaultEdgeLength).ToList());
+
+      // initialize the layout engine using the rectangles, edges, and desired settings 
+      alg = new ConstrainedFDLayout(rectangles, edges, IdealEdgeLength, edgeLengths);
+      alg.setAvoidNodeOverlaps(PreventOverlaps); // prevent overlap of node shapes
+
+      // identify clusters and configure cluster hierarchy
+      var clusters = IdentifyClusters(rectangles, edges).ToList();
+      if (clusters.Count > 1) {
+        var rootCluster = new RootCluster();
+        foreach (var cluster in clusters) {
+          rootCluster.addChildCluster(cluster);
+        }
+        alg.setClusterHierarchy(rootCluster);
+      }
+
+      var topology = new ColaTopologyAddon();
+      alg.setTopology(topology);
+      alg.makeFeasible();
+      var newTopology = ColaTopologyAddon.CastToConcreteType(alg.getTopology()); // store topology after makeFeasible()
+
+      topologyNodes = newTopology.topologyNodes;
+      topologyRoutes = newTopology.topologyRoutes;
+
+      RouteEdges();
+      // finally, run the layout engine (the positions of the rectangles will be updated)
+      alg.run();
+    }
+
+    public void Run(bool preserveTopology = true) {
+      if (preserveTopology) {
+        RouteEdges();
+        var topology = new ColaTopologyAddon(topologyNodes, topologyRoutes);
+        alg.setTopology(topology);
+      }
+      alg.run();
+    }
+
+    /// <summary>
+    /// This method is used internally by the @IdentifyClusters method to separate vertices by color 
+    /// (vertices of the same subgraph will have the same color)
+    /// </summary>
+    /// <param name="v">The starting vertex from which all adjacent vertices will be colored.</param>
+    private static void ColourNeighbours(IVertex v) {
+      foreach (var arc in v.InArcs) {
+        if (arc.Source.Weight > 0) continue;
+        arc.Source.Weight = v.Weight;
+        ColourNeighbours(arc.Source);
+      }
+      foreach (var arc in v.OutArcs) {
+        if (arc.Target.Weight > 0) continue;
+        arc.Target.Weight = v.Weight;
+        ColourNeighbours(arc.Target);
+      }
+    }
+
+    /// <summary>
+    /// Method used to identify the disconnected components of the graph, so that they can be layouted separately and placed in non-overlapping areas of the drawing region.
+    /// </summary>
+    /// <param name="rectangles">The rectangles corresponding to the graph nodes.</param>
+    /// <param name="edges">The edges connecting the rectangles.</param>
+    /// <returns>A list of clusters representing the disconnected components.</returns>
+    private static IEnumerable<Cluster> IdentifyClusters(RectanglePtrs rectangles, ColaEdges edges) {
+      // build a graph using the rectangles and the edges
+      var vertices = new List<IVertex>(rectangles.Select(x => new Vertex()));
+      foreach (var e in edges) {
+        var i = (int)e.first;
+        var j = (int)e.second;
+        var arc = new Arc(vertices[i], vertices[j]);
+        vertices[i].AddArc(arc);
+        vertices[j].AddArc(arc);
+      }
+      // group vertices into clusters
+      var clusters = new List<RectangularCluster>();
+      for (int i = 0; i < vertices.Count; ++i) {
+        var v = vertices[i];
+        if (v.Weight > 0) {
+          clusters[(int)Math.Round(v.Weight) - 1].addChildNode((uint)i);
+        } else {
+          var cluster = new RectangularCluster();
+          cluster.addChildNode((uint)i);
+          clusters.Add(cluster);
+          v.Weight = clusters.Count;
+          ColourNeighbours(v);
+        }
+      }
+      return clusters;
+    }
+
+    /// <summary>
+    /// This method performs edge routing, meaning that edges are moved such that they go around the nodes.
+    /// Routing can produce polyline or orthogonal graph edges.
+    /// </summary>
+    private void RouteEdges() {
+      topologyRoutes = new TopologyEdgePtrs();
+      // after the layout is done, we need to use a router to route edges
+      RouterFlag rf;
+      switch (EdgeRoutingMode) {
+        case EdgeRouting.Polyline:
+          rf = RouterFlag.PolyLineRouting;
+          break;
+        case EdgeRouting.Orthogonal:
+          rf = RouterFlag.OrthogonalRouting;
+          break;
+        default:
+          var id = topologyNodes.Count;
+          foreach (var edge in edges) {
+            var eps = new TopologyEdgePointPtrs();
+            var src = topologyNodes[(int)edge.first];
+            var dst = topologyNodes[(int)edge.second];
+            eps.Add(new EdgePoint(src, EdgePoint.RectIntersect.CENTRE));
+            eps.Add(new EdgePoint(dst, EdgePoint.RectIntersect.CENTRE));
+            topologyRoutes.Add(new Edge((uint)id++, IdealEdgeLength, eps));
+          }
+          return;
+      }
+      var router = new Router((uint)rf);
+      // set the minimal distance by which nodes should be avoided by the router
+      router.setRoutingParameter(RoutingParameter.shapeBufferDistance, 5);
+      router.UseLeesAlgorithm = true;
+      router.InvisibilityGrph = false;
+      // consider topology routes only for the topologyNodes associated with our objects (the rectangles)
+      for (int i = 0; i < topologyNodes.Count; ++i) {
+        var r = topologyNodes[i].rect;
+        var poly = new Polygon(4);
+        var xmin = r.getMinX();
+        var xmax = r.getMaxX();
+        var ymin = r.getMinY();
+        var ymax = r.getMaxY();
+
+        poly.ps[0] = new Cola.Point(xmax, ymin);
+        poly.ps[1] = new Cola.Point(xmax, ymax);
+        poly.ps[2] = new Cola.Point(xmin, ymax);
+        poly.ps[3] = new Cola.Point(xmin, ymin);
+        var shapeRef = new ShapeRef(router, poly);
+        idMap[shapeRef.id()] = (uint)i;
+      }
+      router.processTransaction();
+
+      for (int i = 0; i < edges.Count; ++i) {
+        var edge = edges[i];
+        var src = topologyNodes[(int)edge.first];
+        var dst = topologyNodes[(int)edge.second];
+        var srcPt = new Cola.Point(src.rect.getCentreX(), src.rect.getCentreY());
+        var dstPt = new Cola.Point(dst.rect.getCentreX(), dst.rect.getCentreY());
+        var connRef = new ConnRef(router, new ConnEnd(srcPt), new ConnEnd(dstPt));
+        router.processTransaction();
+
+        //        var route = connRef.displayRoute().curvedPolyline(10);
+        var route = connRef.displayRoute();
+        var eps = new TopologyEdgePointPtrs(); // edge points
+        eps.Add(new EdgePoint(src, EdgePoint.RectIntersect.CENTRE));
+        for (int j = 1; j < route.size() - 1; ++j) {
+          var p = route.ps[j];
+          var ri = CalculateIntersect(p);
+          if (idMap.ContainsKey(p.id)) {
+            var node = topologyNodes[(int)idMap[p.id]];
+            eps.Add(new EdgePoint(node, ri));
+          } else {
+            // the node is not part of the topology and only represents a point in the route polyline
+            // therefore, we do not add it to the topologyNodes (although it may need to be treated separately in some cases)
+            var id = router.newObjectId();
+            var node = new Node(id, new Cola.Rectangle(p.x, p.x + 1, p.y, p.y + 1));
+            idMap[id] = id;
+            eps.Add(new EdgePoint(node, ri));
+          }
+        }
+        eps.Add(new EdgePoint(dst, EdgePoint.RectIntersect.CENTRE));
+        topologyRoutes.Add(new Edge((uint)i, IdealEdgeLength, eps));
+      }
+    }
+
+    /// <summary>
+    /// Save the layouted graph to a svg file
+    /// </summary>
+    /// <param name="path">The save path.</param>
+    public void OutputInstanceToSVG(string path) {
+      alg.outputInstanceToSVG(path);
+    }
+
+    private static EdgePoint.RectIntersect CalculateIntersect(Point p) {
+      switch (p.vn) {
+        case 0:
+          return EdgePoint.RectIntersect.BR;
+        case 1:
+          return EdgePoint.RectIntersect.TR;
+        case 2:
+          return EdgePoint.RectIntersect.TL;
+        case 3:
+          return EdgePoint.RectIntersect.BL;
+        default:
+          return EdgePoint.RectIntersect.CENTRE;
+      }
+    }
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/Plugin.cs.frame
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/Plugin.cs.frame	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/Plugin.cs.frame	(revision 15929)
@@ -0,0 +1,41 @@
+#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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.VariableInteractionNetworks.Views {
+  /// <summary>
+  /// Plugin class for HeuristicLab.VariableInteractionNetworks.Views plugin.
+  /// </summary>
+  [Plugin("HeuristicLab.VariableInteractionNetworks.Views", "Provides the functionality for generating and visualizing variable interaction networks.", "3.3.10.$WCREV$")]
+  [PluginFile("HeuristicLab.VariableInteractionNetworks.Views-3.3.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.Collections", "3.3")]
+  [PluginDependency("HeuristicLab.Common", "3.3")]
+  [PluginDependency("HeuristicLab.Common.Resources", "3.3")]
+  [PluginDependency("HeuristicLab.Core", "3.3")]
+  [PluginDependency("HeuristicLab.Data", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization", "3.3")]
+  [PluginDependency("HeuristicLab.Parameters", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
+  [PluginDependency("HeuristicLab.VariableInteractionNetworks", "3.3")]
+  public class Plugin : PluginBase {
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/Properties/AssemblyInfo.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/Properties/AssemblyInfo.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/Properties/AssemblyInfo.cs	(revision 15929)
@@ -0,0 +1,36 @@
+﻿using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.VariableInteractionNetworks.Views")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab.VariableInteractionNetworks.Views")]
+[assembly: AssemblyCopyright("Copyright ©  2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("7d2df649-1a39-4b86-bf97-3c1b28ea793c")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/RunCollectionVariableInteractionNetworkView.Designer.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/RunCollectionVariableInteractionNetworkView.Designer.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/RunCollectionVariableInteractionNetworkView.Designer.cs	(revision 15929)
@@ -0,0 +1,327 @@
+﻿namespace HeuristicLab.VariableInteractionNetworks.Views {
+  partial class RunCollectionVariableInteractionNetworkView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+
+    #region Component Designer generated code
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      this.settingsGroupBox = new System.Windows.Forms.GroupBox();
+      this.impactThresholdTrackBar = new System.Windows.Forms.TrackBar();
+      this.exportImpactsMatrixButton = new System.Windows.Forms.Button();
+      this.onlineImpactCalculationButton = new System.Windows.Forms.Button();
+      this.maximizationCheckBox = new System.Windows.Forms.CheckBox();
+      this.qualityResultNameComboBox = new System.Windows.Forms.ComboBox();
+      this.qualityResultNameLabel = new System.Windows.Forms.Label();
+      this.impactAggregationComboBox = new System.Windows.Forms.ComboBox();
+      this.impactResultNameComboBox = new System.Windows.Forms.ComboBox();
+      this.weightAggregationLabel = new System.Windows.Forms.Label();
+      this.label2 = new System.Windows.Forms.Label();
+      this.label1 = new System.Windows.Forms.Label();
+      this.layoutOptionsGroupBox = new System.Windows.Forms.GroupBox();
+      this.idealEdgeLengthTextBox = new System.Windows.Forms.TextBox();
+      this.edgeRoutingComboBox = new System.Windows.Forms.ComboBox();
+      this.label4 = new System.Windows.Forms.Label();
+      this.label3 = new System.Windows.Forms.Label();
+      this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+      this.impactThresholdLabel = new System.Windows.Forms.Label();
+      this.relayoutGraphButton = new System.Windows.Forms.Button();
+      this.graphChart = new HeuristicLab.VariableInteractionNetworks.Views.DirectedGraphChart();
+      this.settingsGroupBox.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.impactThresholdTrackBar)).BeginInit();
+      this.layoutOptionsGroupBox.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // settingsGroupBox
+      // 
+      this.settingsGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+            | System.Windows.Forms.AnchorStyles.Left)));
+      this.settingsGroupBox.Controls.Add(this.impactThresholdLabel);
+      this.settingsGroupBox.Controls.Add(this.impactThresholdTrackBar);
+      this.settingsGroupBox.Controls.Add(this.exportImpactsMatrixButton);
+      this.settingsGroupBox.Controls.Add(this.onlineImpactCalculationButton);
+      this.settingsGroupBox.Controls.Add(this.maximizationCheckBox);
+      this.settingsGroupBox.Controls.Add(this.qualityResultNameComboBox);
+      this.settingsGroupBox.Controls.Add(this.qualityResultNameLabel);
+      this.settingsGroupBox.Controls.Add(this.impactAggregationComboBox);
+      this.settingsGroupBox.Controls.Add(this.impactResultNameComboBox);
+      this.settingsGroupBox.Controls.Add(this.weightAggregationLabel);
+      this.settingsGroupBox.Controls.Add(this.label2);
+      this.settingsGroupBox.Controls.Add(this.label1);
+      this.settingsGroupBox.Location = new System.Drawing.Point(4, 4);
+      this.settingsGroupBox.Name = "settingsGroupBox";
+      this.settingsGroupBox.Size = new System.Drawing.Size(331, 235);
+      this.settingsGroupBox.TabIndex = 1;
+      this.settingsGroupBox.TabStop = false;
+      this.settingsGroupBox.Text = "Network Configuration";
+      // 
+      // impactThresholdTrackBar
+      // 
+      this.impactThresholdTrackBar.AutoSize = false;
+      this.impactThresholdTrackBar.LargeChange = 1;
+      this.impactThresholdTrackBar.Location = new System.Drawing.Point(10, 118);
+      this.impactThresholdTrackBar.Maximum = 1000;
+      this.impactThresholdTrackBar.Name = "impactThresholdTrackBar";
+      this.impactThresholdTrackBar.Size = new System.Drawing.Size(312, 23);
+      this.impactThresholdTrackBar.TabIndex = 7;
+      this.impactThresholdTrackBar.ValueChanged += new System.EventHandler(this.impactThresholdTrackBar_ValueChanged);
+      // 
+      // exportImpactsMatrixButton
+      // 
+      this.exportImpactsMatrixButton.Location = new System.Drawing.Point(10, 203);
+      this.exportImpactsMatrixButton.Name = "exportImpactsMatrixButton";
+      this.exportImpactsMatrixButton.Size = new System.Drawing.Size(149, 23);
+      this.exportImpactsMatrixButton.TabIndex = 6;
+      this.exportImpactsMatrixButton.Text = "Export Impacts Matrix";
+      this.exportImpactsMatrixButton.UseVisualStyleBackColor = true;
+      this.exportImpactsMatrixButton.Click += new System.EventHandler(this.exportImpactsMatrixButton_Click);
+      // 
+      // onlineImpactCalculationButton
+      // 
+      this.onlineImpactCalculationButton.Location = new System.Drawing.Point(10, 174);
+      this.onlineImpactCalculationButton.Name = "onlineImpactCalculationButton";
+      this.onlineImpactCalculationButton.Size = new System.Drawing.Size(149, 23);
+      this.onlineImpactCalculationButton.TabIndex = 6;
+      this.onlineImpactCalculationButton.Text = "Online Impact Calculation";
+      this.onlineImpactCalculationButton.UseVisualStyleBackColor = true;
+      this.onlineImpactCalculationButton.Click += new System.EventHandler(this.onlineImpactCalculationButton_Click);
+      // 
+      // maximizationCheckBox
+      // 
+      this.maximizationCheckBox.AutoSize = true;
+      this.maximizationCheckBox.Location = new System.Drawing.Point(236, 44);
+      this.maximizationCheckBox.Name = "maximizationCheckBox";
+      this.maximizationCheckBox.Size = new System.Drawing.Size(86, 17);
+      this.maximizationCheckBox.TabIndex = 5;
+      this.maximizationCheckBox.Text = "Maximization";
+      this.maximizationCheckBox.UseVisualStyleBackColor = true;
+      this.maximizationCheckBox.CheckedChanged += new System.EventHandler(this.NetworkConfigurationChanged);
+      // 
+      // qualityResultNameComboBox
+      // 
+      this.qualityResultNameComboBox.FormattingEnabled = true;
+      this.qualityResultNameComboBox.Location = new System.Drawing.Point(121, 17);
+      this.qualityResultNameComboBox.Name = "qualityResultNameComboBox";
+      this.qualityResultNameComboBox.Size = new System.Drawing.Size(201, 21);
+      this.qualityResultNameComboBox.TabIndex = 4;
+      this.qualityResultNameComboBox.SelectedIndexChanged += new System.EventHandler(this.NetworkConfigurationChanged);
+      // 
+      // qualityResultNameLabel
+      // 
+      this.qualityResultNameLabel.AutoSize = true;
+      this.qualityResultNameLabel.Location = new System.Drawing.Point(7, 20);
+      this.qualityResultNameLabel.Name = "qualityResultNameLabel";
+      this.qualityResultNameLabel.Size = new System.Drawing.Size(96, 13);
+      this.qualityResultNameLabel.TabIndex = 3;
+      this.qualityResultNameLabel.Text = "Quality result name";
+      // 
+      // impactAggregationComboBox
+      // 
+      this.impactAggregationComboBox.FormattingEnabled = true;
+      this.impactAggregationComboBox.Items.AddRange(new object[] {
+            "Best run",
+            "Runs average"});
+      this.impactAggregationComboBox.Location = new System.Drawing.Point(121, 147);
+      this.impactAggregationComboBox.Name = "impactAggregationComboBox";
+      this.impactAggregationComboBox.Size = new System.Drawing.Size(201, 21);
+      this.impactAggregationComboBox.TabIndex = 1;
+      this.impactAggregationComboBox.Text = "Best run";
+      this.impactAggregationComboBox.SelectedIndexChanged += new System.EventHandler(this.NetworkConfigurationChanged);
+      // 
+      // impactResultNameComboBox
+      // 
+      this.impactResultNameComboBox.FormattingEnabled = true;
+      this.impactResultNameComboBox.Location = new System.Drawing.Point(121, 67);
+      this.impactResultNameComboBox.Name = "impactResultNameComboBox";
+      this.impactResultNameComboBox.Size = new System.Drawing.Size(201, 21);
+      this.impactResultNameComboBox.TabIndex = 1;
+      this.impactResultNameComboBox.SelectedIndexChanged += new System.EventHandler(this.NetworkConfigurationChanged);
+      // 
+      // weightAggregationLabel
+      // 
+      this.weightAggregationLabel.AutoSize = true;
+      this.weightAggregationLabel.Location = new System.Drawing.Point(7, 150);
+      this.weightAggregationLabel.Name = "weightAggregationLabel";
+      this.weightAggregationLabel.Size = new System.Drawing.Size(98, 13);
+      this.weightAggregationLabel.TabIndex = 0;
+      this.weightAggregationLabel.Text = "Impact aggregation";
+      // 
+      // label2
+      // 
+      this.label2.AutoSize = true;
+      this.label2.Location = new System.Drawing.Point(7, 97);
+      this.label2.Name = "label2";
+      this.label2.Size = new System.Drawing.Size(85, 13);
+      this.label2.TabIndex = 0;
+      this.label2.Text = "Impact threshold";
+      // 
+      // label1
+      // 
+      this.label1.AutoSize = true;
+      this.label1.Location = new System.Drawing.Point(7, 70);
+      this.label1.Name = "label1";
+      this.label1.Size = new System.Drawing.Size(96, 13);
+      this.label1.TabIndex = 0;
+      this.label1.Text = "Impact result name";
+      // 
+      // layoutOptionsGroupBox
+      // 
+      this.layoutOptionsGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+            | System.Windows.Forms.AnchorStyles.Left)));
+      this.layoutOptionsGroupBox.Controls.Add(this.relayoutGraphButton);
+      this.layoutOptionsGroupBox.Controls.Add(this.idealEdgeLengthTextBox);
+      this.layoutOptionsGroupBox.Controls.Add(this.edgeRoutingComboBox);
+      this.layoutOptionsGroupBox.Controls.Add(this.label4);
+      this.layoutOptionsGroupBox.Controls.Add(this.label3);
+      this.layoutOptionsGroupBox.Location = new System.Drawing.Point(4, 245);
+      this.layoutOptionsGroupBox.Name = "layoutOptionsGroupBox";
+      this.layoutOptionsGroupBox.Size = new System.Drawing.Size(331, 217);
+      this.layoutOptionsGroupBox.TabIndex = 2;
+      this.layoutOptionsGroupBox.TabStop = false;
+      this.layoutOptionsGroupBox.Text = "Layout Options";
+      // 
+      // idealEdgeLengthTextBox
+      // 
+      this.idealEdgeLengthTextBox.Location = new System.Drawing.Point(121, 43);
+      this.idealEdgeLengthTextBox.Name = "idealEdgeLengthTextBox";
+      this.idealEdgeLengthTextBox.Size = new System.Drawing.Size(201, 20);
+      this.idealEdgeLengthTextBox.TabIndex = 2;
+      this.idealEdgeLengthTextBox.Text = "50";
+      this.idealEdgeLengthTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.TextBoxValidating);
+      this.idealEdgeLengthTextBox.Validated += new System.EventHandler(this.LayoutConfigurationBoxValidated);
+      // 
+      // edgeRoutingComboBox
+      // 
+      this.edgeRoutingComboBox.FormattingEnabled = true;
+      this.edgeRoutingComboBox.Items.AddRange(new object[] {
+            "None",
+            "Polyline",
+            "Orthogonal"});
+      this.edgeRoutingComboBox.Location = new System.Drawing.Point(121, 17);
+      this.edgeRoutingComboBox.Name = "edgeRoutingComboBox";
+      this.edgeRoutingComboBox.Size = new System.Drawing.Size(201, 21);
+      this.edgeRoutingComboBox.TabIndex = 3;
+      this.edgeRoutingComboBox.Text = "None";
+      this.edgeRoutingComboBox.SelectedIndexChanged += new System.EventHandler(this.LayoutConfigurationChanged);
+      // 
+      // label4
+      // 
+      this.label4.AutoSize = true;
+      this.label4.Location = new System.Drawing.Point(6, 46);
+      this.label4.Name = "label4";
+      this.label4.Size = new System.Drawing.Size(89, 13);
+      this.label4.TabIndex = 0;
+      this.label4.Text = "Ideal edge length";
+      // 
+      // label3
+      // 
+      this.label3.AutoSize = true;
+      this.label3.Location = new System.Drawing.Point(7, 20);
+      this.label3.Name = "label3";
+      this.label3.Size = new System.Drawing.Size(67, 13);
+      this.label3.TabIndex = 0;
+      this.label3.Text = "Edge routing";
+      // 
+      // errorProvider
+      // 
+      this.errorProvider.ContainerControl = this;
+      // 
+      // impactThresholdLabel
+      // 
+      this.impactThresholdLabel.Location = new System.Drawing.Point(118, 92);
+      this.impactThresholdLabel.Name = "impactThresholdLabel";
+      this.impactThresholdLabel.Size = new System.Drawing.Size(204, 23);
+      this.impactThresholdLabel.TabIndex = 8;
+      this.impactThresholdLabel.Text = "0";
+      this.impactThresholdLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+      // 
+      // relayoutGraphButton
+      // 
+      this.relayoutGraphButton.Location = new System.Drawing.Point(10, 69);
+      this.relayoutGraphButton.Name = "relayoutGraphButton";
+      this.relayoutGraphButton.Size = new System.Drawing.Size(149, 23);
+      this.relayoutGraphButton.TabIndex = 4;
+      this.relayoutGraphButton.Text = "Recalculate Layout";
+      this.relayoutGraphButton.UseVisualStyleBackColor = true;
+      this.relayoutGraphButton.Click += new System.EventHandler(this.relayoutGraphButton_Click);
+      // 
+      // graphChart
+      // 
+      this.graphChart.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.graphChart.BackColor = System.Drawing.SystemColors.Control;
+      this.graphChart.Graph = null;
+      this.graphChart.DefaultEdgeLength = 50D;
+      this.graphChart.Location = new System.Drawing.Point(341, 4);
+      this.graphChart.Mode = null;
+      this.graphChart.Name = "graphChart";
+      this.graphChart.PerformEdgeRouting = false;
+      this.graphChart.RoutingMode = HeuristicLab.VariableInteractionNetworks.Views.ConstrainedForceDirectedLayout.EdgeRouting.None;
+      this.graphChart.ScaleOnResize = true;
+      this.graphChart.ShowToolBar = true;
+      this.graphChart.Size = new System.Drawing.Size(411, 458);
+      this.graphChart.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
+      this.graphChart.TabIndex = 0;
+      // 
+      // RunCollectionVariableInteractionNetworkView
+      // 
+      this.Controls.Add(this.layoutOptionsGroupBox);
+      this.Controls.Add(this.settingsGroupBox);
+      this.Controls.Add(this.graphChart);
+      this.Name = "RunCollectionVariableInteractionNetworkView";
+      this.Size = new System.Drawing.Size(755, 465);
+      this.settingsGroupBox.ResumeLayout(false);
+      this.settingsGroupBox.PerformLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.impactThresholdTrackBar)).EndInit();
+      this.layoutOptionsGroupBox.ResumeLayout(false);
+      this.layoutOptionsGroupBox.PerformLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private DirectedGraphChart graphChart;
+    private System.Windows.Forms.GroupBox settingsGroupBox;
+    private System.Windows.Forms.Label label1;
+    private System.Windows.Forms.Label label2;
+    private System.Windows.Forms.ComboBox impactResultNameComboBox;
+    private System.Windows.Forms.GroupBox layoutOptionsGroupBox;
+    private System.Windows.Forms.Label label3;
+    private System.Windows.Forms.ComboBox edgeRoutingComboBox;
+    private System.Windows.Forms.TextBox idealEdgeLengthTextBox;
+    private System.Windows.Forms.Label label4;
+    private System.Windows.Forms.ErrorProvider errorProvider;
+    private System.Windows.Forms.ComboBox impactAggregationComboBox;
+    private System.Windows.Forms.Label weightAggregationLabel;
+    private System.Windows.Forms.Label qualityResultNameLabel;
+    private System.Windows.Forms.ComboBox qualityResultNameComboBox;
+    private System.Windows.Forms.CheckBox maximizationCheckBox;
+    private System.Windows.Forms.Button onlineImpactCalculationButton;
+    private System.Windows.Forms.Button exportImpactsMatrixButton;
+    private System.Windows.Forms.TrackBar impactThresholdTrackBar;
+    private System.Windows.Forms.Label impactThresholdLabel;
+    private System.Windows.Forms.Button relayoutGraphButton;
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/RunCollectionVariableInteractionNetworkView.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/RunCollectionVariableInteractionNetworkView.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/RunCollectionVariableInteractionNetworkView.cs	(revision 15929)
@@ -0,0 +1,505 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Core.Views;
+using HeuristicLab.Data;
+using HeuristicLab.MainForm;
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Visualization;
+using Ellipse = HeuristicLab.Visualization.Ellipse;
+using Rectangle = HeuristicLab.Visualization.Rectangle;
+
+namespace HeuristicLab.VariableInteractionNetworks.Views {
+  [View("Variable Interaction Network")]
+  [Content(typeof(RunCollection), IsDefaultView = false)]
+
+  public sealed partial class RunCollectionVariableInteractionNetworkView : ItemView {
+    public RunCollectionVariableInteractionNetworkView() {
+      InitializeComponent();
+      ConfigureNodeShapes();
+    }
+
+    public new RunCollection Content {
+      get { return (RunCollection)base.Content; }
+      set {
+        if (value != null && value != Content) {
+          base.Content = value;
+        }
+      }
+    }
+
+    private VariableInteractionNetwork variableInteractionNetwork;
+
+    private static void AssertSameProblemData(RunCollection runs) {
+      IDataset dataset = null;
+      IRegressionProblemData problemData = null;
+      foreach (var run in runs) {
+        var solution = (IRegressionSolution)run.Results.Values.Single(x => x is IRegressionSolution);
+        var ds = solution.ProblemData.Dataset;
+
+        if (solution.ProblemData == problemData) continue;
+        if (ds == dataset) continue;
+        if (problemData == null) {
+          problemData = solution.ProblemData;
+          continue;
+        }
+        if (dataset == null) {
+          dataset = ds;
+          continue;
+        }
+
+        if (problemData.TrainingPartition.Start != solution.ProblemData.TrainingPartition.Start || problemData.TrainingPartition.End != solution.ProblemData.TrainingPartition.End)
+          throw new InvalidOperationException("The runs must share the same data.");
+
+        if (!ds.DoubleVariables.SequenceEqual(dataset.DoubleVariables))
+          throw new InvalidOperationException("The runs must share the same data.");
+
+        foreach (var v in ds.DoubleVariables) {
+          var values1 = (IList<double>)ds.GetReadOnlyDoubleValues(v);
+          var values2 = (IList<double>)dataset.GetReadOnlyDoubleValues(v);
+
+          if (values1.Count != values2.Count)
+            throw new InvalidOperationException("The runs must share the same data.");
+
+          if (!values1.SequenceEqual(values2))
+            throw new InvalidOperationException("The runs must share the same data.");
+        }
+      }
+    }
+
+    public static RegressionEnsembleSolution CreateEnsembleSolution(IEnumerable<IRun> runs) {
+      var solutions = runs.Select(x => x.Results.Values.Single(v => v is IRegressionSolution)).Cast<IRegressionSolution>();
+      return new RegressionEnsembleSolution(new RegressionEnsembleModel(solutions.Select(x => x.Model)), solutions.First().ProblemData);
+    }
+
+    public static Dictionary<string, Tuple<IEnumerable<IRun>, Dictionary<string, double>>> CalculateVariableImpactsOnline(RunCollection runs, bool useBest) {
+      AssertSameProblemData(runs);
+      var solution = (IRegressionSolution)runs.First().Results.Values.Single(x => x is IRegressionSolution);
+      var dataset = (Dataset)solution.ProblemData.Dataset;
+      var originalValues = dataset.DoubleVariables.ToDictionary(x => x, x => dataset.GetReadOnlyDoubleValues(x).ToList());
+      var medians = dataset.DoubleVariables.ToDictionary(x => x, x => Enumerable.Repeat(originalValues[x].Median(), originalValues[x].Count).ToList());
+
+      var targetImpacts = new Dictionary<string, Tuple<IEnumerable<IRun>, Dictionary<string, double>>>();
+
+      if (useBest) {
+        // build network using only the best run for each target
+      } else {
+        var groups = runs.GroupBy(run => {
+          var sol = (IRegressionSolution)run.Results.Values.Single(x => x is IRegressionSolution);
+          return Concatenate(sol.ProblemData.AllowedInputVariables) + sol.ProblemData.TargetVariable;
+        });
+
+        foreach (var group in groups) {
+          // calculate average impacts
+          var averageImpacts = new Dictionary<string, double>();
+          solution = (IRegressionSolution)group.First().Results.Values.Single(x => x is IRegressionSolution);
+          foreach (var run in group) {
+            var sol = (IRegressionSolution)run.Results.Values.Single(v => v is IRegressionSolution);
+
+            DoubleLimit estimationLimits = null;
+            if (run.Parameters.ContainsKey("EstimationLimits")) {
+              estimationLimits = (DoubleLimit)run.Parameters["EstimationLimits"];
+            }
+            var md = dataset.ToModifiable();
+            var impacts = CalculateImpacts(sol, md, originalValues, medians, estimationLimits);
+            foreach (var pair in impacts) {
+              if (averageImpacts.ContainsKey(pair.Key))
+                averageImpacts[pair.Key] += pair.Value;
+              else {
+                averageImpacts[pair.Key] = pair.Value;
+              }
+            }
+          }
+          var count = group.Count();
+          var keys = averageImpacts.Keys.ToList();
+          foreach (var v in keys) {
+            averageImpacts[v] /= count;
+          }
+
+          targetImpacts[solution.ProblemData.TargetVariable] = new Tuple<IEnumerable<IRun>, Dictionary<string, double>>(group, averageImpacts);
+        }
+      }
+      return targetImpacts;
+    }
+
+    private static Dictionary<string, double> CalculateImpacts(IRegressionSolution solution, ModifiableDataset dataset,
+      Dictionary<string, List<double>> originalValues, Dictionary<string, List<double>> medianValues, DoubleLimit estimationLimits = null) {
+      var impacts = new Dictionary<string, double>();
+
+      var model = solution.Model;
+      var pd = solution.ProblemData;
+
+      var rows = pd.TrainingIndices.ToList();
+      var targetValues = pd.Dataset.GetDoubleValues(pd.TargetVariable, rows).ToList();
+
+
+      foreach (var v in pd.AllowedInputVariables) {
+        dataset.ReplaceVariable(v, medianValues[v]);
+
+        var estimatedValues = model.GetEstimatedValues(dataset, rows);
+        if (estimationLimits != null)
+          estimatedValues = estimatedValues.LimitToRange(estimationLimits.Lower, estimationLimits.Upper);
+
+        OnlineCalculatorError error;
+        var r = OnlinePearsonsRCalculator.Calculate(targetValues, estimatedValues, out error);
+        var newQuality = error == OnlineCalculatorError.None ? r * r : double.NaN;
+        var originalQuality = solution.TrainingRSquared;
+        impacts[v] = originalQuality - newQuality;
+
+        dataset.ReplaceVariable(v, originalValues[v]);
+      }
+      return impacts;
+    }
+
+    public static Dictionary<string, Tuple<IEnumerable<IRun>, Dictionary<string, double>>> CalculateVariableImpactsFromRunResults(RunCollection runs,
+      string qualityResultName, bool maximization, string impactsResultName, bool useBestRunsPerTarget = false) {
+      var targets = runs.GroupBy(x => ((IRegressionProblemData)x.Parameters["ProblemData"]).TargetVariable).ToList();
+      var targetImpacts = new Dictionary<string, Tuple<IEnumerable<IRun>, Dictionary<string, double>>>();
+
+      Func<IRun, double> getQualityValue = run => ((DoubleValue)run.Results[qualityResultName]).Value;
+
+      if (useBestRunsPerTarget) {
+        var bestRunsPerTarget = maximization
+          ? targets.Select(x => x.OrderBy(getQualityValue).Last())
+          : targets.Select(x => x.OrderBy(getQualityValue).First());
+
+        foreach (var run in bestRunsPerTarget) {
+          var pd = (IRegressionProblemData)run.Parameters["ProblemData"];
+          var target = pd.TargetVariable;
+          var impacts = (DoubleMatrix)run.Results[impactsResultName];
+          targetImpacts[target] = new Tuple<IEnumerable<IRun>, Dictionary<string, double>>(new[] { run }, impacts.RowNames.Select((x, i) => new { Name = x, Index = i }).ToDictionary(x => x.Name, x => impacts[x.Index, 0]));
+        }
+      } else {
+        foreach (var target in targets) {
+          var averageImpacts = CalculateAverageImpacts(new RunCollection(target), impactsResultName);
+          targetImpacts[target.Key] = new Tuple<IEnumerable<IRun>, Dictionary<string, double>>(target, averageImpacts);
+        }
+      }
+      return targetImpacts;
+    }
+
+    public static VariableInteractionNetwork CreateNetwork(Dictionary<string, Tuple<IEnumerable<IRun>, Dictionary<string, double>>> targetImpacts) {
+      var nodes = new Dictionary<string, IVertex>();
+      var vn = new VariableInteractionNetwork();
+      foreach (var ti in targetImpacts) {
+        var target = ti.Key;
+        var variableImpacts = ti.Value.Item2;
+        var targetRuns = ti.Value.Item1;
+        IVertex targetNode;
+
+        var variables = variableImpacts.Keys.ToList();
+        if (variables.Count == 0) continue;
+
+        if (!nodes.TryGetValue(target, out targetNode)) {
+          targetNode = new VariableNetworkNode { Label = target };
+          vn.AddVertex(targetNode);
+          nodes[target] = targetNode;
+        }
+
+        IVertex variableNode;
+        if (variables.Count > 1) {
+          var variableList = new List<string>(variables) { target };
+          var junctionLabel = Concatenate(variableList);
+          IVertex junctionNode;
+          var sb = new StringBuilder();
+          if (!nodes.TryGetValue(junctionLabel, out junctionNode)) {
+            var solutionsEnsemble = CreateEnsembleSolution(targetRuns);
+            junctionNode = new JunctionNetworkNode { Label = solutionsEnsemble.TrainingRSquared.ToString("N3", CultureInfo.CurrentCulture), Data = solutionsEnsemble };
+            vn.AddVertex(junctionNode);
+            nodes[junctionLabel] = junctionNode;
+            sb.AppendLine(junctionNode.Label);
+          }
+          IArc arc;
+          foreach (var v in variables) {
+            var impact = variableImpacts[v];
+            if (!nodes.TryGetValue(v, out variableNode)) {
+              variableNode = new VariableNetworkNode { Label = v };
+              vn.AddVertex(variableNode);
+              nodes[v] = variableNode;
+            }
+            arc = new Arc(variableNode, junctionNode) { Weight = impact, Label = impact.ToString("N3", CultureInfo.CurrentCulture) };
+            sb.AppendLine(v + ": " + arc.Label);
+            vn.AddArc(arc);
+          }
+          var jcnNode = (JunctionNetworkNode)junctionNode;
+          var trainingR2 = ((IRegressionSolution)jcnNode.Data).TrainingRSquared;
+          arc = new Arc(junctionNode, targetNode) { Weight = junctionNode.InArcs.Sum(x => x.Weight), Label = trainingR2.ToString("N3", CultureInfo.CurrentCulture) };
+          vn.AddArc(arc);
+        } else {
+          foreach (var v in variables) {
+            var impact = variableImpacts[v];
+            if (!nodes.TryGetValue(v, out variableNode)) {
+              variableNode = new VariableNetworkNode { Label = v };
+              vn.AddVertex(variableNode);
+              nodes[v] = variableNode;
+            }
+            var arc = new Arc(variableNode, targetNode) {
+              Weight = impact,
+              Label = impact.ToString("N3", CultureInfo.CurrentCulture)
+            };
+            vn.AddArc(arc);
+          }
+        }
+      }
+      return vn;
+    }
+
+    public static VariableInteractionNetwork ApplyThreshold(VariableInteractionNetwork originalNetwork, double threshold) {
+      var arcs = originalNetwork.Arcs.Where(x => x.Weight >= threshold).ToList();
+      if (!arcs.Any()) return originalNetwork;
+      var filteredNetwork = new VariableInteractionNetwork();
+      var cloner = new Cloner();
+      var vertices = arcs.SelectMany(x => new[] { x.Source, x.Target }).Select(cloner.Clone).Distinct(); // arcs are not cloned
+      filteredNetwork.AddVertices(vertices);
+      filteredNetwork.AddArcs(arcs.Select(x => (IArc)x.Clone(cloner)));
+
+      var unusedJunctions = filteredNetwork.Vertices.Where(x => x.InDegree == 0 && x is JunctionNetworkNode).ToList();
+      filteredNetwork.RemoveVertices(unusedJunctions);
+      var orphanedNodes = filteredNetwork.Vertices.Where(x => x.Degree == 0).ToList();
+      filteredNetwork.RemoveVertices(orphanedNodes);
+      return filteredNetwork.Vertices.Any() ? filteredNetwork : originalNetwork;
+    }
+
+    private static double CalculateAverageQuality(RunCollection runs) {
+      var pd = (IRegressionProblemData)runs.First().Parameters["ProblemData"];
+      var target = pd.TargetVariable;
+      var inputs = pd.AllowedInputVariables;
+
+      if (!runs.All(x => {
+        var problemData = (IRegressionProblemData)x.Parameters["ProblemData"];
+        return target == problemData.TargetVariable && inputs.SequenceEqual(problemData.AllowedInputVariables);
+      })) {
+        throw new ArgumentException("All runs must have the same target and inputs.");
+      }
+      return runs.Average(x => ((DoubleValue)x.Results["Best training solution quality"]).Value);
+    }
+
+    public static Dictionary<string, double> CalculateAverageImpacts(RunCollection runs, string resultName) {
+      var pd = (IRegressionProblemData)runs.First().Parameters["ProblemData"];
+      var target = pd.TargetVariable;
+      var inputs = pd.AllowedInputVariables.ToList();
+
+      var impacts = inputs.ToDictionary(x => x, x => 0d);
+
+      // check if all the runs have the same target and same inputs
+      if (!runs.All(x => {
+        var problemData = (IRegressionProblemData)x.Parameters["ProblemData"];
+        return target == problemData.TargetVariable && inputs.SequenceEqual(problemData.AllowedInputVariables);
+      })) {
+        throw new ArgumentException("All runs must have the same target and inputs.");
+      }
+
+      foreach (var run in runs) {
+        var impactsMatrix = (DoubleMatrix)run.Results[resultName];
+        int i = 0;
+        foreach (var v in impactsMatrix.RowNames) {
+          impacts[v] += impactsMatrix[i, 0];
+          ++i;
+        }
+      }
+
+      foreach (var v in inputs) {
+        impacts[v] /= runs.Count;
+      }
+
+      return impacts;
+    }
+
+    private static string Concatenate(IEnumerable<string> strings) {
+      var sb = new StringBuilder();
+      foreach (var s in strings) {
+        sb.Append(s);
+      }
+      return sb.ToString();
+    }
+
+    private void ConfigureNodeShapes() {
+      graphChart.ClearShapes();
+      var font = new Font(FontFamily.GenericSansSerif, 12);
+      graphChart.AddShape(typeof(VariableNetworkNode), new LabeledPrimitive(new Ellipse(graphChart.Chart, new PointD(0, 0), new PointD(30, 30), Pens.Black, Brushes.White), "", font));
+      graphChart.AddShape(typeof(JunctionNetworkNode), new LabeledPrimitive(new Rectangle(graphChart.Chart, new PointD(0, 0), new PointD(15, 15), Pens.Black, Brushes.DarkGray), "", font));
+    }
+
+    #region events
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      var run = Content.First();
+      var pd = (IRegressionProblemData)run.Parameters["ProblemData"];
+      var variables = new HashSet<string>(new List<string>(pd.Dataset.DoubleVariables));
+      impactResultNameComboBox.Items.Clear();
+      foreach (var result in run.Results.Where(x => x.Value is DoubleMatrix)) {
+        var m = (DoubleMatrix)result.Value;
+        if (m.RowNames.All(x => variables.Contains(x)))
+          impactResultNameComboBox.Items.Add(result.Key);
+      }
+      qualityResultNameComboBox.Items.Clear();
+      foreach (var result in run.Results.Where(x => x.Value is DoubleValue)) {
+        qualityResultNameComboBox.Items.Add(result.Key);
+      }
+      if (impactResultNameComboBox.Items.Count > 0) {
+        impactResultNameComboBox.Text = (string)impactResultNameComboBox.Items[0];
+      }
+      if (qualityResultNameComboBox.Items.Count > 0) {
+        qualityResultNameComboBox.Text = (string)qualityResultNameComboBox.Items[0];
+      }
+      if (impactResultNameComboBox.Items.Count > 0 && qualityResultNameComboBox.Items.Count > 0)
+        NetworkConfigurationChanged(this, EventArgs.Empty);
+    }
+
+    private void TextBoxValidating(object sender, CancelEventArgs e) {
+      double v;
+      string errorMsg = "Could not parse the entered value. Please input a real number.";
+      var tb = (TextBox)sender;
+      if (!double.TryParse(tb.Text, out v)) {
+        e.Cancel = true;
+        tb.Select(0, tb.Text.Length);
+
+        // Set the ErrorProvider error with the text to display. 
+        this.errorProvider.SetError(tb, errorMsg);
+        errorProvider.BlinkStyle = ErrorBlinkStyle.NeverBlink;
+        errorProvider.SetIconPadding(tb, -20);
+      }
+    }
+
+    private void ImpactThresholdTextBoxValidated(object sender, EventArgs e) {
+      var tb = (TextBox)sender;
+      errorProvider.SetError(tb, string.Empty);
+      double impact;
+      if (!double.TryParse(tb.Text, out impact)) {
+        impact = 0.2;
+      }
+      var network = ApplyThreshold(variableInteractionNetwork, impact);
+      graphChart.Graph = network;
+    }
+
+    private void LayoutConfigurationBoxValidated(object sender, EventArgs e) {
+      var tb = (TextBox)sender;
+      errorProvider.SetError(tb, string.Empty);
+      LayoutConfigurationChanged(sender, e);
+    }
+
+    private void NetworkConfigurationChanged(object sender, EventArgs e) {
+      var useBest = impactAggregationComboBox.SelectedIndex <= 0;
+      var threshold = impactThresholdTrackBar.Value / 100.0;
+      var qualityResultName = qualityResultNameComboBox.Text;
+      var impactsResultName = impactResultNameComboBox.Text;
+      if (string.IsNullOrEmpty(qualityResultName) || string.IsNullOrEmpty(impactsResultName))
+        return;
+      var maximization = maximizationCheckBox.Checked;
+      var impacts = CalculateVariableImpactsFromRunResults(Content, qualityResultName, maximization, impactsResultName, useBest);
+      variableInteractionNetwork = CreateNetwork(impacts);
+      var network = ApplyThreshold(variableInteractionNetwork, threshold);
+      graphChart.Graph = network;
+    }
+
+    private void LayoutConfigurationChanged(object sender, EventArgs e) {
+      ConstrainedForceDirectedLayout.EdgeRouting routingMode;
+      switch (edgeRoutingComboBox.SelectedIndex) {
+        case 0:
+          routingMode = ConstrainedForceDirectedLayout.EdgeRouting.None;
+          break;
+        case 1:
+          routingMode = ConstrainedForceDirectedLayout.EdgeRouting.Polyline;
+          break;
+        case 2:
+          routingMode = ConstrainedForceDirectedLayout.EdgeRouting.Orthogonal;
+          break;
+        default:
+          throw new ArgumentException("Invalid edge routing mode.");
+      }
+      var idealEdgeLength = double.Parse(idealEdgeLengthTextBox.Text);
+      if (routingMode == graphChart.RoutingMode && idealEdgeLength.IsAlmost(graphChart.DefaultEdgeLength)) return;
+      graphChart.RoutingMode = routingMode;
+      graphChart.PerformEdgeRouting = routingMode != ConstrainedForceDirectedLayout.EdgeRouting.None;
+      graphChart.DefaultEdgeLength = idealEdgeLength;
+      graphChart.Draw();
+    }
+
+    private void ControlsEnable(bool enabled) {
+      qualityResultNameComboBox.Enabled
+        = impactResultNameComboBox.Enabled
+        = impactAggregationComboBox.Enabled
+        = impactThresholdTrackBar.Enabled
+        = onlineImpactCalculationButton.Enabled
+        = edgeRoutingComboBox.Enabled
+        = idealEdgeLengthTextBox.Enabled
+        = maximizationCheckBox.Enabled = enabled;
+    }
+
+    private void onlineImpactCalculationButton_Click(object sender, EventArgs args) {
+      var worker = new BackgroundWorker();
+      worker.DoWork += (o, e) => {
+        ControlsEnable(false);
+        var impacts = CalculateVariableImpactsOnline(Content, false);
+        variableInteractionNetwork = CreateNetwork(impacts);
+        var threshold = impactThresholdTrackBar.Minimum + (double)impactThresholdTrackBar.Value / impactThresholdTrackBar.Maximum;
+        graphChart.Graph = ApplyThreshold(variableInteractionNetwork, threshold);
+      };
+      worker.RunWorkerCompleted += (o, e) => ControlsEnable(true);
+      worker.RunWorkerAsync();
+    }
+
+    private void relayoutGraphButton_Click(object sender, EventArgs e) {
+      graphChart.Draw();
+    }
+    #endregion
+
+    private void exportImpactsMatrixButton_Click(object sender, EventArgs e) {
+      var graph = graphChart.Graph;
+      var labels = graph.Vertices.OfType<VariableNetworkNode>().Select(x => x.Label).ToList();
+      labels.Sort(); // sort variables alphabetically
+      var matrix = new DoubleMatrix(labels.Count, labels.Count) { RowNames = labels, ColumnNames = labels };
+      var indexes = labels.Select((x, i) => new { Label = x, Index = i }).ToDictionary(x => x.Label, x => x.Index);
+      var junctions = graph.Vertices.OfType<JunctionNetworkNode>().ToList();
+      foreach (var jn in junctions) {
+        var target = jn.OutArcs.First().Target.Label;
+        var targetIndex = indexes[target];
+        foreach (var input in jn.InArcs) {
+          var inputIndex = indexes[input.Source.Label];
+          var inputImpact = input.Weight;
+          matrix[targetIndex, inputIndex] = inputImpact;
+        }
+      }
+      for (int i = 0; i < labels.Count; ++i) matrix[i, i] = 1;
+      MainFormManager.MainForm.ShowContent(matrix);
+    }
+
+    private void impactThresholdTrackBar_ValueChanged(object sender, EventArgs e) {
+      var impact = impactThresholdTrackBar.Minimum + (double)impactThresholdTrackBar.Value / impactThresholdTrackBar.Maximum;
+      impactThresholdLabel.Text = impact.ToString("N3", CultureInfo.CurrentCulture);
+      var network = ApplyThreshold(variableInteractionNetwork, impact);
+      graphChart.Graph = network;
+    }
+
+
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/RunCollectionVariableInteractionNetworkView.resx
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/RunCollectionVariableInteractionNetworkView.resx	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/RunCollectionVariableInteractionNetworkView.resx	(revision 15929)
@@ -0,0 +1,123 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="errorProvider.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+</root>
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.sln
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.sln	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.sln	(revision 15929)
@@ -0,0 +1,53 @@
+﻿
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.VariableInteractionNetworks-3.3", "HeuristicLab.VariableInteractionNetworks\3.3\HeuristicLab.VariableInteractionNetworks-3.3.csproj", "{D891ED5C-77EB-4A24-9967-DECADBF15CE9}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E44C8817-BBED-40EA-ADE6-6C36F557A622}"
+	ProjectSection(SolutionItems) = preProject
+		PreBuildEvent.cmd = PreBuildEvent.cmd
+	EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.VariableInteractionNetworks.Views-3.3", "HeuristicLab.VariableInteractionNetworks.Views\3.3\HeuristicLab.VariableInteractionNetworks.Views-3.3.csproj", "{EA1A0A27-A38D-4086-812A-9CE0FF557103}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Debug|x64.ActiveCfg = Debug|x64
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Debug|x64.Build.0 = Debug|x64
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Debug|x86.ActiveCfg = Debug|x86
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Debug|x86.Build.0 = Debug|x86
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Release|x64.ActiveCfg = Release|x64
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Release|x64.Build.0 = Release|x64
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Release|x86.ActiveCfg = Release|x86
+		{D891ED5C-77EB-4A24-9967-DECADBF15CE9}.Release|x86.Build.0 = Release|x86
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Debug|x64.ActiveCfg = Debug|x64
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Debug|x64.Build.0 = Debug|x64
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Debug|x86.ActiveCfg = Debug|x86
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Debug|x86.Build.0 = Debug|x86
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Release|x64.ActiveCfg = Release|x64
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Release|x64.Build.0 = Release|x64
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Release|x86.ActiveCfg = Release|x86
+		{EA1A0A27-A38D-4086-812A-9CE0FF557103}.Release|x86.Build.0 = Release|x86
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/HeuristicLab.VariableInteractionNetworks-3.3.csproj
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/HeuristicLab.VariableInteractionNetworks-3.3.csproj	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/HeuristicLab.VariableInteractionNetworks-3.3.csproj	(revision 15929)
@@ -0,0 +1,224 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{D891ED5C-77EB-4A24-9967-DECADBF15CE9}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.VariableInteractionNetworks</RootNamespace>
+    <AssemblyName>HeuristicLab.VariableInteractionNetworks-3.3</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="HeuristicLab.Analysis-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Analysis-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Collections-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Collections-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Common-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Common-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Common.Resources-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Common.Resources-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Core-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Core-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Data-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Data-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Data.Views-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\HeuristicLab.Data.Views\3.3\obj\Release\HeuristicLab.Data.Views-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.MainForm-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.MainForm-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.MainForm.WindowsForms-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.MainForm.WindowsForms-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Operators-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Operators-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Optimization-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimizer-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Optimizer-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Parameters-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Parameters-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Persistence-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Persistence-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.PluginInfrastructure-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic.Classification-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis.Symbolic.Classification-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.Instances-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.Instances-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="PresentationCore" />
+    <Reference Include="PresentationFramework" />
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+    <Reference Include="WindowsBase" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="INetworkNode.cs" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SymbolicDataAnalysisVariableImpactsAnalyzer.cs" />
+    <Compile Include="VariableInteractionNetwork.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="Plugin.cs.frame" />
+    <None Include="Properties\AssemblyInfo.cs.frame" />
+  </ItemGroup>
+  <ItemGroup>
+    <WCFMetadata Include="Service References\" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd</PreBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/INetworkNode.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/INetworkNode.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/INetworkNode.cs	(revision 15929)
@@ -0,0 +1,6 @@
+﻿namespace HeuristicLab.VariableInteractionNetworks {
+  public interface INetworkNode {
+    string Id { get; }
+    string Description { get; set; }
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/Plugin.cs.frame
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/Plugin.cs.frame	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/Plugin.cs.frame	(revision 15929)
@@ -0,0 +1,53 @@
+#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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.VariableInteractionNetworks {
+  /// <summary>
+  /// Plugin class for HeuristicLab.VariableInteractionNetworks plugin.
+  /// </summary>
+  [Plugin("HeuristicLab.VariableInteractionNetworks", "Provides the functionality for generating and visualizing variable interaction networks.", "3.3.10.$WCREV$")]
+  [PluginFile("HeuristicLab.VariableInteractionNetworks-3.3.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.Collections", "3.3")]
+  [PluginDependency("HeuristicLab.Common", "3.3")]
+  [PluginDependency("HeuristicLab.Common.Resources", "3.3")]
+  [PluginDependency("HeuristicLab.Analysis", "3.3")]
+  [PluginDependency("HeuristicLab.Common.Resources", "3.3")]
+  [PluginDependency("HeuristicLab.Core", "3.3")]
+  [PluginDependency("HeuristicLab.Data", "3.3")]
+  [PluginDependency("HeuristicLab.Data.Views", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization", "3.3")]
+  [PluginDependency("HeuristicLab.Optimizer", "3.3")]
+  [PluginDependency("HeuristicLab.Parameters", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
+  [PluginDependency("HeuristicLab.Operators", "3.3")]
+  [PluginDependency("HeuristicLab.MainForm", "3.3")]
+  [PluginDependency("HeuristicLab.MainForm.WindowsForms", "3.3")]
+  [PluginDependency("HeuristicLab.Problems.DataAnalysis.Symbolic.Regression", "3.4")]
+  [PluginDependency("HeuristicLab.Problems.DataAnalysis.Symbolic.Classification", "3.4")]
+  [PluginDependency("HeuristicLab.Problems.DataAnalysis.Symbolic", "3.4")]
+  [PluginDependency("HeuristicLab.Problems.DataAnalysis", "3.4")]
+  [PluginDependency("HeuristicLab.Problems.Instances", "3.3")]
+  [PluginDependency("HeuristicLab.Encodings.SymbolicExpressionTreeEncoding", "3.4")]  
+  public class Plugin : PluginBase {
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/Properties/AssemblyInfo.cs.frame
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/Properties/AssemblyInfo.cs.frame	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/Properties/AssemblyInfo.cs.frame	(revision 15929)
@@ -0,0 +1,55 @@
+#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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.VariableInteractionNetworks")]
+[assembly: AssemblyDescription("HeuristicLab Variable Interaction Networks")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2014 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("2C246561-1750-4770-BDB9-0FD89D844068")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("3.3.0.0")]
+[assembly: AssemblyFileVersion("3.3.10.$WCREV$")]
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/SymbolicDataAnalysisVariableImpactsAnalyzer.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/SymbolicDataAnalysisVariableImpactsAnalyzer.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/SymbolicDataAnalysisVariableImpactsAnalyzer.cs	(revision 15929)
@@ -0,0 +1,286 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
+
+namespace HeuristicLab.VariableInteractionNetworks {
+  [Item("SymbolicRegressionVariableImpactsAnalyzer", "An analyzer which calculates variable impacts based on the average node impacts from the tree")]
+  [StorableClass]
+  public class SymbolicRegressionVariableImpactsAnalyzer : SymbolicDataAnalysisAnalyzer {
+    #region parameter names
+    private const string UpdateCounterParameterName = "UpdateCounter";
+    private const string UpdateIntervalParameterName = "UpdateInterval";
+    public const string QualityParameterName = "Quality";
+    private const string SymbolicDataAnalysisTreeInterpreterParameterName = "SymbolicExpressionTreeInterpreter";
+    private const string ProblemDataParameterName = "ProblemData";
+    private const string ApplyLinearScalingParameterName = "ApplyLinearScaling";
+    private const string MaxCOIterationsParameterName = "MaxCOIterations";
+    private const string EstimationLimitsParameterName = "EstimationLimits";
+    private const string EvaluatorParameterName = "Evaluator";
+    private const string PercentageBestParameterName = "PercentageBest";
+    private const string LastGenerationsParameterName = "LastGenerations";
+    private const string MaximumGenerationsParameterName = "MaximumGenerations";
+    private const string OptimizeConstantsParameterName = "OptimizeConstants";
+    private const string PruneTreesParameterName = "PruneTrees";
+    private const string AverageVariableImpactsResultName = "Average variable impacts";
+    private const string AverageVariableImpactsHistoryResultName = "Average variable impacts history";
+    #endregion
+
+    private SymbolicRegressionSolutionImpactValuesCalculator impactsCalculator;
+
+    #region parameters
+    public ValueParameter<IntValue> UpdateCounterParameter {
+      get { return (ValueParameter<IntValue>)Parameters[UpdateCounterParameterName]; }
+    }
+    public ValueParameter<IntValue> UpdateIntervalParameter {
+      get { return (ValueParameter<IntValue>)Parameters[UpdateIntervalParameterName]; }
+    }
+    public IScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters[QualityParameterName]; }
+    }
+    public ILookupParameter<ISymbolicDataAnalysisExpressionTreeInterpreter> SymbolicDataAnalysisTreeInterpreterParameter {
+      get { return (ILookupParameter<ISymbolicDataAnalysisExpressionTreeInterpreter>)Parameters[SymbolicDataAnalysisTreeInterpreterParameterName]; }
+    }
+    public ILookupParameter<IRegressionProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<IRegressionProblemData>)Parameters[ProblemDataParameterName]; }
+    }
+    public ILookupParameter<BoolValue> ApplyLinearScalingParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters[ApplyLinearScalingParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> MaxCOIterationsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[MaxCOIterationsParameterName]; }
+    }
+    public ILookupParameter<DoubleLimit> EstimationLimitsParameter {
+      get { return (ILookupParameter<DoubleLimit>)Parameters[EstimationLimitsParameterName]; }
+    }
+    public ILookupParameter<ISymbolicRegressionSingleObjectiveEvaluator> EvaluatorParameter {
+      get { return (ILookupParameter<ISymbolicRegressionSingleObjectiveEvaluator>)Parameters[EvaluatorParameterName]; }
+    }
+    public IFixedValueParameter<PercentValue> PercentageBestParameter {
+      get { return (IFixedValueParameter<PercentValue>)Parameters[PercentageBestParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> LastGenerationsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[LastGenerationsParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> OptimizeConstantsParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[OptimizeConstantsParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> PruneTreesParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[PruneTreesParameterName]; }
+    }
+    private ILookupParameter<IntValue> MaximumGenerationsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters[MaximumGenerationsParameterName]; }
+    }
+    #endregion
+
+    #region parameter properties
+    public int UpdateCounter {
+      get { return UpdateCounterParameter.Value.Value; }
+      set { UpdateCounterParameter.Value.Value = value; }
+    }
+    public int UpdateInterval {
+      get { return UpdateIntervalParameter.Value.Value; }
+      set { UpdateIntervalParameter.Value.Value = value; }
+    }
+    #endregion
+
+    public SymbolicRegressionVariableImpactsAnalyzer() {
+      #region add parameters
+      Parameters.Add(new ValueParameter<IntValue>(UpdateCounterParameterName, new IntValue(0)));
+      Parameters.Add(new ValueParameter<IntValue>(UpdateIntervalParameterName, new IntValue(1)));
+      Parameters.Add(new LookupParameter<IRegressionProblemData>(ProblemDataParameterName));
+      Parameters.Add(new LookupParameter<ISymbolicDataAnalysisExpressionTreeInterpreter>(SymbolicDataAnalysisTreeInterpreterParameterName));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>(QualityParameterName, "The individual qualities."));
+      Parameters.Add(new LookupParameter<BoolValue>(ApplyLinearScalingParameterName));
+      Parameters.Add(new LookupParameter<DoubleLimit>(EstimationLimitsParameterName));
+      Parameters.Add(new FixedValueParameter<IntValue>(MaxCOIterationsParameterName, new IntValue(3)));
+      Parameters.Add(new FixedValueParameter<PercentValue>(PercentageBestParameterName, new PercentValue(1)));
+      Parameters.Add(new FixedValueParameter<IntValue>(LastGenerationsParameterName, new IntValue(10)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(OptimizeConstantsParameterName, new BoolValue(false)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(PruneTreesParameterName, new BoolValue(false)));
+      Parameters.Add(new LookupParameter<IntValue>(MaximumGenerationsParameterName, "The maximum number of generations which should be processed."));
+      Parameters.Add(new LookupParameter<ISymbolicRegressionSingleObjectiveEvaluator>(EvaluatorParameterName));
+      #endregion
+
+      impactsCalculator = new SymbolicRegressionSolutionImpactValuesCalculator();
+    }
+
+    [StorableConstructor]
+    protected SymbolicRegressionVariableImpactsAnalyzer(bool deserializing) : base(deserializing) { }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      impactsCalculator = new SymbolicRegressionSolutionImpactValuesCalculator();
+
+      if (!Parameters.ContainsKey(EvaluatorParameterName))
+        Parameters.Add(new LookupParameter<ISymbolicRegressionSingleObjectiveEvaluator>(EvaluatorParameterName));
+    }
+
+    protected SymbolicRegressionVariableImpactsAnalyzer(SymbolicRegressionVariableImpactsAnalyzer original, Cloner cloner)
+        : base(original, cloner) {
+      impactsCalculator = new SymbolicRegressionSolutionImpactValuesCalculator();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicRegressionVariableImpactsAnalyzer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      #region Update counter & update interval
+      UpdateCounter++;
+      if (UpdateCounter != UpdateInterval) {
+        return base.Apply();
+      }
+      UpdateCounter = 0;
+      #endregion
+      var results = ResultCollectionParameter.ActualValue;
+      int maxGen = MaximumGenerationsParameter.ActualValue.Value;
+      int gen = results.ContainsKey("Generations") ? ((IntValue)results["Generations"].Value).Value : 0;
+      int lastGen = LastGenerationsParameter.Value.Value;
+
+      if (lastGen > 0 && gen < maxGen - lastGen)
+        return base.Apply();
+
+      var trees = SymbolicExpressionTree.ToArray();
+      var qualities = QualityParameter.ActualValue.ToArray();
+
+      Array.Sort(qualities, trees);
+      Array.Reverse(qualities);
+      Array.Reverse(trees);
+
+      var interpreter = SymbolicDataAnalysisTreeInterpreterParameter.ActualValue;
+      var problemData = ProblemDataParameter.ActualValue;
+      var applyLinearScaling = ApplyLinearScalingParameter.ActualValue.Value;
+      var constantOptimizationIterations = MaxCOIterationsParameter.Value.Value; // fixed value parameter => Value
+      var estimationLimits = EstimationLimitsParameter.ActualValue; // lookup parameter => ActualValue
+      var percentageBest = PercentageBestParameter.Value.Value;
+      var optimizeConstants = OptimizeConstantsParameter.Value.Value;
+      var pruneTrees = PruneTreesParameter.Value.Value;
+
+      var allowedInputVariables = problemData.AllowedInputVariables.ToList();
+      DataTable dataTable;
+      if (!results.ContainsKey(AverageVariableImpactsHistoryResultName)) {
+        dataTable = new DataTable("Variable impacts", "Average impact of variables over the population");
+        dataTable.VisualProperties.XAxisTitle = "Generation";
+        dataTable.VisualProperties.YAxisTitle = "Average variable impact";
+        results.Add(new Result(AverageVariableImpactsHistoryResultName, dataTable));
+
+        foreach (var v in allowedInputVariables) {
+          dataTable.Rows.Add(new DataRow(v) { VisualProperties = { StartIndexZero = true } });
+        }
+      }
+      dataTable = (DataTable)results[AverageVariableImpactsHistoryResultName].Value;
+
+      int nTrees = (int)Math.Round(trees.Length * percentageBest);
+      var bestTrees = trees.Take(nTrees).Select(x => (ISymbolicExpressionTree)x.Clone()).ToList();
+      // simplify trees before doing anything else
+      var simplifiedTrees = bestTrees.Select(x => TreeSimplifier.Simplify(x)).ToList();
+
+      if (optimizeConstants) {
+        for (int i = 0; i < simplifiedTrees.Count; ++i) {
+          qualities[i].Value = SymbolicRegressionConstantOptimizationEvaluator.OptimizeConstants(interpreter, simplifiedTrees[i], problemData, problemData.TrainingIndices, applyLinearScaling, constantOptimizationIterations, true, estimationLimits.Lower, estimationLimits.Upper);
+        }
+      }
+
+      if (pruneTrees) {
+        for (int i = 0; i < simplifiedTrees.Count; ++i) {
+          simplifiedTrees[i] = SymbolicRegressionPruningOperator.Prune(simplifiedTrees[i], impactsCalculator, interpreter, problemData, estimationLimits, problemData.TrainingIndices);
+        }
+      }
+      // map each variable to a list of indices of the trees that contain it
+      var variablesToTreeIndices = allowedInputVariables.ToDictionary(x => x, x => Enumerable.Range(0, simplifiedTrees.Count).Where(i => ContainsVariable(simplifiedTrees[i], x)).ToList());
+
+      // variable values used for restoring original values in the dataset
+      var variableValues = allowedInputVariables.Select(x => problemData.Dataset.GetReadOnlyDoubleValues(x).ToList()).ToList();
+      // the ds gets new variable values (not the above).
+      var variableNames = allowedInputVariables.Concat(new[] { problemData.TargetVariable }).ToList();
+      var ds = new ModifiableDataset(variableNames, variableNames.Select(x => problemData.Dataset.GetReadOnlyDoubleValues(x).ToList()));
+      var pd = new RegressionProblemData(ds, allowedInputVariables, problemData.TargetVariable);
+      pd.TrainingPartition.Start = problemData.TrainingPartition.Start;
+      pd.TrainingPartition.End = problemData.TrainingPartition.End;
+      pd.TestPartition.Start = problemData.TestPartition.Start;
+      pd.TestPartition.End = problemData.TestPartition.End;
+
+      for (int i = 0; i < allowedInputVariables.Count; ++i) {
+        var v = allowedInputVariables[i];
+        var median = problemData.Dataset.GetDoubleValues(v, problemData.TrainingIndices).Median();
+        var values = new List<double>(Enumerable.Repeat(median, problemData.Dataset.Rows));
+        // replace values with median
+        ds.ReplaceVariable(v, values);
+
+        var indices = variablesToTreeIndices[v];
+        if (!indices.Any()) {
+          dataTable.Rows[v].Values.Add(0);
+          continue;
+        }
+
+        var averageImpact = 0d;
+        for (int j = 0; j < indices.Count; ++j) {
+          var tree = simplifiedTrees[j];
+          var originalQuality = qualities[j].Value;
+          double newQuality;
+          if (optimizeConstants) {
+            newQuality = SymbolicRegressionConstantOptimizationEvaluator.OptimizeConstants(interpreter, tree, pd, problemData.TrainingIndices, applyLinearScaling, constantOptimizationIterations, true, estimationLimits.Lower, estimationLimits.Upper);
+          } else {
+            var evaluator = EvaluatorParameter.ActualValue;
+            newQuality = evaluator.Evaluate(this.ExecutionContext, tree, pd, pd.TrainingIndices);
+          }
+          averageImpact += originalQuality - newQuality; // impact calculated this way may be negative
+        }
+        averageImpact /= indices.Count;
+        dataTable.Rows[v].Values.Add(averageImpact);
+        // restore original values
+        ds.ReplaceVariable(v, variableValues[i]);
+      }
+
+      var averageVariableImpacts = new DoubleMatrix(dataTable.Rows.Count, 1);
+      var rowNames = dataTable.Rows.Select(x => x.Name).ToList();
+      averageVariableImpacts.RowNames = rowNames;
+      for (int i = 0; i < rowNames.Count; ++i) {
+        averageVariableImpacts[i, 0] = dataTable.Rows[rowNames[i]].Values.Last();
+      }
+      if (!results.ContainsKey(AverageVariableImpactsResultName)) {
+        results.Add(new Result(AverageVariableImpactsResultName, averageVariableImpacts));
+      } else {
+        results[AverageVariableImpactsResultName].Value = averageVariableImpacts;
+      }
+      return base.Apply();
+    }
+
+    private static bool ContainsVariable(ISymbolicExpressionTree tree, string variableName) {
+      return tree.IterateNodesPrefix().OfType<VariableTreeNode>().Any(x => x.VariableName == variableName);
+    }
+  }
+}
+
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/VariableInteractionNetwork.cs
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/VariableInteractionNetwork.cs	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks/3.3/VariableInteractionNetwork.cs	(revision 15929)
@@ -0,0 +1,355 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.Eventing.Reader;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.VariableInteractionNetworks {
+  [Item("VariableInteractionNetwork", "A graph representation of variables and their relationships.")]
+  [StorableClass]
+  public class VariableInteractionNetwork : DirectedGraph {
+    /// <summary>
+    /// Creates a network from a matrix of variable impacts (each row represents a target variable, each column represents an input variable)
+    /// The network is acyclic. Values in the diagonal are ignored.
+    /// The algorithm starts with an empty network and incrementally adds next most relevant input variable for each target variable up to a given threshold
+    /// In each iteration cycles are broken by removing the weakest link.
+    /// </summary>
+    /// <param name="nmse">vector of NMSE values for each target variable</param>
+    /// <param name="variableImpacts">Variable impacts (smaller is lower impact). Row names and columns names should be set</param>
+    /// <param name="nmseThreshold">Threshold for NMSE values. Variables with a NMSE value larger than the threshold are considered as independent variables</param>
+    /// <param name="varImpactThreshold">Threshold for variable impact values. Impacts with a value smaller than the threshold are considered as independent</param>
+    /// <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();
+      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++) {
+        var name = varNames[i];
+        var varVertex = new VariableNetworkNode() { Label = name };
+        network.AddVertex(varVertex);
+        if (nmse[i] < nmseThreshold) {
+          var functionVertex = new JunctionNetworkNode() { Label = "f_" + name };
+          name2funVertex.Add(name, functionVertex);
+          network.AddVertex(functionVertex);
+          var predArc = network.AddArc(functionVertex, varVertex);
+          predArc.Weight = double.PositiveInfinity; // never delete arcs from f_x -> x (representing output of a function)
+        }
+      }
+
+      // rel is updated (impacts which are represented in the network are set to zero)
+      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;
+
+      var addedArcs = AddArcs(network, rel, varNames, name2funVertex, varImpactThreshold);
+      while (addedArcs.Any()) {
+        var cycles = network.FindShortestCycles().ToList();
+        while (cycles.Any()) {
+          // delete weakest link
+          var weakestArc = cycles.SelectMany(cycle => network.ArcsForCycle(cycle)).OrderBy(a => a.Weight).First();
+          network.RemoveArc(weakestArc);
+
+          cycles = network.FindShortestCycles().ToList();
+        }
+
+        addedArcs = AddArcs(network, rel, varNames, name2funVertex, varImpactThreshold);
+      }
+
+      return network;
+    }
+
+    /// <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)
+
+        var rowVector = Enumerable.Range(0, impacts.GetLength(0)).Select(col => impacts[row, col]).ToArray();
+        var max = rowVector.Max();
+        if (max > threshold) {
+          var idxOfMax = Array.IndexOf<double>(rowVector, max);
+          impacts[row, idxOfMax] = double.NegativeInfinity; // edge is not considered anymore
+          var srcName = varNames[idxOfMax];
+          var dstName = varNames[row];
+          var vertex = network.Vertices.Single(v => v.Label == srcName);
+          var arc = network.AddArc(vertex, name2funVertex[dstName]);
+          arc.Weight = max;
+          newArcs.Add(arc);
+        }
+      }
+      return newArcs;
+    }
+
+    [StorableConstructor]
+    public VariableInteractionNetwork(bool deserializing) : base(deserializing) { }
+
+    public VariableInteractionNetwork() { }
+
+    protected VariableInteractionNetwork(VariableInteractionNetwork original, Cloner cloner) : base(original, cloner) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new VariableInteractionNetwork(this, cloner);
+    }
+    private IList<IArc> ArcsForCycle(IList<IVertex> cycle) {
+      var res = new List<IArc>();
+      foreach (var t in cycle.Zip(cycle.Skip(1), Tuple.Create)) {
+        var src = t.Item1;
+        var dst = t.Item2;
+        var arc = Arcs.Single(a => a.Source == src && a.Target == dst);
+        res.Add(arc);
+      }
+      return res;
+    }
+
+
+    // 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))
+          yield return cycle;
+      }
+    }
+
+    private IEnumerable<IList<IVertex>> FindShortestCycles(VariableNetworkNode startVariable) {
+      var q = new Queue<List<IVertex>>(); // queue of paths
+      var path = new List<IVertex>();
+      var cycles = new List<List<IVertex>>();
+      var maxPathLength = base.Vertices.Count();
+
+      path.Add(startVariable);
+      q.Enqueue(new List<IVertex>(path));
+
+      FindShortestCycles(q, maxPathLength, cycles);
+      return cycles;
+    }
+
+    // TODO efficiency
+    private void FindShortestCycles(Queue<List<IVertex>> queue, int maxPathLength, List<List<IVertex>> cycles) {
+      while (queue.Any()) {
+        var path = queue.Dequeue();
+        if (path.Count > 1 && path.First() == path.Last()) {
+          cycles.Add(new List<IVertex>(path)); // found a cycle
+        } 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) {
+            queue.Enqueue(new List<IVertex>(path.Concat(new IVertex[] { neighbour })));
+          }
+        }
+      }
+    }
+
+    public DoubleMatrix GetWeightsMatrix() {
+      var names = Vertices.OfType<VariableNetworkNode>()
+        .Select(v => v.Label)
+        .OrderBy(s => s, new NaturalStringComparer()).ToArray();
+      var w = new double[names.Length, names.Length];
+
+      var name2idx = new Dictionary<string, int>();
+      for (int i = 0; i < names.Length; i++) {
+        name2idx.Add(names[i], i);
+      }
+
+      foreach (var arc in Arcs) {
+        // only consider arcs going into a junction node
+        var target = arc.Target as JunctionNetworkNode;
+        if (target != null) {
+          var srcVarName = arc.Source.Label;
+          // each function node must have exactly one outgoing arc
+          var dstVarName = arc.Target.OutArcs.Single().Target.Label;
+
+          w[name2idx[dstVarName], name2idx[srcVarName]] = arc.Weight;
+        }
+      }
+
+
+      return new DoubleMatrix(w, names, names);
+    }
+
+    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, 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();
+    }
+  }
+
+  [Item("VariableNetworkNode", "A graph vertex which represents a symbolic regression variable.")]
+  [StorableClass]
+  public class VariableNetworkNode : Vertex<IDeepCloneable>, INetworkNode {
+    public VariableNetworkNode() {
+      Id = Guid.NewGuid().ToString();
+    }
+
+    public VariableNetworkNode(VariableNetworkNode original, Cloner cloner) : base(original, cloner) {
+      Id = original.Id;
+      Description = original.Description;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new VariableNetworkNode(this, cloner);
+    }
+
+    public string Id { get; }
+    public string Description { get; set; }
+  }
+
+  [Item("FunctionNetworkNode", "A graph vertex representing a junction node.")]
+  [StorableClass]
+  public class JunctionNetworkNode : Vertex<IDeepCloneable>, INetworkNode {
+    public JunctionNetworkNode() {
+      Id = Guid.NewGuid().ToString();
+    }
+
+    public JunctionNetworkNode(JunctionNetworkNode original, Cloner cloner) : base(original, cloner) {
+      Id = original.Id;
+      Description = original.Description;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new JunctionNetworkNode(this, cloner);
+    }
+
+    public string Id { get; }
+    public string Description { get; set; }
+  }
+}
Index: /branches/2288_HeuristicLab.VariableInteractionNetworks/PreBuildEvent.cmd
===================================================================
--- /branches/2288_HeuristicLab.VariableInteractionNetworks/PreBuildEvent.cmd	(revision 15929)
+++ /branches/2288_HeuristicLab.VariableInteractionNetworks/PreBuildEvent.cmd	(revision 15929)
@@ -0,0 +1,11 @@
+IF EXIST "%ProjectDir%\Properties\AssemblyInfo.cs.frame" SubWCRev "%ProjectDir%\" "%ProjectDir%\Properties\AssemblyInfo.cs.frame" "%ProjectDir%\Properties\AssemblyInfo.cs"
+IF %ERRORLEVEL% NEQ 0 GOTO Error_Handling
+IF EXIST "%ProjectDir%\Plugin.cs.frame" SubWCRev "%ProjectDir%\" "%ProjectDir%\Plugin.cs.frame" "%ProjectDir%\Plugin.cs"
+IF %ERRORLEVEL% NEQ 0 GOTO Error_Handling
+GOTO Done
+
+:Error_Handling
+ECHO There was an error while running subwcrev. Please verify that the *.cs.frame files have been correctly converted to *.cs files, otherwise HeuristicLab won't build. 
+exit 0
+
+:Done
Index: /branches/2886_SymRegGrammarEnumeration/ExpressionClustering/ExpressionClustering.csproj
===================================================================
--- /branches/2886_SymRegGrammarEnumeration/ExpressionClustering/ExpressionClustering.csproj	(revision 15928)
+++ /branches/2886_SymRegGrammarEnumeration/ExpressionClustering/ExpressionClustering.csproj	(revision 15929)
@@ -71,5 +71,7 @@
       <HintPath>..\..\..\trunk\bin\HeuristicLab.Common-3.3.dll</HintPath>
     </Reference>
-    <Reference Include="HeuristicLab.Core-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec" />
+    <Reference Include="HeuristicLab.Core-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Core-3.3.dll</HintPath>
+    </Reference>
     <Reference Include="HeuristicLab.Core.Views-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
