Index: /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/PictureGenerator.cs
===================================================================
--- /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/PictureGenerator.cs	(revision 7316)
+++ /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/PictureGenerator.cs	(revision 7316)
@@ -0,0 +1,245 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Drawing;
+using System.Windows.Forms.DataVisualization.Charting;
+using System.IO;
+
+namespace VRPProblemAnalyzer {
+  public class PictureGenerator {
+    private static int TourSize = 1000;
+    private static double MinDemandSize = 2;
+    private static double MaxDemandSize = TourSize / 25.0;
+
+    private static int TourBorder = (int)Math.Ceiling(MaxDemandSize);
+
+    private static int ChartWidth = TourSize / 2;
+    private static int ChartHeight = 250;
+    
+    private static int DemandSegments = 10;
+
+    private static int DistanceSegments = 10;
+
+    public static Image GeneratePicture(TSPLIBParser problemInstance, SolutionParser solution) {    
+      Image tourVisualization = GenerateTourVisualization(problemInstance, solution);
+      Image demandDistribution = GenerateDemandDistribution(problemInstance);
+      Image distanceDistribution = GenerateDistanceDistribution(problemInstance);
+
+      Bitmap bmp = new Bitmap(Math.Max(TourSize, ChartWidth * 2), tourVisualization.Height + ChartHeight);
+      using (Graphics g = Graphics.FromImage(bmp)) {
+        g.FillRectangle(Brushes.White, 0, 0, bmp.Width, bmp.Height);
+        g.DrawImage(tourVisualization, 0, 0);
+        g.DrawImage(demandDistribution, 0, tourVisualization.Height);
+        g.DrawImage(distanceDistribution, ChartWidth, tourVisualization.Height); 
+      }
+      return bmp;
+    }
+
+    private static Image GenerateTourVisualization(TSPLIBParser problemInstance, SolutionParser solution) {
+      double[,] coordinates = problemInstance.Vertices;
+
+      double xMin = double.MaxValue, yMin = double.MaxValue, xMax = double.MinValue, yMax = double.MinValue;
+      for (int i = 0; i < coordinates.GetLength(0); i++) {
+        if (xMin > coordinates[i, 0]) xMin = coordinates[i, 0];
+        if (yMin > coordinates[i, 1]) yMin = coordinates[i, 1];
+        if (xMax < coordinates[i, 0]) xMax = coordinates[i, 0];
+        if (yMax < coordinates[i, 1]) yMax = coordinates[i, 1];
+      }
+      double xWidth = xMax - xMin;
+      double yHeight = yMax - yMin;
+
+      int width, height;
+      if (xWidth > yHeight) {
+        width = TourSize;
+        height = (int)Math.Round(TourSize * (yHeight / xWidth));
+      } else {
+        width = (int)Math.Round(TourSize * (xWidth / yHeight));
+        height = TourSize;
+      }
+      Bitmap bitmap = new Bitmap(width, height);
+
+      double xStep = (width - 2 * TourBorder) / xWidth;
+      double yStep = (height - 2 * TourBorder) / yHeight;
+
+      Pen[] pens = {new Pen(Color.FromArgb(100, 92,20,237)), new Pen(Color.FromArgb(100, 237,183,20)), new Pen(Color.FromArgb(100, 237,20,219)), new Pen(Color.FromArgb(100, 20,237,76)),
+                    new Pen(Color.FromArgb(100, 237,61,20)), new Pen(Color.FromArgb(100, 115,78,26)), new Pen(Color.FromArgb(100, 20,237,229)), new Pen(Color.FromArgb(100, 39,101,19)),
+                    new Pen(Color.FromArgb(100, 230,170,229)), new Pen(Color.FromArgb(100, 142,136,89)), new Pen(Color.FromArgb(100, 157,217,166)), new Pen(Color.FromArgb(100, 31,19,101)),
+                    new Pen(Color.FromArgb(100, 173,237,20)), new Pen(Color.FromArgb(100, 230,231,161)), new Pen(Color.FromArgb(100, 142,89,89)), new Pen(Color.FromArgb(100, 93,89,142)),
+                    new Pen(Color.FromArgb(100, 146,203,217)), new Pen(Color.FromArgb(100, 101,19,75)), new Pen(Color.FromArgb(100, 198,20,237)), new Pen(Color.FromArgb(100, 185,185,185)),
+                    new Pen(Color.FromArgb(100, 179,32,32)), new Pen(Color.FromArgb(100, 18,119,115)), new Pen(Color.FromArgb(100, 104,158,239)), new Pen(Color.Black)};
+
+      foreach (Pen pen in pens) {
+        pen.Width = 2;
+      }
+
+      using (Graphics graphics = Graphics.FromImage(bitmap)) {
+        graphics.FillRectangle(Brushes.White, 0, 0, width, height);
+
+        int currentTour = 0;
+        foreach (List<int> tour in solution.Routes) {
+          Point[] tourPoints = new Point[tour.Count + 2];
+          int[] customerSizes = new int[tour.Count];
+          int lastCustomer = 0;
+
+          for (int i = -1; i <= tour.Count; i++) {
+            int location = 0;
+
+            if (i == -1 || i == tour.Count)
+              location = 0; //depot
+            else
+              location = tour[i];
+
+            Point locationPoint = new Point(TourBorder + ((int)((coordinates[location, 0] - xMin) * xStep)),
+                            bitmap.Height - (TourBorder + ((int)((coordinates[location, 1] - yMin) * yStep))));
+            tourPoints[i + 1] = locationPoint;
+
+            if (i != -1 && i != tour.Count) {
+              customerSizes[i] = (int)Math.Round(MinDemandSize + problemInstance.Demands[location] / problemInstance.Capacity * (MaxDemandSize - MinDemandSize));
+            }
+            lastCustomer = location;
+          }
+
+          graphics.DrawPolygon(pens[((currentTour >= pens.Length) ? (pens.Length - 1) : (currentTour))], tourPoints);
+
+          using(Brush brush = new SolidBrush(Color.FromArgb(100, 0, 0, 0))) {
+            for (int i = 0; i < tour.Count; i++) {
+              int size = customerSizes[i];
+              graphics.FillEllipse(brush, tourPoints[i + 1].X - size, tourPoints[i + 1].Y - size, size * 2, size * 2);
+            }
+          }
+
+          graphics.FillRectangle(Brushes.Blue, tourPoints[0].X - 5, tourPoints[0].Y - 5, 10, 10);
+
+          currentTour++;
+        }
+      }
+
+      for (int i = 0; i < pens.Length; i++)
+        pens[i].Dispose();
+
+      return bitmap;
+    }
+
+    private static List<Tuple<double, int>> GetDemandDistribution(TSPLIBParser problemInstance) {
+      var result = new List<Tuple<double, int>>();
+
+      double step = problemInstance.Capacity / (double)DemandSegments;
+      double current = 0;
+
+      while(current < problemInstance.Capacity) {
+        int count = problemInstance.Demands.Where(d => d > current && d <= current + step).Count(); 
+        result.Add(new Tuple<double, int>(current + step / 2, count));
+        current += step;           
+      }
+     
+      return result;
+    }
+
+    private static Image GenerateDemandDistribution(TSPLIBParser problemInstance) {     
+      Chart chart = new Chart();
+      chart.Size = new Size(ChartWidth, ChartHeight);
+
+      chart.Titles.Add("Demand Distribution");
+      chart.ChartAreas.Add("");
+
+      chart.ChartAreas[0].BackColor = Color.White;
+
+      chart.ChartAreas[0].AxisX.Title = "Demand";
+      chart.ChartAreas[0].AxisX.Minimum = 0;
+      chart.ChartAreas[0].AxisX.Maximum = problemInstance.Capacity;
+      chart.ChartAreas[0].AxisX.Interval = problemInstance.Capacity / (double)DemandSegments;
+      chart.ChartAreas[0].AxisX.MajorGrid.Enabled = false;
+
+      chart.ChartAreas[0].AxisY.Title = "Customers";
+      chart.ChartAreas[0].AxisY.Minimum = 0;
+      chart.ChartAreas[0].AxisY.Maximum = problemInstance.Vertices.GetLength(0);
+      chart.ChartAreas[0].AxisY.MajorGrid.Enabled = true;
+      chart.ChartAreas[0].AxisY.MajorGrid.LineColor = Color.FromArgb(100, Color.Blue);
+
+      chart.Series.Add("");
+      chart.Series[0].ChartType = SeriesChartType.Column;
+
+      foreach (Tuple<double, int> entry in GetDemandDistribution(problemInstance)) {
+        chart.Series[0].Points.AddXY(entry.Item1, entry.Item2);
+      }
+
+      Image image;
+      using (var chartimage = new MemoryStream()) {
+        chart.SaveImage(chartimage, ChartImageFormat.Png);
+        image = Image.FromStream(chartimage);
+      }
+      return image;
+    }
+
+    private static double GetAverageDistance(int customer, double[,] vertices) {
+      double dist = 0;
+      int count = 0;
+
+      for (int i = 0; i < vertices.GetLength(0); i++) {
+        if (i != customer) {
+          dist += Utils.GetDistance(vertices, customer, i);
+          count++;
+        }
+      }
+
+      return dist / count;
+    }
+
+    private static List<Tuple<double, int>> GetDistanceDistribution(TSPLIBParser problemInstance) {
+      var result = new List<Tuple<double, int>>();
+
+      double step = 1.0 / (double)DistanceSegments;
+      double current = 0;
+
+      List<double> averageDistances = new List<double>();
+      for (int i = 0; i < problemInstance.Vertices.GetLength(0); i++) {
+        averageDistances.Add(GetAverageDistance(i, problemInstance.Vertices));
+      }
+
+        while (current < 1.0) {
+          int count = averageDistances.Where(d => d > current && d <= current + step).Count();
+          result.Add(new Tuple<double, int>(current + step / 2, count));
+          current += step;
+        }
+
+      return result;
+    }
+
+    private static Image GenerateDistanceDistribution(TSPLIBParser problemInstance) {
+      Chart chart = new Chart();
+      chart.Size = new Size(ChartWidth, ChartHeight);
+
+      chart.Titles.Add("Distance Distribution");
+      chart.ChartAreas.Add("");
+
+      chart.ChartAreas[0].BackColor = Color.White;
+
+      chart.ChartAreas[0].AxisX.Title = "Distance";
+      chart.ChartAreas[0].AxisX.Minimum = 0;
+      chart.ChartAreas[0].AxisX.Maximum = 1;
+      chart.ChartAreas[0].AxisX.Interval = 1.0 / (double)DistanceSegments;
+      chart.ChartAreas[0].AxisX.MajorGrid.Enabled = false;
+
+      chart.ChartAreas[0].AxisY.Title = "Customers";
+      chart.ChartAreas[0].AxisY.Minimum = 0;
+      chart.ChartAreas[0].AxisY.Maximum = problemInstance.Vertices.GetLength(0);
+      chart.ChartAreas[0].AxisY.MajorGrid.Enabled = true;
+      chart.ChartAreas[0].AxisY.MajorGrid.LineColor = Color.FromArgb(100, Color.Blue);
+
+      chart.Series.Add("");
+      chart.Series[0].ChartType = SeriesChartType.Column;
+
+      foreach (Tuple<double, int> entry in GetDistanceDistribution(problemInstance)) {
+        chart.Series[0].Points.AddXY(entry.Item1, entry.Item2);
+      }
+
+      Image image;
+      using (var chartimage = new MemoryStream()) {
+        chart.SaveImage(chartimage, ChartImageFormat.Png);
+        image = Image.FromStream(chartimage);
+      }
+      return image;
+    }
+  }
+}
Index: /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/Program.cs
===================================================================
--- /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/Program.cs	(revision 7315)
+++ /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/Program.cs	(revision 7316)
@@ -5,14 +5,9 @@
 using System.Text;
 using System.IO;
