Index: /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/HeuristicLab.Problems.TravelingSalesman-3.3.csproj
===================================================================
--- /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/HeuristicLab.Problems.TravelingSalesman-3.3.csproj	(revision 17238)
+++ /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/HeuristicLab.Problems.TravelingSalesman-3.3.csproj	(revision 17239)
@@ -156,4 +156,6 @@
     <Compile Include="MoveEvaluators\TSPMoveEvaluator.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TSP.cs" />
+    <Compile Include="TSPData.cs" />
   </ItemGroup>
   <ItemGroup>
Index: /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TSP.cs
===================================================================
--- /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TSP.cs	(revision 17239)
+++ /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TSP.cs	(revision 17239)
@@ -0,0 +1,131 @@
+﻿using System;
+using HEAL.Attic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.Instances;
+
+namespace HeuristicLab.Problems.TravelingSalesman {
+  [Item("Traveling Salesman Problem (TSP)", "Represents a symmetric Traveling Salesman Problem.")]
+  [Creatable(CreatableAttribute.Categories.CombinatorialProblems, Priority = 100)]
+  [StorableType("60511a03-b8b4-47cd-a119-78f97358a6b0")]
+  public class TSP : SingleObjectiveProblem<PermutationEncoding, Permutation>, IProblemInstanceConsumer<TSPData> {
+    public static int DistanceMatrixSizeLimit { get; set; } = 1000;
+
+    public override bool Maximization => false;
+
+    [Storable]
+    private IValueParameter<ITSPData> tspDataParameter;
+    public IValueParameter<ITSPData> TSPDataParameter {
+      get { return tspDataParameter; }
+    }
+    [Storable]
+    private IValueParameter<Permutation> bestKnownSolutionParameter;
+    public IValueParameter<Permutation> BestKnownSolutionParameter {
+      get { return bestKnownSolutionParameter; }
+    }
+
+    public ITSPData TSPData {
+      get { return tspDataParameter.Value; }
+      set { tspDataParameter.Value = value; }
+    }
+    public Permutation BestKnownSolution {
+      get { return bestKnownSolutionParameter.Value; }
+      set { bestKnownSolutionParameter.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected TSP(StorableConstructorFlag _) : base(_) { }
+
+    protected TSP(TSP original, Cloner cloner)
+      : base(original, cloner) {
+      tspDataParameter = cloner.Clone(original.tspDataParameter);
+      bestKnownSolutionParameter = cloner.Clone(original.bestKnownSolutionParameter);
+    }
+
+    public TSP() : base(new PermutationEncoding("Tour", 16, PermutationTypes.RelativeUndirected)) {
+      TSPData = new RoundedEuclideanCoordinatesTSPData() {
+        Coordinates = new DoubleMatrix(new double[,] {
+        { 100, 100 }, { 100, 200 }, { 100, 300 }, { 100, 400 },
+        { 200, 100 }, { 200, 200 }, { 200, 300 }, { 200, 400 },
+        { 300, 100 }, { 300, 200 }, { 300, 300 }, { 300, 400 },
+        { 400, 100 }, { 400, 200 }, { 400, 300 }, { 400, 400 }
+        })
+      };
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TSP(this, cloner);
+    }
+
+    public override double Evaluate(Permutation tour, IRandom random) {
+      return Evaluate(tour);
+    }
+
+    public double Evaluate(Permutation tour) {
+      var tourLength = 0.0;
+      for (var i = 0; i < tour.Length - 1; i++) {
+        tourLength += TSPData.GetDistance(tour[i], tour[i + 1]);
+      }
+      tourLength += TSPData.GetDistance(tour[tour.Length - 1], tour[0]);
+      return tourLength;
+    }
+
+    public void Load(TSPData data) {
+      if (data.Coordinates == null && data.Distances == null)
+        throw new System.IO.InvalidDataException("The given instance specifies neither coordinates nor distances!");
+      if (data.Dimension > DistanceMatrixSizeLimit && (data.DistanceMeasure == DistanceMeasure.Att
+        || data.DistanceMeasure == DistanceMeasure.Manhattan
+        || data.DistanceMeasure == DistanceMeasure.Maximum))
+        throw new System.IO.InvalidDataException("The given instance uses an unsupported distance measure and is too large for using a distance matrix.");
+      if (data.Coordinates != null && data.Coordinates.GetLength(1) != 2)
+        throw new System.IO.InvalidDataException("The coordinates of the given instance are not in the right format, there need to be one row for each customer and two columns for the x and y coordinates.");
+
+      Name = data.Name;
+      Description = data.Description;
+
+      if (data.DistanceMeasure == DistanceMeasure.Att
+        || data.DistanceMeasure == DistanceMeasure.Manhattan
+        || data.DistanceMeasure == DistanceMeasure.Maximum
+        || data.Dimension <= DistanceMatrixSizeLimit) {
+        TSPData = new MatrixTSPData(data.GetDistanceMatrix(), data.Coordinates);
+      } else if (data.DistanceMeasure == DistanceMeasure.Direct && data.Distances != null) {
+        TSPData = new MatrixTSPData(data.Distances, data.Coordinates);
+      } else {
+        switch (data.DistanceMeasure) {
+          case DistanceMeasure.Euclidean:
+            throw new NotImplementedException();
+            break;
+          case DistanceMeasure.RoundedEuclidean:
+            TSPData = new RoundedEuclideanCoordinatesTSPData(data.Coordinates);
+            break;
+          case DistanceMeasure.UpperEuclidean:
+            throw new NotImplementedException();
+            break;
+          case DistanceMeasure.Geo:
+            throw new NotImplementedException();
+            break;
+          default:
+            throw new System.IO.InvalidDataException("An unknown distance measure is given in the instance!");
+        }
+      }
+      BestKnownSolution = null;
+      BestKnownQuality = double.NaN;
+
+      if (data.BestKnownTour != null) {
+        try {
+          BestKnownSolution = new Permutation(PermutationTypes.RelativeUndirected, data.BestKnownTour);
+          BestKnownQuality = Evaluate(BestKnownSolution);
+        } catch (InvalidOperationException) {
+          if (data.BestKnownQuality.HasValue)
+            BestKnownQuality = data.BestKnownQuality.Value;
+        }
+      } else if (data.BestKnownQuality.HasValue) {
+        BestKnownQuality = data.BestKnownQuality.Value;
+      }
+      OnReset();
+    }
+  }
+}
Index: /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TSPData.cs
===================================================================
--- /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TSPData.cs	(revision 17239)
+++ /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TSPData.cs	(revision 17239)
@@ -0,0 +1,113 @@
+﻿using System;
+using HEAL.Attic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+
+namespace HeuristicLab.Problems.TravelingSalesman {
+  [StorableType("1a9bf60c-b6a6-4c95-8e99-5a2dec0ee892")]
+  public interface ITSPData : IItem {
+    double GetDistance(int fromCity, int toCity);
+  }
+
+  [Item("Coordinates-based TSP Data", "TSP that is represented by coordinates of cities.")]
+  [StorableType("3955d07a-d43c-4a01-9505-d2effb1ea865")]
+  public abstract class CoordinatesTSPData : Item, ITSPData {
+    [Storable]
+    public DoubleMatrix Coordinates { get; set; }
+
+    [StorableConstructor]
+    protected CoordinatesTSPData(StorableConstructorFlag _) : base(_) { }
+    protected CoordinatesTSPData(CoordinatesTSPData original, Cloner cloner) : base(original, cloner) {
+      Coordinates = cloner.Clone(original.Coordinates);
+    }
+    protected CoordinatesTSPData() : base() {
+      Coordinates = new DoubleMatrix();
+    }
+    protected CoordinatesTSPData(double[,] coordinates) : base() {
+      if (coordinates == null) throw new ArgumentNullException(nameof(coordinates));
+      if (coordinates.GetLength(1) != 2) throw new ArgumentException("Argument must have exactly two columns.", nameof(coordinates));
+      Coordinates = new DoubleMatrix(coordinates);
+    }
+
+    public double GetDistance(int fromCity, int toCity) {
+      return GetDistance(Coordinates[fromCity, 0], Coordinates[fromCity, 1],
+        Coordinates[toCity, 0], Coordinates[toCity, 1]);
+    }
+
+    public abstract double GetDistance(double fromX, double fromY, double toX, double toY);
+  }
+
+  [Item("Euclidean (rounded) TSP Data", "TSP that is represented by coordinates and a rounded euclidean distance measure.")]
+  [StorableType("4bf58348-cd98-46c5-a4c0-55f486ca88b4")]
+  public sealed class RoundedEuclideanCoordinatesTSPData : CoordinatesTSPData {
+
+    [StorableConstructor]
+    private RoundedEuclideanCoordinatesTSPData(StorableConstructorFlag _) : base(_) { }
+    private RoundedEuclideanCoordinatesTSPData(RoundedEuclideanCoordinatesTSPData original, Cloner cloner) : base(original, cloner) { }
+    public RoundedEuclideanCoordinatesTSPData() : base() { }
+    public RoundedEuclideanCoordinatesTSPData(double[,] coordinates) : base(coordinates) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RoundedEuclideanCoordinatesTSPData(this, cloner);
+    }
+
+    public override double GetDistance(double fromX, double fromY, double toX, double toY) {
+      return Math.Round(Math.Sqrt((fromX - toX) * (fromX - toX) + (fromY - toY) * (fromY - toY)));
+    }
+  }
+
+  [Item("Matrix-based TSP Data", "TSP that is representd by a distance matrix.")]
+  [StorableType("4df58a35-679d-4414-b815-9450ae100823")]
+  public class MatrixTSPData : Item, ITSPData {
+    [Storable]
+    private double[,] Matrix { get; set; }
+
+    [Storable]
+    public DoubleMatrix DisplayCoordinates { get; set; }
+
+    [StorableConstructor]
+    protected MatrixTSPData(StorableConstructorFlag _) : base(_) { }
+    protected MatrixTSPData(MatrixTSPData original, Cloner cloner) : base(original, cloner) {
+      Matrix = original.Matrix;
+      DisplayCoordinates = cloner.Clone(original.DisplayCoordinates);
+    }
+    public MatrixTSPData() {
+      Matrix = new double[0, 0];
+      DisplayCoordinates = null;
+    }
+    public MatrixTSPData(double[,] matrix, double[,] coordinates = null) {
+      Matrix = (double[,])matrix.Clone();
+      if (coordinates != null) DisplayCoordinates = new DoubleMatrix(coordinates);
+      if (DisplayCoordinates != null && DisplayCoordinates.Columns != 2)
+        throw new ArgumentException("Argument must have exactly two columns.", nameof(coordinates));
+      if (DisplayCoordinates != null && DisplayCoordinates.Rows != Matrix.GetLength(0))
+        throw new ArgumentException("Unequal number of rows in " + nameof(matrix) + " and " + nameof(coordinates) + ".");
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MatrixTSPData(this, cloner);
+    }
+
+    public void SetMatrix(double[,] matrix, double[,] coordinates = null) {
+      Matrix = (double[,])matrix.Clone();
+      if (coordinates == null) DisplayCoordinates = null;
+      else DisplayCoordinates = new DoubleMatrix(coordinates);
+      if (DisplayCoordinates != null && DisplayCoordinates.Columns != 2)
+        throw new ArgumentException("Argument must have exactly two columns.", nameof(coordinates));
+      if (DisplayCoordinates != null && DisplayCoordinates.Rows != Matrix.GetLength(0))
+        throw new ArgumentException("Unequal number of rows in " + nameof(matrix) + " and " + nameof(coordinates) + ".");
+    }
+
+    public void SetMatrix(ValueTypeMatrix<double> matrix, DoubleMatrix coordinates = null) {
+      Matrix = matrix.CloneAsMatrix();
+      DisplayCoordinates = (DoubleMatrix)coordinates?.Clone();
+      if (DisplayCoordinates != null && DisplayCoordinates.Columns != 2)
+        throw new ArgumentException("Argument must have exactly two columns.", nameof(coordinates));
+      if (DisplayCoordinates != null && DisplayCoordinates.Rows != Matrix.GetLength(0))
+        throw new ArgumentException("Unequal number of rows in " + nameof(matrix) + " and " + nameof(coordinates) + ".");
+    }
+
+    public double GetDistance(int fromCity, int toCity) => Matrix[fromCity, toCity];
+  }
+}
Index: /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TravelingSalesmanProblem.cs
===================================================================
--- /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TravelingSalesmanProblem.cs	(revision 17238)
+++ /branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TravelingSalesmanProblem.cs	(revision 17239)
@@ -38,5 +38,4 @@
 namespace HeuristicLab.Problems.TravelingSalesman {
   [Item("Traveling Salesman Problem (TSP)", "Represents a symmetric Traveling Salesman Problem.")]
-  [Creatable(CreatableAttribute.Categories.CombinatorialProblems, Priority = 100)]
   [StorableType("F0A3550C-2B8F-497D-BF32-5763F8D7592C")]
   public sealed class TravelingSalesmanProblem : SingleObjectiveHeuristicOptimizationProblem<ITSPEvaluator, IPermutationCreator>,
