![]() |
Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. A templated-reader for MPS (Mathematical Programming System) format.
From Wikipedia https://en.wikipedia.org/wiki/MPS_(format): ``` The format was named after an early IBM LP product[1] and has emerged as a de facto standard ASCII medium among most of the commercial LP solvers.
MPS is column-oriented (as opposed to entering the model as equations), and all model components (variables, rows, etc.) receive names. MPS is an old format, so it is set up for punch cards: Fields start in column 2, 5, 15, 25, 40 and 50. Sections of an MPS file are marked by so-called header cards, which are distinguished by their starting in column 1. Although it is typical to use upper-case throughout the file for historical reasons, many MPS-readers will accept mixed-case for anything except the header cards, and some allow mixed-case anywhere. The names that you choose for the individual entities (constraints or variables) are not important to the solver; one should pick meaningful names, or easy names for a post-processing code to read. ```
For example: NAME TESTPROB ROWS N COST L LIM1 G LIM2 E MYEQN COLUMNS XONE COST 1 LIM1 1 XONE LIM2 1 YTWO COST 4 LIM1 1 YTWO MYEQN -1 ZTHREE COST 9 LIM2 1 ZTHREE MYEQN 1 RHS RHS1 LIM1 5 LIM2 10 RHS1 MYEQN 7 BOUNDS UP BND1 XONE 4 LO BND1 YTWO -1 UP BND1 YTWO 1 ENDATA
A common alternative is the so-called free format; where names can have (in principle) arbitrary length, but no white space, and where each data or section line can start with or without white space. In both cases the number of fields in each line remain unchanged. This implementation supports both fixed and free (width) format.
Although there is no one format (as many solvers have expanded it over time to support their own generalizations to MIP; i.e. Mixed Integer (Linear) Programming; most support the sections shown in the previous example.
In what follows, we describe the format and requirements for each of the supported sections. Note that sections must appear in the order in this description, and that optional sections can be skipped altogether, but if they do appear, the must do so in the order in this description.
Section order and data within each section:
This optional section has the format: 'NAME <optional_name>‘ / In fixed format, <optional_name> must start at column 15. / / - OBJSENSE / / This optional section specifies the objective direction of the problem (min / or max), by a single line containing either 'MIN’ or 'MAX'. In fixed format, / this field must start at column 2. If no OBJSENSE section is present, the / problem should be treated as a minimization problem (this is the most widely / used convention, but the actual behavior is implementation defined). / / - ROWS / / This is mandatory section, and each following data line is composed of / lines with two fields: / ' T RowName' / where T is one of: / - N: for no constraint type, usually used to describe objective / coefficients. The first row of type N is used as objective function. If / no row is of type N, then the objective function is zero, and the / problem can be seen a feasibility problem. / - L: for less than or equal, / - G: for greater than or equal, / - E: for equality constraints. / Right hand side of constraints are zero by default (these can be overridden / in sections RHS and RANGES). Repeating a 'RowName' is undefined behavior. In / fixed format, the type appears in column 2 and the row name starts in / column 5. / / - LAZYCONS / / This section is optional, and has the same format (and meaning) as the ROWS / section, i.e. each constraint mentioned here must be new, and each one of / them defines a constraint of the problem. The only difference is that / constraints defined in this section are marked as 'lazy', meaning that there / might be an advantage, when solving the problem, to dynamically add them to / the solving process on the fly. / / - COLUMNS / / This is a mandatory section, and each of the following data lines is / composed of three or five fields with the format: / ' <ColName> <RowName>
<RowName2> <Value2>' / where 'RowName' and 'RowName2' are constraints defined in the ROWS or / LAZYCONS section; 'Value' and 'Value2' are finite values; 'RowName2' and / 'Value2' are optional. The triplet <RowName,ColName,Value> is added to / constraint matrix; and, if present, the triplet <RowName2,ColName,Value2> is / added to the constraint matrix. Note that there is no explicit requirement / that triplets are unique (and how to treat duplicates is / implementation-defined) nor sorted. / / In fixed format, the column name starts in column 5, the row name for the / first non-zero starts in column 15, and the value for the first non-zero / starts in column 25. If a second non-zero is present, the row name starts in / column 40 and the value starts in column 50. / / The COLUMNS section can optionally include (possibly multiple) integrality / markers. Variables mentioned between a pair of markers are assigned type / 'Integer' with binary bounds by default (even if the variable appears for the / first time outside a pair of integrality markers, thus changing its default / bounds). Refer to the BOUNDS section for how to change these bounds. / / The format of these markers is (excluding double quotes): / - " <IgnoredField> 'MARKER' 'INTORG'", / - " <ColName> <RowName> <Value> <RowName2> <Value2>" / ... / - " <ColName> <RowName> <Value> <RowName2> <Value2>" / - " <IgnoredField> 'MARKER' 'INTEND'", / Where the first field is ignored. In fixed format, the fields start in / columns 5, 15 and 40, respectively. Note that the second field must exactly / match 'MARKER', and the third field must be 'INTORG' for opening an integer / section, and 'INTEND' for closing an integer section. / / - RHS / / This is a mandatory section, and each of the following data lines is / composed of three or five fields with the format: / ' <Ignored_Field> <RowName1> <Value1> <OptionalRow2> <OptionalValue2>', / where the first field is ignored, and <RowName> must have been defined in / sections ROWS or LAZYCONS with type E, L or G, and where <Value1> is the / right hand side of <RowName>, and must be a finite value. If <OptionalRow2> / and <OptionalValue2> are present, the same constraints and behavior applies. / In fixed format fields start at columns 2, 5, 15, 40 and 50. / / You can specify an objective 'Offset' by adding the pair <Objective_Name> / <Minus_Offset> in one of the data lines of the RHS section. / / - RANGES / / This is an optional section, and each of the following data lines is / composed of three or five fields: / ' <IgnoredField> <RowName> <Range1> <OptionalRowName2> <OptionalRange2>', / where the first field is ignored, and <RowName> must have been defined in / sections ROWS or LAZYCONS with type E, L or G, and <Range1> must be a finite / value. In fixed format fields must start in columns 2, 5, 15, 40 and 50. / / The effect of specifying a range depends on the sense of the / specified row and whether the range has a positive or negative <Range1>: / ~~~ / Row_type Range_value_sign rhs_lower_limit rhs_upper_limit / G + or - rhs rhs + range / L + or - rhs - range rhs / E + rhs rhs + range / E - rhs + range rhs / ~~~ / If <OptionalRowName2> and <OptionalRange2> are present, the same constraints / and behavior applies. / / - BOUNDS / / Each variable has by default a lower bound of zero, and an upper bound of / infinity, except if the variable is mentioned between integrality markers and / is not mentioned in this section, in which case its lower bound is zero, and / its upper bound is one. / / This is a mandatory section, and each of the following data lines is composed / of three or four fields with the format: / ' <BoundType> <IgnoredField> <ColName>
', / - LO: lower bound for variable,
is mandatory, and / the data line has the effect of setting
<= <ColName>, / - UP: upper bound for variable,
is mandatory, and the / data line has the effect of setting <ColName> <=
, / - FX: for fixed variable,
is mandatory, and the data line has the / effect of setting
<= <ColName> <=
, / - FR: for free variable,
is optional and ignored if present, and / the data line has the effect of setting −∞ <= <ColName> <= ∞, / - MI: infinity lower bound,
is optional and ignored if present, and / the data line has the effect of setting −∞ <= <ColName>, / - PL: infinity upper bound,
is optional and ignored if present, and / the data line has the effect of setting <ColName> <= ∞, / - BV: binary variable,
is optional and ignored if present, and the / data line has the effect of setting 0 <= <ColName> <= 1, / - LI: lower bound for integer variables, same constraints and effect as LO. / - UI: upper bound for integer variables, same constraints and effect as UP. / - SC: stands for semi-continuous and indicates that the variable may be zero, / but if not must be equal to at least the value given (this is not a / common type of variable, and can easily be described in terms of a / binary plus a continuous variable and a constraint linking the two, an / implementation may choose not to support this kind of variable); /
is mandatory, and is only meaningful if it is strictly / positive. / No extra constraints or assumptions are imposed on the order, or the number / of bound constraints on a variable. Each data line is processed sequentially / and its effects enforced; regardless of previously set bounds, explicitly or / by default. / / In fixed format, fields start in columns 2, 5, 15 and 25. / / - INDICATORS / / This is an optional section, and each of the following data lines is / composed of four fields with the format: / ' IF <RowName> <ColName> <BinaryValue>', / where <RowName> is a row defined either in the ROWS or LAZYCONS sections, / <ColName> is forced to be a binary variable (intersecting previously set / bounds with the interval [0,1], and requiring it to be integer); the effect / of the data line is to remove <RowName> from the set of common linear / constraints (which must be satisfied for all feasible solutions), and / instead require the constraint to be satisfied only if the binary variable / <ColName> holds the value <BinaryValue>. /
namespace operations_research {
/ Forms of MPS format supported, either detected automatically, or free / format, or fixed (width) format. enum class MPSReaderFormat { kAutoDetect, kFree, kFixed };
/ Implementation details. namespace internal {
/ Maximum number of 'fields' in an MPS line, either in fixed or free format. static constexpr int kNumMpsFields = 6;
/ Enum for MPS section ids. enum class MPSSectionId { kUnknownSection, kName, kObjsense, kRows, kLazycons, kColumns, kRhs, kRanges, kBounds, kIndicators, kEndData };
/ Represents a single line of an MPS file (or string), and its corresponding / fields. class MPSLineInfo { public: / Creates an MPSLineInfo for line, which should outlive this object. If / the line is a comment line, does not split the line into fields. Returns / InvalidArgumentError if: / * free_form == false and line contains a forbidden character ('\t') / after stripping trailing whitespace, / * free_form == false and line is not in fixed format, or / * if when splitting the line into fields too many fields are detected. static absl::StatusOr<MPSLineInfo> Create(int64_t line_num, bool free_form, absl::string_view line);
/ Returns a view of the line. absl::string_view GetLine() const { return line_; }
/
/ Returns the number of fields in the line. What constitutes a 'field' / depends on the format (fixed or free) used at creation time. See the / previous description of MPS fixed and free formats for more details. int GetFieldsSize() const { return fields_.size(); }
/ Returns the word starting at position 0 in the line. If the line is empty, / or if the line starts with a space, returns "". absl::string_view GetFirstWord() const;
/ Returns true if the line contains a comment (starting with '*') or / if it is a blank line. bool IsCommentOrBlank() const;
/ Helper function that returns the index-th field in the line. /
/ After calling SplitLineIntoFields has been called, returns the offset at / which to start the parsing of fields within the line. See the preceding / discussion on free and fixed MPS format for details on what constitutes a / field in a line. / If in fixed form, the offset is 0. / If in fixed form and the number of fields is odd, it is 1, / otherwise it is 0. / This is useful when processing RANGES and RHS sections. / If SplitLineIntoFields has not been called before, returns 0. int GetFieldOffset() const { return free_form_ ? fields_.size() & 1 : 0; }
/ Returns an absl::InvalidArgumentError with the given error message, / postfixed by the line of the .mps file (number and contents). absl::Status InvalidArgumentError(absl::string_view error_message) const;
/ Appends the line of the .mps file (number and contents) to the / status if it's an error message. absl::Status AppendLineToError(const absl::Status& status) const;
private: MPSLineInfo(int64_t line_num, bool free_form, absl::string_view line) : free_form_{free_form}, line_num_{line_num}, line_{line} {}
/ Splits into fields the line. absl::Status SplitLineIntoFields();
/ Returns true if the line matches the fixed format. bool IsFixedFormat() const;
/ Boolean set to true if the reader expects a free-form MPS file. const bool free_form_;
/ Storage of the fields for the line. absl::InlinedVector<absl::string_view, internal::kNumMpsFields> fields_;
/ The current line number (passed at construction time). const int64_t line_num_;
/ The line being parsed (with ASCII trailing white space removed, that / includes windows end of line, new line, space, vertical tab and horizontal / tab). const absl::string_view line_; };
} // namespace internal
/ Templated MPS reader. The template class DataWrapper must provide: / type: / - IndexType: for indices of rows and columns. / functions: / - void SetUp(): Called before parsing. After this function call, the / internal state of the object should be the same as in creation. /
Definition at line 494 of file mps_reader_template.h.
#include <mps_reader_template.h>
Public Types | |
using | IndexType = typename DataWrapper::IndexType |
Type for row and column indices, as provided by DataWrapper. |
Public Member Functions | |
MPSReaderTemplate () | |
absl::StatusOr< MPSReaderFormat > | ParseFile (absl::string_view file_name, DataWrapper *data, MPSReaderFormat form=MPSReaderFormat::kAutoDetect) |
absl::StatusOr< MPSReaderFormat > | ParseString (absl::string_view source, DataWrapper *data, MPSReaderFormat form=MPSReaderFormat::kAutoDetect) |
using MPSReaderTemplate< DataWrapper >::IndexType = typename DataWrapper::IndexType |
Type for row and column indices, as provided by DataWrapper.
Definition at line 497 of file mps_reader_template.h.
MPSReaderTemplate< DataWrapper >::MPSReaderTemplate | ( | ) |
Definition at line 1174 of file mps_reader_template.h.
absl::StatusOr< MPSReaderFormat > MPSReaderTemplate< DataWrapper >::ParseFile | ( | absl::string_view | file_name, |
DataWrapper * | data, | ||
MPSReaderFormat | form = MPSReaderFormat::kAutoDetect ) |
Parses a file in MPS format; if successful, returns the type of MPS format detected (one of kFree or kFixed). If form is either kFixed or kFree, the function will either return kFixed (or kFree respectively) if the input data satisfies the format, or an absl::InvalidArgumentError otherwise.
Definition at line 655 of file mps_reader_template.h.
absl::StatusOr< MPSReaderFormat > MPSReaderTemplate< DataWrapper >::ParseString | ( | absl::string_view | source, |
DataWrapper * | data, | ||
MPSReaderFormat | form = MPSReaderFormat::kAutoDetect ) |
Parses a string in MPS format; if successful, returns the type of MPS format detected (one of kFree or kFixed). If form is either kFixed or kFree, the function will either return kFixed (or kFree respectively) if the input data satisfies the format, or an absl::InvalidArgumentError otherwise.
Definition at line 685 of file mps_reader_template.h.