+using System.Drawing;
 
 namespace VRPProblemAnalyzer {
   
   public class Program {
-
-    private static double GetDistance(double[,] vertices, int source, int target) {
-      return Math.Sqrt(
-        Math.Pow((vertices[source, 0] - vertices[target, 0]), 2) + 
-        Math.Pow((vertices[source, 1] - vertices[target, 1]), 2));
-    }
 
     private static double[] GetDistances(double[,] vertices) {
@@ -23,5 +18,5 @@
         for (int j = 0; j < cities; j++) {
           if (i != j) {
-            result.Add(GetDistance(vertices, i, j));
+            result.Add(Utils.GetDistance(vertices, i, j));
           }
         }
@@ -39,5 +34,5 @@
         for (int j = 0; j < cities; j++) {
           if (i != j) {
-            distance += GetDistance(vertices, i, j);
+            distance += Utils.GetDistance(vertices, i, j);
           }
         }
@@ -187,4 +182,5 @@
           instance.Demands[i] = instance.Demands[i] / instance.Capacity;
       }
+      instance.Capacity = 1.0;
 
       //normalize coordinates
@@ -199,5 +195,4 @@
       var factor = Math.Sqrt(0.5)/Math.Max(rangeX, rangeY);
 
-
       for (int i = 0; i < instance.Vertices.GetLength(0); i++) {
         instance.Vertices[i, 0] = (cities[i].X-minX)*factor;
@@ -221,5 +216,11 @@
           Normalize(parser);
 
-          sw.Write(Path.GetFileNameWithoutExtension(instance));
+          string instanceName = Path.GetFileNameWithoutExtension(instance);
+
+          string solutionName = Path.Combine(Path.GetDirectoryName(instance), Path.GetFileNameWithoutExtension(instance) + ".opt");
+          SolutionParser solution = new SolutionParser(solutionName);
+          solution.Parse();
+
+          sw.Write(instanceName);
           sw.Write(';');
           sw.Write(parser.Vertices.Length / 2 - 1);
@@ -242,8 +243,12 @@
           sw.Write(';');
           sw.WriteLine();
-        }
-      }
-      Console.WriteLine("Done. Press Enter...");
-      Console.ReadLine();
+
+
+          Image picture = PictureGenerator.GeneratePicture(parser, solution);
+          picture.Save(Path.Combine(path, instanceName + ".png"));
+        }
+      }
+      //Console.WriteLine("Done. Press Enter...");
+      //Console.ReadLine();
     }
   }
