source: branches/symbreg-factors-2650/HeuristicLab.Problems.Instances.VehicleRouting/3.4/GoldenFormat/GoldenParser.cs @ 14542

Last change on this file since 14542 was 14542, checked in by gkronber, 3 years ago

#2650: merged r14504:14533 from trunk to branch

File size: 12.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 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.IO;
24
25namespace HeuristicLab.Problems.Instances.VehicleRouting {
26  public class GoldenParser {
27    private string file;
28    private Stream stream;
29    private string problemName;
30
31    #region Inner Enum TSPLIBEdgeWeightType
32    public enum GoldenEdgeWeightType {
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 string comment;
55    /// <summary>
56    /// Gets the comment of the parsed VRP.
57    /// </summary>
58    public string Comment {
59      get { return comment; }
60    }
61    private double[,] vertices;
62    /// <summary>
63    /// Gets the vertices of the parsed VRP.
64    /// </summary>
65    public double[,] Vertices {
66      get { return vertices; }
67    }
68    private GoldenEdgeWeightType weightType;
69    /// <summary>
70    /// Gets the weight format of the parsed VRP.
71    /// </summary>
72    public GoldenEdgeWeightType WeightType {
73      get { return weightType; }
74    }
75
76    private double capacity;
77    public double Capacity {
78      get {
79        return capacity;
80      }
81    }
82
83    private int vehicles;
84    public int Vehicles {
85      get {
86        return vehicles;
87      }
88    }
89
90    private double distance;
91    public double Distance {
92      get {
93        return distance;
94      }
95    }
96
97    private double[] demands;
98    public double[] Demands {
99      get {
100        return demands;
101      }
102    }
103
104    public String ProblemName {
105      get {
106        return problemName;
107      }
108    }
109
110    /// <summary>
111    /// Initializes a new instance of <see cref="TSPLIBParser"/> with the given <paramref name="path"/>.
112    /// </summary>
113    /// <exception cref="ArgumentException">Thrown if the input file is not a TSPLIB TSP file (*.vrp)
114    /// </exception>
115    /// <param name="path">The path where the VRP is stored.</param>
116    public GoldenParser() {
117      comment = string.Empty;
118      vertices = null;
119      weightType = GoldenEdgeWeightType.UNDEFINED;
120      capacity = -1;
121      vehicles = -1;
122      distance = -1;
123      demands = null;
124    }
125
126    public GoldenParser(string file)
127      : this() {
128      this.file = file;
129    }
130
131    public GoldenParser(Stream stream)
132      : this() {
133      this.stream = stream;
134    }
135
136    /// <summary>
137    /// Reads the TSPLIB VRP file and parses the elements.
138    /// </summary>
139    /// <exception cref="InvalidDataException">Thrown if the file has an invalid format or contains invalid data.</exception>
140    public void Parse() {
141      StreamReader reader;
142      if (stream != null) {
143        reader = new StreamReader(stream);
144      } else {
145        reader = new StreamReader(file);
146        problemName = Path.GetFileNameWithoutExtension(file);
147      }
148
149      using (reader) {
150        int section = -1;
151        string str = null;
152        bool weightFormatIsChecked = false;
153
154        do {
155          str = reader.ReadLine();
156          section = GetSection(str);
157
158          if (section != -1) {
159            switch (section) {
160              case NAME:
161                ReadName(str);
162                break;
163              case TYPE:
164                CheckType(str);
165                break;
166              case COMMENT:
167                ReadComment(str);
168                break;
169              case DIM:
170                InitArrays(str);
171                break;
172              case WEIGHTTYPE:
173                ReadWeightType(str);
174                break;
175              case WEIGHTFORMAT:
176                ReadWeightFormat(str);
177                weightFormatIsChecked = true;
178                break;
179              case NODETYPE:
180                CheckNodeType(str);
181                break;
182              case NODESECTION:
183                ReadVertices(reader);
184                break;
185              case CAPACITY:
186                ReadCapacity(str);
187                break;
188              case VEHICLES:
189                ReadVehicles(str);
190                break;
191              case DISTANCE:
192                ReadDistance(str);
193                break;
194              case DEPOTSECTION:
195                ReadDepot(reader);
196                break;
197              case DEMANDSECTION:
198                ReadDemands(reader);
199                break;
200            }
201          }
202        } while (!((section == EOF) || (str == null)));
203
204        if (!weightFormatIsChecked || weightType == GoldenEdgeWeightType.UNDEFINED)
205          throw new InvalidDataException("Input file does not contain format or edge weight format information.");
206      }
207    }
208
209    private int GetSection(string str) {
210      if (str == null)
211        return EOF;
212
213      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
214      if (tokens.Length == 0)
215        return -1;
216
217      string token = tokens[0].Trim();
218      if (token.Equals("eof", StringComparison.OrdinalIgnoreCase))
219        return EOF;
220      if (token.Equals("name", StringComparison.OrdinalIgnoreCase))
221        return NAME;
222      if (token.Equals("type", StringComparison.OrdinalIgnoreCase))
223        return TYPE;
224      if (token.Equals("comment", StringComparison.OrdinalIgnoreCase))
225        return COMMENT;
226      if (token.Equals("dimension", StringComparison.OrdinalIgnoreCase))
227        return DIM;
228      if (token.Equals("edge_weight_type", StringComparison.OrdinalIgnoreCase))
229        return WEIGHTTYPE;
230      if (token.Equals("edge_weight_format", StringComparison.OrdinalIgnoreCase))
231        return WEIGHTFORMAT;
232      if (token.Equals("node_coord_type", StringComparison.OrdinalIgnoreCase))
233        return NODETYPE;
234      if (token.Equals("node_coord_section", StringComparison.OrdinalIgnoreCase))
235        return NODESECTION;
236      if (token.Equals("capacity", StringComparison.OrdinalIgnoreCase))
237        return CAPACITY;
238      if (token.Equals("vehicles", StringComparison.OrdinalIgnoreCase))
239        return VEHICLES;
240      if (token.Equals("distance", StringComparison.OrdinalIgnoreCase))
241        return DISTANCE;
242      if (token.Equals("depot_section", StringComparison.OrdinalIgnoreCase))
243        return DEPOTSECTION;
244      if (token.Equals("demand_section", StringComparison.OrdinalIgnoreCase))
245        return DEMANDSECTION;
246
247      return -1;
248    }
249
250    private void ReadName(string str) {
251      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
252      problemName = tokens[tokens.Length - 1].Trim();
253    }
254
255    private void CheckType(string str) {
256      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
257
258      string type = tokens[tokens.Length - 1].Trim();
259      if (!type.Equals("cvrp", StringComparison.OrdinalIgnoreCase))
260        throw new InvalidDataException("Input file format is not \"CVRP\"");
261    }
262
263    private void ReadComment(string str) {
264      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
265      comment = tokens[tokens.Length - 1].Trim();
266    }
267
268    private void InitArrays(string str) {
269      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
270      string dimension = tokens[tokens.Length - 1].Trim();
271
272      int dim = Int32.Parse(dimension);
273      vertices = new double[dim, 2];
274      demands = new double[dim];
275    }
276
277    private void ReadWeightType(string str) {
278      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
279      string type = tokens[tokens.Length - 1].Trim();
280
281      if (type.Equals("euc_2d", StringComparison.OrdinalIgnoreCase))
282        weightType = GoldenEdgeWeightType.EUC_2D;
283      else if (type.Equals("geo", StringComparison.OrdinalIgnoreCase))
284        weightType = GoldenEdgeWeightType.GEO;
285      else if (type.Equals("function", StringComparison.OrdinalIgnoreCase)) {
286        weightType = GoldenEdgeWeightType.UNDEFINED;
287      } else
288        throw new InvalidDataException("Input file contains an unsupported edge weight format (only \"EUC_2D\" and \"GEO\" are supported).");
289    }
290
291    private void ReadWeightFormat(string str) {
292      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
293      string format = tokens[tokens.Length - 1].Trim();
294
295      if (format.Equals("euc_2d", StringComparison.OrdinalIgnoreCase))
296        weightType = GoldenEdgeWeightType.EUC_2D;
297      else if (format.Equals("geo", StringComparison.OrdinalIgnoreCase))
298        weightType = GoldenEdgeWeightType.GEO;
299      else
300        throw new InvalidDataException("Input file contains an unsupported edge weight format.");
301    }
302
303    private void CheckNodeType(string str) {
304      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
305      string type = tokens[tokens.Length - 1].Trim();
306
307      if (!type.Equals("twod_coords", StringComparison.OrdinalIgnoreCase))
308        throw new InvalidDataException("Input file contains an unsupported node coordinates format (only \"TWOD_COORDS\" is supported).");
309    }
310
311    private void ReadVertices(StreamReader reader) {
312      if (vertices == null)
313        throw new InvalidDataException("Input file does not contain dimension information.");
314
315      for (int i = 1; i < (vertices.Length / 2); i++) {
316        string str = reader.ReadLine();
317        string[] tokens = str.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
318
319        if (tokens.Length != 3)
320          throw new InvalidDataException("Input file contains invalid node coordinates.");
321
322        vertices[i, 0] = double.Parse(tokens[1], System.Globalization.CultureInfo.InvariantCulture);
323        vertices[i, 1] = double.Parse(tokens[2], System.Globalization.CultureInfo.InvariantCulture);
324      }
325    }
326
327    private void ReadCapacity(string str) {
328      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
329      capacity = double.Parse(tokens[tokens.Length - 1].Trim(), System.Globalization.CultureInfo.InvariantCulture);
330    }
331
332    private void ReadVehicles(string str) {
333      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
334      vehicles = int.Parse(tokens[tokens.Length - 1].Trim());
335    }
336
337    private void ReadDistance(string str) {
338      string[] tokens = str.Split(new string[] { ":" }, StringSplitOptions.None);
339      distance = double.Parse(tokens[tokens.Length - 1].Trim(), System.Globalization.CultureInfo.InvariantCulture);
340    }
341
342    private void ReadDepot(StreamReader reader) {
343      string[] tokens;
344      do {
345        string str = reader.ReadLine();
346        tokens = str.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
347
348        if (tokens.Length == 2) {
349          vertices[0, 0] = double.Parse(tokens[0], System.Globalization.CultureInfo.InvariantCulture);
350          vertices[0, 1] = double.Parse(tokens[1], System.Globalization.CultureInfo.InvariantCulture);
351        }
352      } while (tokens.Length == 2);
353    }
354
355    private void ReadDemands(StreamReader reader) {
356      if (demands == null)
357        throw new InvalidDataException("Input file does not contain dimension information.");
358
359      for (int i = 0; i < demands.Length; i++) {
360        if (i != 0) {
361          string str = reader.ReadLine();
362          string[] tokens = str.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
363
364          if (tokens.Length != 2)
365            throw new InvalidDataException("Input file contains invalid demands.");
366
367          int index = int.Parse(tokens[0]);
368          double value = double.Parse(tokens[1], System.Globalization.CultureInfo.InvariantCulture);
369
370          demands[index] = value;
371        } else {
372          demands[0] = 0;
373        }
374      }
375    }
376  }
377}
Note: See TracBrowser for help on using the repository browser.