Free cookie consent management tool by TermsFeed Policy Generator

source: branches/FitnessLandscapeAnalysis/VRPProblemAnalyzer/TSPLIBParser.cs @ 8347

Last change on this file since 8347 was 7316, checked in by svonolfe, 13 years ago

Added Picture generator (#1696)

File size: 13.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Globalization;
24using System.IO;
25
26namespace VRPProblemAnalyzer {
27  /// <summary>
28  /// Parses a *.vrp file in TSPLIB format and extracts its information about a VRP.
29  /// </summary>
30  public class TSPLIBParser {
31    #region Inner Enum TSPLIBEdgeWeightType
32    public enum TSPLIBEdgeWeightType {
33      UNDEFINED,
34      EUC_2D,
35      GEO
36    }
37    #endregion
38
39    private const int EOF = 0;
40    private const int NAME = 1;
41    private const int TYPE = 2;
42    private const int COMMENT = 3;
43    private const int DIM = 4;
44    private const int WEIGHTTYPE = 5;
45    private const int WEIGHTFORMAT = 11;
46    private const int NODETYPE = 6;
47    private const int NODESECTION = 7;
48    private const int CAPACITY = 8;
49    private const int DISTANCE = 12;
50    private const int VEHICLES = 13;
51    private const int DEPOTSECTION = 9;
52    private const int DEMANDSECTION = 10;
53
54    private StreamReader source;
55    private bool alternateFormat;
56    CultureInfo culture = new CultureInfo("en-US");
57
58    private string name;
59    /// <summary>
60    /// Gets the name of the parsed VRP.
61    /// </summary>
62    public string Name {
63      get { return name; }
64    }
65    private string comment;
66    /// <summary>
67    /// Gets the comment of the parsed VRP.
68    /// </summary>
69    public string Comment {
70      get { return comment; }
71    }
72    private double[,] vertices;
73    /// <summary>
74    /// Gets the vertices of the parsed VRP.
75    /// </summary>
76    public double[,] Vertices {
77      get { return vertices; }
78    }
79    private TSPLIBEdgeWeightType weightType;
80    /// <summary>
81    /// Gets the weight format of the parsed VRP.
82    /// </summary>
83    public TSPLIBEdgeWeightType WeightType {
84      get { return weightType; }
85    }
86
87    private double capacity;
88    public double Capacity {
89      get {
90        return capacity;
91      }
92      set {
93        capacity = value;
94      }
95    }
96
97    private double distance;
98    public double Distance {
99      get {
100        return distance;
101      }
102    }
103
104    private int vehicles;
105    public int Vehicles {
106      get {
107        return vehicles;
108      }
109    }
110
111    private int depot;
112    public int Depot {
113      get {
114        return depot;
115      }
116    }
117
118    private double[] demands;
119    public double[] Demands {
120      get {
121        return demands;
122      }
123    }
124
125    /// <summary>
126    /// Initializes a new instance of <see cref="TSPLIBParser"/> with the given <paramref name="path"/>.
127    /// </summary>
128    /// <exception cref="ArgumentException">Thrown if the input file is not a TSPLIB TSP file (*.vrp)
129    /// </exception>
130    /// <param name="path">The path where the VRP is stored.</param>
131    public TSPLIBParser(String path) {
132      if (!path.EndsWith(".vrp"))
133        throw new ArgumentException("Input file has to be a TSPLIB CVRP file (*.vrp, *.txt).");
134
135      source = null;
136      name = path;
137      comment = string.Empty;
138      vertices = null;
139      weightType = TSPLIBEdgeWeightType.UNDEFINED;
140      capacity = -1;
141      distance = -1;
142      vehicles = -1;
143      depot = -1;
144      demands = null;
145      alternateFormat = false;
146    }
147
148    /// <summary>
149    /// Reads the TSPLIB VRP file and parses the elements.
150    /// </summary>
151    /// <exception cref="InvalidDataException">Thrown if the file has an invalid format or contains invalid data.</exception>
152    public void Parse() {
153      using (source = new StreamReader(name)) {
154        int section = -1;
155        string str = null;
156        bool typeIsChecked = false;
157        bool weightTypeIsChecked = false;
158        bool weightFormatIsChecked = false;
159
160        do {
161          str = source.ReadLine();
162          section = GetSection(str);
163
164          if (section != -1) {
165            switch (section) {
166              case NAME:
167                ReadName(str);
168                break;
169              case TYPE:
170                CheckType(str);
171                typeIsChecked = true;
172                break;
173              case COMMENT:
174                ReadComment(str);
175                break;
176              case DIM:
177                InitArrays(str);
178                break;
179              case WEIGHTTYPE:
180                ReadWeightType(str);
181                weightTypeIsChecked = true;
182                break;
183              case WEIGHTFORMAT:
184                ReadWeightFormat(str);
185                weightFormatIsChecked = true;
186                break;
187              case NODETYPE:
188                CheckNodeType(str);
189                break;
190              case NODESECTION:
191                ReadVertices();
192                break;
193              case CAPACITY:
194                ReadCapacity(str);
195                break;
196              case DISTANCE:
197                ReadDistance(str);
198                break;
199              case VEHICLES:
200                ReadVehicles(str);
201                break;
202              case DEPOTSECTION:
203                ReadDepot();
204                break;
205              case DEMANDSECTION:
206                ReadDemands();
207                break;
208            }
209          }
210        } while (!((section == EOF) || (str == null)));
211
212        if (!typeIsChecked || !weightTypeIsChecked ||
213          (alternateFormat && !weightFormatIsChecked) ||
214          weightType == TSPLIBEdgeWeightType.UNDEFINED)
215          throw new InvalidDataException("Input file does not contain format or edge weight format information.");
216      }
217      source = null;
218    }
219
220    private int GetSection(string str) {
221      if (str == null)
222        return EOF;
223
224      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
225      if (tokens.Length == 0)
226        return -1;
227
228      string token = tokens[0].Trim();
229      if (token.Equals("eof", StringComparison.OrdinalIgnoreCase))
230        return EOF;
231      if (token.Equals("name", StringComparison.OrdinalIgnoreCase))
232        return NAME;
233      if (token.Equals("type", StringComparison.OrdinalIgnoreCase))
234        return TYPE;
235      if (token.Equals("comment", StringComparison.OrdinalIgnoreCase))
236        return COMMENT;
237      if (token.Equals("dimension", StringComparison.OrdinalIgnoreCase))
238        return DIM;
239      if (token.Equals("edge_weight_type", StringComparison.OrdinalIgnoreCase))
240        return WEIGHTTYPE;
241      if (token.Equals("edge_weight_format", StringComparison.OrdinalIgnoreCase))
242        return WEIGHTFORMAT;
243      if (token.Equals("node_coord_type", StringComparison.OrdinalIgnoreCase))
244        return NODETYPE;
245      if (token.Equals("node_coord_section", StringComparison.OrdinalIgnoreCase))
246        return NODESECTION;
247      if (token.Equals("capacity", StringComparison.OrdinalIgnoreCase))
248        return CAPACITY;
249      if (token.Equals("distance", StringComparison.OrdinalIgnoreCase))
250        return DISTANCE;
251      if (token.Equals("vehicles", StringComparison.OrdinalIgnoreCase))
252        return VEHICLES;
253      if (token.Equals("depot_section", StringComparison.OrdinalIgnoreCase))
254        return DEPOTSECTION;
255      if (token.Equals("demand_section", StringComparison.OrdinalIgnoreCase))
256        return DEMANDSECTION;
257
258      return -1;
259    }
260
261    private void ReadName(string str) {
262      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
263      name = tokens[tokens.Length - 1].Trim();
264    }
265
266    private void CheckType(string str) {
267      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
268
269      string type = tokens[tokens.Length - 1].Trim();
270      if (!type.Equals("cvrp", StringComparison.OrdinalIgnoreCase))
271        throw new InvalidDataException("Input file format is not \"CVRP\"");
272    }
273
274    private void ReadComment(string str) {
275      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
276      comment = tokens[tokens.Length - 1].Trim();
277    }
278
279    private void InitArrays(string str) {
280      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
281      string dimension = tokens[tokens.Length - 1].Trim();
282
283      int dim = Int32.Parse(dimension);
284      vertices = new double[dim, 2];
285      demands = new double[dim];
286    }
287
288    private void ReadWeightType(string str) {
289      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
290      string type = tokens[tokens.Length - 1].Trim();
291
292      if (type.Equals("euc_2d", StringComparison.OrdinalIgnoreCase))
293        weightType = TSPLIBEdgeWeightType.EUC_2D;
294      else if (type.Equals("geo", StringComparison.OrdinalIgnoreCase))
295        weightType = TSPLIBEdgeWeightType.GEO;
296      else if (type.Equals("function", StringComparison.OrdinalIgnoreCase)) {
297        weightType = TSPLIBEdgeWeightType.UNDEFINED;
298        alternateFormat = true;
299      } else
300        throw new InvalidDataException("Input file contains an unsupported edge weight format (only \"EUC_2D\" and \"GEO\" are supported).");
301    }
302
303    private void ReadWeightFormat(string str) {
304      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
305      string format = tokens[tokens.Length - 1].Trim();
306
307      if (alternateFormat && format.Equals("euc_2d", StringComparison.OrdinalIgnoreCase))
308        weightType = TSPLIBEdgeWeightType.EUC_2D;
309      else if (format.Equals("geo", StringComparison.OrdinalIgnoreCase))
310        weightType = TSPLIBEdgeWeightType.GEO;
311      else
312        throw new InvalidDataException("Input file contains an unsupported edge weight format.");
313    }
314
315    private void CheckNodeType(string str) {
316      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
317      string type = tokens[tokens.Length - 1].Trim();
318
319      if (!type.Equals("twod_coords", StringComparison.OrdinalIgnoreCase))
320        throw new InvalidDataException("Input file contains an unsupported node coordinates format (only \"TWOD_COORDS\" is supported).");
321    }
322
323    private void ReadVertices() {
324      if (vertices == null)
325        throw new InvalidDataException("Input file does not contain dimension information.");
326
327      for (int i = 0; i < (vertices.Length / 2); i++) {
328        if (!(alternateFormat && i == 0)) {
329          string str = source.ReadLine();
330          string[] tokens = str.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
331
332          if (tokens.Length != 3)
333            throw new InvalidDataException("Input file contains invalid node coordinates.");
334
335          vertices[i, 0] = double.Parse(tokens[1], culture.NumberFormat);
336          vertices[i, 1] = double.Parse(tokens[2], culture.NumberFormat);
337        }
338      }
339    }
340
341    private void ReadCapacity(string str) {
342      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
343      capacity = double.Parse(tokens[tokens.Length - 1].Trim(), culture.NumberFormat);
344    }
345
346    private void ReadDistance(string str) {
347      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
348      distance = double.Parse(tokens[tokens.Length - 1].Trim(), culture.NumberFormat);
349    }
350
351    private void ReadVehicles(string str) {
352      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
353      vehicles = int.Parse(tokens[tokens.Length - 1].Trim());
354    }
355
356    private void ReadDepot() {
357      if (alternateFormat) {
358        string[] tokens;
359        do {
360          string str = source.ReadLine();
361          tokens = str.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
362
363          if (tokens.Length == 2) {
364            vertices[0, 0] = double.Parse(tokens[0], culture.NumberFormat);
365            vertices[0, 1] = double.Parse(tokens[1], culture.NumberFormat);
366            depot = 1;
367          }
368        } while(tokens.Length == 2);
369      } else {
370        int read;
371        do {
372          string str = source.ReadLine();
373          read = int.Parse(str);
374          if (read != -1)
375            depot = read;
376        } while (read != -1);
377      }
378    }
379
380    private void ReadDemands() {
381      if (demands == null)
382        throw new InvalidDataException("Input file does not contain dimension information.");
383
384      for (int i = 0; i < demands.Length; i++) {
385        if (!(alternateFormat && i == 0)) {
386          string str = source.ReadLine();
387          string[] tokens = str.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
388
389          if (tokens.Length != 2)
390            throw new InvalidDataException("Input file contains invalid demands.");
391
392          int index = int.Parse(tokens[0]);
393          double value = double.Parse(tokens[1]);
394
395          if (alternateFormat)
396            demands[index] = value;
397          else
398            demands[index - 1] = value;
399        } else {
400          demands[0] = 0;
401        }
402      }
403    }
404  }
405}
Note: See TracBrowser for help on using the repository browser.