Index: /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/SolutionParser.cs
===================================================================
--- /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/SolutionParser.cs	(revision 7316)
+++ /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/SolutionParser.cs	(revision 7316)
@@ -0,0 +1,63 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.IO;
+
+namespace VRPProblemAnalyzer {
+  public class SolutionParser {
+    private string file;
+
+    private List<List<int>> routes;
+
+    public List<List<int>> Routes {
+      get {
+        return routes;
+      }
+    }
+
+    public SolutionParser(string file) {
+      this.file = file;
+      this.routes = new List<List<int>>();
+    }
+
+    public void Parse() {
+      this.routes.Clear();
+      using (StreamReader reader = new StreamReader(file)) {
+        String line;
+        while ((line = reader.ReadLine()) != null) {
+          string[] token = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
+
+          if (token.Length > 2) {
+            List<int> route = new List<int>();
+
+            for (int i = 2; i < token.Length; i++) {
+              route.Add(int.Parse(token[i]));
+            }
+
+            routes.Add(route);
+          }
+        }
+      }
+    }
+  }
+}
Index: /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/TSPLIBParser.cs
===================================================================
--- /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/TSPLIBParser.cs	(revision 7315)
+++ /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/TSPLIBParser.cs	(revision 7316)
@@ -89,4 +89,7 @@
       get {
         return capacity;
+      }
+      set {
+        capacity = value;
       }
     }
