Index: /branches/VRP/HeuristicLab.Problems.VehicleRouting.Views/3.3/VehicleRoutingProblemView.Designer.cs
===================================================================
--- /branches/VRP/HeuristicLab.Problems.VehicleRouting.Views/3.3/VehicleRoutingProblemView.Designer.cs	(revision 4231)
+++ /branches/VRP/HeuristicLab.Problems.VehicleRouting.Views/3.3/VehicleRoutingProblemView.Designer.cs	(revision 4232)
@@ -30,4 +30,5 @@
       this.tabPage2 = new System.Windows.Forms.TabPage();
       this.vrpSolutionView = new HeuristicLab.Problems.VehicleRouting.Views.VRPSolutionView();
+      this.importButton2 = new System.Windows.Forms.Button();
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
       this.tabControl1.SuspendLayout();
@@ -60,8 +61,8 @@
       this.tabControl1.Controls.Add(this.tabPage1);
       this.tabControl1.Controls.Add(this.tabPage2);
-      this.tabControl1.Location = new System.Drawing.Point(0, 84);
+      this.tabControl1.Location = new System.Drawing.Point(0, 109);
       this.tabControl1.Name = "tabControl1";
       this.tabControl1.SelectedIndex = 0;
-      this.tabControl1.Size = new System.Drawing.Size(490, 338);
+      this.tabControl1.Size = new System.Drawing.Size(490, 313);
       this.tabControl1.TabIndex = 6;
       // 
@@ -72,5 +73,5 @@
       this.tabPage1.Name = "tabPage1";
       this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
-      this.tabPage1.Size = new System.Drawing.Size(482, 312);
+      this.tabPage1.Size = new System.Drawing.Size(482, 287);
       this.tabPage1.TabIndex = 0;
       this.tabPage1.Text = "Parameters";
@@ -85,5 +86,5 @@
       this.parameterCollectionView.Name = "parameterCollectionView";
       this.parameterCollectionView.ReadOnly = false;
-      this.parameterCollectionView.Size = new System.Drawing.Size(476, 306);
+      this.parameterCollectionView.Size = new System.Drawing.Size(476, 281);
       this.parameterCollectionView.TabIndex = 1;
       // 
@@ -94,5 +95,5 @@
       this.tabPage2.Name = "tabPage2";
       this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
-      this.tabPage2.Size = new System.Drawing.Size(482, 312);
+      this.tabPage2.Size = new System.Drawing.Size(482, 287);
       this.tabPage2.TabIndex = 1;
       this.tabPage2.Text = "Visualization";
@@ -110,7 +111,20 @@
       this.vrpSolutionView.TabIndex = 0;
       // 
+      // importButton2
+      // 
+      this.importButton2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                  | System.Windows.Forms.AnchorStyles.Right)));
+      this.importButton2.Location = new System.Drawing.Point(0, 81);
+      this.importButton2.Name = "importButton2";
+      this.importButton2.Size = new System.Drawing.Size(490, 23);
+      this.importButton2.TabIndex = 7;
+      this.importButton2.Text = "Import from TSPLib";
+      this.importButton2.UseVisualStyleBackColor = true;
+      this.importButton2.Click += new System.EventHandler(this.importButton2_Click);
+      // 
       // VehicleRoutingProblemView
       // 
       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.Controls.Add(this.importButton2);
       this.Controls.Add(this.importButton);
       this.Controls.Add(this.tabControl1);
@@ -123,4 +137,5 @@
       this.Controls.SetChildIndex(this.descriptionLabel, 0);
       this.Controls.SetChildIndex(this.descriptionTextBox, 0);
+      this.Controls.SetChildIndex(this.importButton2, 0);
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
       this.tabControl1.ResumeLayout(false);
@@ -140,4 +155,5 @@
     private Core.Views.ParameterCollectionView parameterCollectionView;
     private VRPSolutionView vrpSolutionView;
+    private System.Windows.Forms.Button importButton2;
   }
 }
Index: /branches/VRP/HeuristicLab.Problems.VehicleRouting.Views/3.3/VehicleRoutingProblemView.cs
===================================================================
--- /branches/VRP/HeuristicLab.Problems.VehicleRouting.Views/3.3/VehicleRoutingProblemView.cs	(revision 4231)
+++ /branches/VRP/HeuristicLab.Problems.VehicleRouting.Views/3.3/VehicleRoutingProblemView.cs	(revision 4232)
@@ -64,5 +64,5 @@
       parameterCollectionView.Enabled = Content != null;
       vrpSolutionView.Enabled = Content != null;
