[13202] | 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 | }
|
---|