Index: /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/Utils.cs
===================================================================
--- /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/Utils.cs	(revision 7315)
+++ /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/Utils.cs	(revision 7316)
@@ -15,4 +15,10 @@
       return points;
     }
+
+    public static double GetDistance(double[,] vertices, int source, int target) {
+      return Math.Sqrt(
+        Math.Pow((vertices[source, 0] - vertices[target, 0]), 2) +
+        Math.Pow((vertices[source, 1] - vertices[target, 1]), 2));
+    }
   }
 }
Index: /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/VRPProblemAnalyzer.csproj
===================================================================
--- /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/VRPProblemAnalyzer.csproj	(revision 7315)
+++ /branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/VRPProblemAnalyzer.csproj	(revision 7316)
@@ -104,4 +104,7 @@
     <Reference Include="System" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Windows.Forms.DataVisualization" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
@@ -112,4 +115,5 @@
   <ItemGroup>
     <Compile Include="EnumerableExtensions.cs" />
+    <Compile Include="PictureGenerator.cs" />
     <Compile Include="PointD.cs" />
     <Compile Include="DepotExcentricityCalculator.cs" />
@@ -117,4 +121,5 @@
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SolutionParser.cs" />
     <Compile Include="TSPLIBParser.cs" />
     <Compile Include="Utils.cs" />