-      importButton.Enabled = Content != null && !ReadOnly;
+      importButton.Enabled = importButton2.Enabled = Content != null && !ReadOnly;
     }
 
@@ -76,7 +76,16 @@
     }
 
+    private void importButton2_Click(object sender, EventArgs e) {
+      OpenFileDialog dialog = new OpenFileDialog();
+      dialog.DefaultExt = "vrp";
+
+      if (dialog.ShowDialog() == DialogResult.OK) {
+        Content.ImportFromTSPLib(dialog.FileName);
+      }
+    }
+
     private void CoordinatesParameter_ValueChanged(object sender, EventArgs e) {
       vrpSolutionView.Content.Coordinates = Content.Coordinates;
-    }
+    }    
   }
 }
Index: /branches/VRP/HeuristicLab.Problems.VehicleRouting/3.3/HeuristicLab.Problems.VehicleRouting-3.3.csproj
===================================================================
--- /branches/VRP/HeuristicLab.Problems.VehicleRouting/3.3/HeuristicLab.Problems.VehicleRouting-3.3.csproj	(revision 4231)
+++ /branches/VRP/HeuristicLab.Problems.VehicleRouting/3.3/HeuristicLab.Problems.VehicleRouting-3.3.csproj	(revision 4232)
@@ -156,4 +156,5 @@
     <Compile Include="Encodings\Potvin\Manipulators\PotvinManipulator.cs" />
     <Compile Include="Interfaces\IVRPMoveMaker.cs" />
+    <Compile Include="TSPLIBParser.cs" />
     <Compile Include="VRPUtilities.cs" />
     <Compile Include="VRPOperator.cs" />
