1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using System.IO;
|
---|
4 | using System.IO.Compression;
|
---|
5 | using System.Linq;
|
---|
6 | using HeuristicLab.Problems.Instances;
|
---|
7 | using HeuristicLab.Problems.Instances.TSPLIB;
|
---|
8 |
|
---|
9 | namespace HeuristicLab.Problems.PTSP {
|
---|
10 | public class PTSPLIBInstanceProvider : TSPLIBInstanceProvider<PTSPData> {
|
---|
11 |
|
---|
12 | public override string Name {
|
---|
13 | get { return "(P)TSPLIB (symmetric TSP)"; }
|
---|
14 | }
|
---|
15 |
|
---|
16 | public override string Description {
|
---|
17 | get { return "Adaption of the Traveling Salesman Problem Library for probabilistic instances"; }
|
---|
18 | }
|
---|
19 |
|
---|
20 | protected override string FileExtension { get { return "tsp"; } }
|
---|
21 |
|
---|
22 | public override IEnumerable<IDataDescriptor> GetDataDescriptors() {
|
---|
23 | Dictionary<string, string> solutions = new Dictionary<string, string>();
|
---|
24 | var solutionsArchiveName = GetResourceName(FileExtension + @"\.opt\.tour\.zip");
|
---|
25 | if (!String.IsNullOrEmpty(solutionsArchiveName)) {
|
---|
26 | using (var solutionsZipFile = new ZipArchive(typeof(TSPLIBTSPInstanceProvider).Assembly.GetManifestResourceStream(solutionsArchiveName), ZipArchiveMode.Read)) {
|
---|
27 | foreach (var entry in solutionsZipFile.Entries)
|
---|
28 | solutions.Add(entry.Name.Substring(0, entry.Name.Length - ".opt.tour".Length) + "." + FileExtension, entry.Name);
|
---|
29 | }
|
---|
30 | }
|
---|
31 | var instanceArchiveName = GetResourceName(FileExtension + @"\.zip");
|
---|
32 | if (String.IsNullOrEmpty(instanceArchiveName)) yield break;
|
---|
33 |
|
---|
34 | using (var instanceStream = new ZipArchive(typeof(TSPLIBTSPInstanceProvider).Assembly.GetManifestResourceStream(instanceArchiveName), ZipArchiveMode.Read)) {
|
---|
35 | foreach (var entry in instanceStream.Entries.Select(x => x.Name).OrderBy(x => x)) {
|
---|
36 | yield return new PTSPDataDescriptor(Path.GetFileNameWithoutExtension(entry), GetInstanceDescription(), entry, solutions.ContainsKey(entry) ? solutions[entry] : String.Empty);
|
---|
37 | }
|
---|
38 | }
|
---|
39 | }
|
---|
40 |
|
---|
41 | public override PTSPData LoadData(IDataDescriptor id) {
|
---|
42 | var descriptor = (PTSPDataDescriptor)id;
|
---|
43 | var instanceArchiveName = GetResourceName(FileExtension + @"\.zip");
|
---|
44 | using (var instancesZipFile = new ZipArchive(typeof(TSPLIBTSPInstanceProvider).Assembly.GetManifestResourceStream(instanceArchiveName), ZipArchiveMode.Read)) {
|
---|
45 | var entry = instancesZipFile.GetEntry(descriptor.InstanceIdentifier);
|
---|
46 | var stream = entry.Open();
|
---|
47 | var parser = new TSPLIBParser(stream);
|
---|
48 | var instance = LoadInstance(parser);
|
---|
49 |
|
---|
50 | if (!String.IsNullOrEmpty(descriptor.SolutionIdentifier)) {
|
---|
51 | var solutionsArchiveName = GetResourceName(FileExtension + @"\.opt\.tour\.zip");
|
---|
52 | using (var solutionsZipFile = new ZipArchive(typeof(TSPLIBTSPInstanceProvider).Assembly.GetManifestResourceStream(solutionsArchiveName), ZipArchiveMode.Read)) {
|
---|
53 | entry = solutionsZipFile.GetEntry(descriptor.SolutionIdentifier);
|
---|
54 | stream = entry.Open();
|
---|
55 | parser = new TSPLIBParser(stream);
|
---|
56 | LoadSolution(parser, instance);
|
---|
57 | }
|
---|
58 | }
|
---|
59 |
|
---|
60 | return instance;
|
---|
61 | }
|
---|
62 | }
|
---|
63 |
|
---|
64 | protected override PTSPData LoadInstance(TSPLIBParser parser) {
|
---|
65 | parser.Parse();
|
---|
66 | if (parser.FixedEdges != null) throw new InvalidDataException("TSP instance " + parser.Name + " contains fixed edges which are not supported by HeuristicLab.");
|
---|
67 | var instance = new PTSPData();
|
---|
68 | instance.Dimension = parser.Dimension;
|
---|
69 | instance.Coordinates = parser.Vertices ?? parser.DisplayVertices;
|
---|
70 | instance.Distances = parser.Distances;
|
---|
71 | switch (parser.EdgeWeightType) {
|
---|
72 | case TSPLIBEdgeWeightTypes.ATT:
|
---|
73 | instance.DistanceMeasure = DistanceMeasure.Att; break;
|
---|
74 | case TSPLIBEdgeWeightTypes.CEIL_2D:
|
---|
75 | instance.DistanceMeasure = DistanceMeasure.UpperEuclidean; break;
|
---|
76 | case TSPLIBEdgeWeightTypes.EUC_2D:
|
---|
77 | instance.DistanceMeasure = DistanceMeasure.RoundedEuclidean; break;
|
---|
78 | case TSPLIBEdgeWeightTypes.EUC_3D:
|
---|
79 | throw new InvalidDataException("3D coordinates are not supported.");
|
---|
80 | case TSPLIBEdgeWeightTypes.EXPLICIT:
|
---|
81 | instance.DistanceMeasure = DistanceMeasure.Direct; break;
|
---|
82 | case TSPLIBEdgeWeightTypes.GEO:
|
---|
83 | instance.DistanceMeasure = DistanceMeasure.Geo; break;
|
---|
84 | case TSPLIBEdgeWeightTypes.MAN_2D:
|
---|
85 | instance.DistanceMeasure = DistanceMeasure.Manhattan; break;
|
---|
86 | case TSPLIBEdgeWeightTypes.MAN_3D:
|
---|
87 | throw new InvalidDataException("3D coordinates are not supported.");
|
---|
88 | case TSPLIBEdgeWeightTypes.MAX_2D:
|
---|
89 | instance.DistanceMeasure = DistanceMeasure.Maximum; break;
|
---|
90 | case TSPLIBEdgeWeightTypes.MAX_3D:
|
---|
91 | throw new InvalidDataException("3D coordinates are not supported.");
|
---|
92 | default:
|
---|
93 | throw new InvalidDataException("The given edge weight is not supported by HeuristicLab.");
|
---|
94 | }
|
---|
95 |
|
---|
96 | // use own hash function in case the implementation of String.GetHashCode() changes
|
---|
97 | // ... and hope that System.Random doesn't change
|
---|
98 | var random = new System.Random(Hash(parser.Name));
|
---|
99 | instance.Probabilities = Enumerable.Range(0, parser.Dimension).Select(x => random.NextDouble() * 0.8 + 0.1).ToArray();
|
---|
100 | instance.Name = parser.Name;
|
---|
101 | instance.Description = parser.Comment
|
---|
102 | + Environment.NewLine + Environment.NewLine
|
---|
103 | + GetInstanceDescription();
|
---|
104 | return instance;
|
---|
105 | }
|
---|
106 |
|
---|
107 | protected override void LoadSolution(TSPLIBParser parser, PTSPData instance) {
|
---|
108 | // the TSP optimal tour isn't necessarily the PTSP optimal tour
|
---|
109 | }
|
---|
110 |
|
---|
111 | public PTSPData LoadData(string tspFile, double? bestQuality) {
|
---|
112 | var data = LoadInstance(new TSPLIBParser(tspFile));
|
---|
113 | if (bestQuality.HasValue)
|
---|
114 | data.BestKnownQuality = bestQuality.Value;
|
---|
115 | return data;
|
---|
116 | }
|
---|
117 |
|
---|
118 | private int Hash(string s) {
|
---|
119 | var h = 3571;
|
---|
120 | unchecked {
|
---|
121 | for (var i = 0; i < s.Length; i++)
|
---|
122 | h = h * 31 + s[i];
|
---|
123 | }
|
---|
124 | return h;
|
---|
125 | }
|
---|
126 | }
|
---|
127 |
|
---|
128 | internal class PTSPDataDescriptor : IDataDescriptor {
|
---|
129 | public string Name { get; internal set; }
|
---|
130 | public string Description { get; internal set; }
|
---|
131 |
|
---|
132 | internal string InstanceIdentifier { get; set; }
|
---|
133 | internal string SolutionIdentifier { get; set; }
|
---|
134 |
|
---|
135 | internal PTSPDataDescriptor(string name, string description, string instanceIdentifier, string solutionIdentifier) {
|
---|
136 | this.Name = name;
|
---|
137 | this.Description = description;
|
---|
138 | this.InstanceIdentifier = instanceIdentifier;
|
---|
139 | this.SolutionIdentifier = solutionIdentifier;
|
---|
140 | }
|
---|
141 | }
|
---|
142 | }
|
---|