using System; using System.Globalization; using System.IO; namespace HeuristicLab.Problems.QuadraticAssignment { public class QAPLIBSolutionParser { public int Size { get; private set; } public int[] Assignment { get; private set; } public double Quality { get; private set; } public Exception Error { get; private set; } public QAPLIBSolutionParser() { Reset(); } public void Reset() { Size = 0; Assignment = null; Quality = double.NaN; Error = null; } /// /// Reads from the given stream data which is expected to be in the QAPLIB solution format. /// /// The QAPLIB solution file format (.sln) is as follows: /// First line: Size of the permutation followed by a blank followed by the quality formatted using no thousands separator and if a fractional number with the "." as decimal symbol /// Remaining lines: The values of the permutation separated by blanks. Values must lie in the range [1;size of the permutation]. /// /// The file to read data from. /// The numbers can be interpreted either as facilities or locations. /// HeuristicLab always encodes the permutation such that the index denotes the facility and the value the location. /// If this parameter is true, then the permutation is expected to follow this encoding. /// If this parameter is false, the meaning of value and index will be swapped when reading the permutation. /// public bool Parse(string file, bool valueAsLocation) { using (Stream stream = new FileStream(file, FileMode.Open, FileAccess.Read)) { return Parse(stream, valueAsLocation); } } /// /// Reads from the given stream data which is expected to be in the QAPLIB solution format. /// /// The QAPLIB solution file format (.sln) is as follows: /// First line: Size of the permutation followed by a blank followed by the quality formatted using no thousands separator and if a fractional number with the "." as decimal symbol /// Remaining lines: The values of the permutation separated by blanks. Values must lie in the range [1;size of the permutation]. /// /// /// The stream is not closed or disposed. The caller has to take care of that. /// /// The stream to read data from. /// The numbers can be interpreted either as facilities or locations. /// HeuristicLab always encodes the permutation such that the index denotes the facility and the value the location. /// If this parameter is true, then the permutation is expected to follow this encoding. /// If this parameter is false, the meaning of value and index will be swapped when reading the permutation. /// True if the file was successfully read or false otherwise. public bool Parse(Stream stream, bool valueAsLocation) { Error = null; try { StreamReader reader = new StreamReader(stream); char[] delim = new char[] { ' ', ',' }; // comma is added for nug30.sln which is the only file that separates the permutation with commas string[] firstline = reader.ReadLine().Split(delim, StringSplitOptions.RemoveEmptyEntries); Size = int.Parse(firstline[0]); Quality = double.Parse(firstline[1], CultureInfo.InvariantCulture.NumberFormat); Assignment = new int[Size]; int read = 0; while (!reader.EndOfStream) { string valLine = reader.ReadLine(); string[] vals = valLine.Split(delim, StringSplitOptions.RemoveEmptyEntries); for (int j = 0; j < vals.Length; j++) { if (valueAsLocation) Assignment[int.Parse(vals[j]) - 1] = read++; else Assignment[read++] = int.Parse(vals[j]) - 1; } } return true; } catch (Exception e) { Error = e; return false; } } } }