Files
ortools-clone/ortools/lp_data/mps_reader.h

261 lines
8.1 KiB
C++

// Copyright 2010-2017 Google
// 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// 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 reader for files in the MPS format.
// see http://lpsolve.sourceforge.net/5.5/mps-format.htm
// and http://www.ici.ro/camo/language/ml11.htm.
//
// MPS stands for Mathematical Programming System.
//
// The format was invented by IBM in the 60's, and has become the de facto
// standard. We developed this reader to be able to read benchmark data
// files. Using the MPS file format for new models is discouraged.
#ifndef OR_TOOLS_LP_DATA_MPS_READER_H_
#define OR_TOOLS_LP_DATA_MPS_READER_H_
#include <algorithm> // for max
#include <string> // for std::string
#include <unordered_map>
#include <vector> // for vector
#include "ortools/base/commandlineflags.h"
#include "ortools/base/hash.h"
#include "ortools/base/int_type.h"
#include "ortools/base/int_type_indexed_vector.h"
#include "ortools/base/macros.h" // for DISALLOW_COPY_AND_ASSIGN, NULL
#include "ortools/base/map_util.h" // for FindOrNull, FindWithDefault
#include "ortools/base/stringprintf.h"
#include "ortools/lp_data/lp_data.h"
#include "ortools/lp_data/lp_types.h"
DECLARE_bool(mps_free_form);
DECLARE_bool(mps_stop_after_first_error);
namespace operations_research {
namespace glop {
// Different types of constraints for a given row.
typedef enum {
UNKNOWN_ROW_TYPE,
EQUALITY,
LESS_THAN,
GREATER_THAN,
OBJECTIVE,
NONE
} MPSRowType;
// Reads a linear program in the mps format.
//
// All Load() methods clear the previously loaded instance and store the result
// in the given LinearProgram. They return false in case of failure to read the
// instance.
class MPSReader {
public:
MPSReader();
// Loads instance from a file.
bool LoadFile(const std::string& file_name, LinearProgram* data);
// Loads instance from a file, specifying if free or fixed format is used.
bool LoadFileWithMode(const std::string& file_name, bool free_form,
LinearProgram* data);
// Same as load file, but try free form mps on fail.
bool LoadFileAndTryFreeFormOnFail(const std::string& file_name,
LinearProgram* data);
// Returns the name of the last loaded problem as defined in the NAME line.
std::string GetProblemName() const;
// See log_errors_ (the default is true).
void set_log_errors(bool v) { log_errors_ = v; }
private:
// Number of fields in one line of MPS file
static const int kNumFields;
// Starting positions of each of the fields.
static const int kFieldStartPos[];
// Lengths of each of the fields.
static const int kFieldLength[];
// Resets the object to its initial value before reading a new file.
void Reset();
// Displays some information on the last loaded file.
void DisplaySummary();
// Get each field for a given line.
void SplitLineIntoFields();
// Get the first word in a line.
std::string 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 fields_[offset + index].
const std::string& GetField(int offset, int index) const {
return fields_[offset + index];
}
// Returns the offset at which to start the parsing of fields_.
// 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.
int GetFieldOffset() const { return free_form_ ? fields_.size() & 1 : 0; }
// Line processor.
void ProcessLine(const std::string& line);
// Process section NAME in the MPS file.
void ProcessNameSection();
// Process section ROWS in the MPS file.
void ProcessRowsSection();
// Process section COLUMNS in the MPS file.
void ProcessColumnsSection();
// Process section RHS in the MPS file.
void ProcessRhsSection();
// Process section RANGES in the MPS file.
void ProcessRangesSection();
// Process section BOUNDS in the MPS file.
void ProcessBoundsSection();
// Process section SOS in the MPS file.
void ProcessSosSection();
// Safely converts a std::string to a double. Possibly sets parse_success_ to
// false if the std::string passed as parameter is ill-formed.
double GetDoubleFromString(const std::string& param);
// Different types of variables, as defined in the MPS file specification.
// Note these are more precise than the ones in PrimalSimplex.
typedef enum {
UNKNOWN_BOUND_TYPE,
LOWER_BOUND,
UPPER_BOUND,
FIXED_VARIABLE,
FREE_VARIABLE,
NEGATIVE,
POSITIVE,
BINARY
} BoundTypeId;
// Stores a bound value of a given type, for a given column name.
void StoreBound(const std::string& bound_type_mnemonic,
const std::string& column_name,
const std::string& bound_value);
// Stores a coefficient value for a column number and a row name.
void StoreCoefficient(ColIndex col, const std::string& row_name,
const std::string& row_value);
// Stores a right-hand-side value for a row name.
void StoreRightHandSide(const std::string& row_name,
const std::string& row_value);
// Stores a range constraint of value row_value for a row name.
void StoreRange(const std::string& row_name, const std::string& range_value);
// Boolean set to true if the reader expects a free-form MPS file.
bool free_form_;
LinearProgram* data_;
// The name of the problem as defined on the NAME line in the MPS file.
std::string problem_name_;
// True if the parsing was successful.
bool parse_success_;
// Storage of the fields for a line of the MPS file.
std::vector<std::string> fields_;
// Stores the name of the objective row.
std::string objective_name_;
// Enum for section ids.
typedef enum {
UNKNOWN_SECTION,
COMMENT,
NAME,
ROWS,
LAZYCONS,
COLUMNS,
RHS,
RANGES,
BOUNDS,
SOS,
ENDATA
} SectionId;
// Id of the current section of MPS file.
SectionId section_;
// Maps section mnemonic --> section id.
std::unordered_map<std::string, SectionId> section_name_to_id_map_;
// Maps row type mnemonic --> row type id.
std::unordered_map<std::string, MPSRowType> row_name_to_id_map_;
// Maps bound type mnemonic --> bound type id.
std::unordered_map<std::string, BoundTypeId> bound_name_to_id_map_;
// Set of bound type mnemonics that constrain variables to be integer.
std::unordered_set<std::string> integer_type_names_set_;
// The current line number in the file being parsed.
int64 line_num_;
// The current line in the file being parsed.
std::string line_;
// A row of Booleans. is_binary_by_default_[col] is true if col
// appeared within a scope started by INTORG and ended with INTEND markers.
DenseBooleanRow is_binary_by_default_;
// True if the problem contains lazy constraints (LAZYCONS).
bool has_lazy_constraints_;
// True if the next variable has to be interpreted as an integer variable.
// This is used to support the marker INTORG that starts an integer section
// and INTEND that ends it.
bool in_integer_section_;
// We keep track of the number of unconstrained rows so we can display it to
// the user because other solvers usually ignore them and we don't (they will
// be removed in the preprocessor).
int num_unconstrained_rows_;
// Whether to log errors to LOG(ERROR) or not. Sometimes we just want to use
// this class to detect a valid .mps file, and encountering errors is
// expected.
bool log_errors_;
DISALLOW_COPY_AND_ASSIGN(MPSReader);
};
} // namespace glop
} // namespace operations_research
#endif // OR_TOOLS_LP_DATA_MPS_READER_H_