Index: /branches/VRP/HeuristicLab.Problems.VehicleRouting/3.3/TSPLIBParser.cs
===================================================================
--- /branches/VRP/HeuristicLab.Problems.VehicleRouting/3.3/TSPLIBParser.cs	(revision 4232)
+++ /branches/VRP/HeuristicLab.Problems.VehicleRouting/3.3/TSPLIBParser.cs	(revision 4232)
@@ -0,0 +1,312 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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.Globalization;
+using System.IO;
+
+namespace HeuristicLab.Problems.VehicleRouting {
+  /// <summary>
+  /// Parses a *.tsp file in TSPLIB format and extracts its information about a TSP.
+  /// </summary>
+  public class TSPLIBParser {
+    #region Inner Enum TSPLIBEdgeWeightType
+    public enum TSPLIBEdgeWeightType {
+      UNDEFINED,
+      EUC_2D,
+      GEO
+    }
+    #endregion
+
+    private const int EOF = 0;
+    private const int NAME = 1;
+    private const int TYPE = 2;
+    private const int COMMENT = 3;
+    private const int DIM = 4;
+    private const int WEIGHTTYPE = 5;
+    private const int NODETYPE = 6;
+    private const int NODESECTION = 7;
+    private const int CAPACITY = 8;
+    private const int DEPOTSECTION = 9;
+    private const int DEMANDSECTION = 10;
+
+    private StreamReader source;
+
+    private string name;
+    /// <summary>
+    /// Gets the name of the parsed TSP.
+    /// </summary>
+    public string Name {
+      get { return name; }
+    }
+    private string comment;
+    /// <summary>
+    /// Gets the comment of the parsed TSP.
+    /// </summary>
+    public string Comment {
+      get { return comment; }
+    }
+    private double[,] vertices;
+    /// <summary>
+    /// Gets the vertices of the parsed TSP.
+    /// </summary>
+    public double[,] Vertices {
+      get { return vertices; }
+    }
+    private TSPLIBEdgeWeightType weightType;
+    /// <summary>
+    /// Gets the weight type of the parsed TSP.
+    /// </summary>
+    public TSPLIBEdgeWeightType WeightType {
+      get { return weightType; }
+    }
+
+    private double capacity;
+    public double Capacity {
+      get {
+        return capacity;
+      }
+    }
+
+    private int depot;
+    public int Depot {
+      get {
+        return depot;
+      }
+    }
+
+    private double[] demands;
+    public double[] Demands {
+      get {
+        return demands;
+      }
+    }
+
+    /// <summary>
+    /// Initializes a new instance of <see cref="TSPLIBParser"/> with the given <paramref name="path"/>.
+    /// </summary>
+    /// <exception cref="ArgumentException">Thrown if the input file is not a TSPLIB TSP file (*.tsp)
+    /// </exception>
+    /// <param name="path">The path where the TSP is stored.</param>
+    public TSPLIBParser(String path) {
+      if (!path.EndsWith(".vrp"))
+        throw new ArgumentException("Input file has to be a TSPLIB CVRP file (*.tsp).");
+
+      source = new StreamReader(path);
+      name = path;
+      comment = string.Empty;
+      vertices = null;
+      weightType = TSPLIBEdgeWeightType.UNDEFINED;
+      capacity = -1;
+      depot = -1;
+      demands = null;
+    }
+
+    /// <summary>
+    /// Reads the TSPLIB TSP file and parses the elements.
+    /// </summary>
+    /// <exception cref="InvalidDataException">Thrown if the file has an invalid format or contains invalid data.</exception>
+    public void Parse() {
+      int section = -1;
+      string str = null;
+      bool typeIsChecked = false;
+      bool weightTypeIsChecked = false;
+
+      do {
+        str = source.ReadLine();
+        section = GetSection(str);
+
+        if (section != -1) {
+          switch (section) {
+            case NAME:
+              ReadName(str);
+              break;
+            case TYPE:
+              CheckType(str);
+              typeIsChecked = true;
+              break;
+            case COMMENT:
+              ReadComment(str);
+              break;
+            case DIM:
+              InitArrays(str);
+              break;
+            case WEIGHTTYPE:
+              ReadWeightType(str);
+              weightTypeIsChecked = true;
+              break;
+            case NODETYPE:
+              CheckNodeType(str);
+              break;
+            case NODESECTION:
+              ReadVertices();
+              break;
+            case CAPACITY:
+              ReadCapacity(str);
+              break;
+            case DEPOTSECTION:
+              ReadDepot();
+              break;
+            case DEMANDSECTION:
+              ReadDemands();
+              break;
+          }
+        }
+      } while (!((section == EOF) || (str == null)));
+
+      if (!(typeIsChecked && weightTypeIsChecked))
+        throw new InvalidDataException("Input file does not contain type or edge weight type information.");
+    }
+
+    private int GetSection(string str) {
+      if (str == null)
+        return EOF;
+
+      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
+      if (tokens.Length == 0)
+        return -1;
+
+      string token = tokens[0].Trim();
+      if (token.Equals("eof", StringComparison.OrdinalIgnoreCase))
+        return EOF;
+      if (token.Equals("name", StringComparison.OrdinalIgnoreCase))
+        return NAME;
+      if (token.Equals("type", StringComparison.OrdinalIgnoreCase))
+        return TYPE;
+      if (token.Equals("comment", StringComparison.OrdinalIgnoreCase))
+        return COMMENT;
+      if (token.Equals("dimension", StringComparison.OrdinalIgnoreCase))
+        return DIM;
+      if (token.Equals("edge_weight_type", StringComparison.OrdinalIgnoreCase))
+        return WEIGHTTYPE;
+      if (token.Equals("node_coord_type", StringComparison.OrdinalIgnoreCase))
+        return NODETYPE;
+      if (token.Equals("node_coord_section", StringComparison.OrdinalIgnoreCase))
+        return NODESECTION;
+      if (token.Equals("capacity", StringComparison.OrdinalIgnoreCase))
+        return CAPACITY;
+      if (token.Equals("depot_section", StringComparison.OrdinalIgnoreCase))
+        return DEPOTSECTION;
+      if (token.Equals("demand_section", StringComparison.OrdinalIgnoreCase))
+        return DEMANDSECTION;
+
+      return -1;
+    }
+
+    private void ReadName(string str) {
+      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
+      name = tokens[tokens.Length - 1].Trim();
+    }
+
+    private void CheckType(string str) {
+      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
+
+      string type = tokens[tokens.Length - 1].Trim();
+      if (!type.Equals("cvrp", StringComparison.OrdinalIgnoreCase))
+        throw new InvalidDataException("Input file type is not \"CVRP\"");
+    }
+
+    private void ReadComment(string str) {
+      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
+      comment = tokens[tokens.Length - 1].Trim();
+    }
+
+    private void InitArrays(string str) {
+      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
+      string dimension = tokens[tokens.Length - 1].Trim();
+
+      int dim = Int32.Parse(dimension);
+      vertices = new double[dim, 2];
+      demands = new double[dim];
+    }
+
+    private void ReadWeightType(string str) {
+      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
+      string type = tokens[tokens.Length - 1].Trim();
+
+      if (type.Equals("euc_2d", StringComparison.OrdinalIgnoreCase))
+        weightType = TSPLIBEdgeWeightType.EUC_2D;
+      else if (type.Equals("geo", StringComparison.OrdinalIgnoreCase))
+        weightType = TSPLIBEdgeWeightType.GEO;
+      else
+        throw new InvalidDataException("Input file contains an unsupported edge weight type (only \"EUC_2D\" and \"GEO\" are supported).");
+    }
+
+    private void CheckNodeType(string str) {
+      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
+      string type = tokens[tokens.Length - 1].Trim();
+
+      if (!type.Equals("twod_coords", StringComparison.OrdinalIgnoreCase))
+        throw new InvalidDataException("Input file contains an unsupported node coordinates type (only \"TWOD_COORDS\" is supported).");
+    }
+
+    private void ReadVertices() {
+      if (vertices == null)
+        throw new InvalidDataException("Input file does not contain dimension information.");
+
+      for (int i = 0; i < (vertices.Length / 2); i++) {
+        string str = source.ReadLine();
+        string[] tokens = str.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
+
+        if (tokens.Length != 3)
+          throw new InvalidDataException("Input file contains invalid node coordinates.");
+
+        CultureInfo culture = new CultureInfo("en-US");
+        vertices[i, 0] = double.Parse(tokens[1], culture.NumberFormat);
+        vertices[i, 1] = double.Parse(tokens[2], culture.NumberFormat);
+      }
+    }
+
+    private void ReadCapacity(string str) {
+      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
+      capacity = double.Parse(tokens[tokens.Length - 1].Trim());
+    }
+
+    private void ReadDepot() {
+      int read;
+
+      do {
+        string str = source.ReadLine();
+        read = int.Parse(str);
+        if (read != -1)
+          depot = read;
+      } while (read != -1);
+    }
+
+    private void ReadDemands() {
+      if (demands == null)
+        throw new InvalidDataException("Input file does not contain dimension information.");
+
+      for (int i = 0; i < demands.Length; i++) {
+        string str = source.ReadLine();
+        string[] tokens = str.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
+
+        if (tokens.Length != 2)
+          throw new InvalidDataException("Input file contains invalid demands.");
+
+        int index = int.Parse(tokens[0]);
+        double value = double.Parse(tokens[1]);
+
+        demands[index - 1] = value;
+      }
+    }
+  }
+}
Index: /branches/VRP/HeuristicLab.Problems.VehicleRouting/3.3/VehicleRoutingProblem.cs
===================================================================
--- /branches/VRP/HeuristicLab.Problems.VehicleRouting/3.3/VehicleRoutingProblem.cs	(revision 4231)
+++ /branches/VRP/HeuristicLab.Problems.VehicleRouting/3.3/VehicleRoutingProblem.cs	(revision 4232)
@@ -431,4 +431,35 @@
     }
 
+    public void ImportFromTSPLib(string tspFileName) {
+      TSPLIBParser parser = new TSPLIBParser(tspFileName);
+      parser.Parse();
+
+      this.Name = parser.Name;
+
+      int problemSize = parser.Demands.Length;
+
+      Coordinates = new DoubleMatrix(parser.Vertices);
+      Vehicles.Value = problemSize - 1;
+      Capacity.Value = parser.Capacity;
+      Demand = new DoubleArray(parser.Demands);
+      ReadyTime = new DoubleArray(problemSize);
+      DueTime = new DoubleArray(problemSize);
+      ServiceTime = new DoubleArray(problemSize);
+
+      for (int i = 0; i < problemSize; i++) {
+        ReadyTime[i] = 0;
+        DueTime[i] = int.MaxValue;
+        ServiceTime[i] = 0;
+      }
+
+      if (parser.Depot != 1)
+        throw new Exception("Invalid depot specification");
+
+      if (parser.WeightType != TSPLIBParser.TSPLIBEdgeWeightType.EUC_2D)
+        throw new Exception("Invalid weight type");
+
+      OnReset();
+    }
+
     private void InitializeRandomVRPInstance() {
       System.Random rand = new System.Random();
