18#include "absl/container/btree_set.h"
19#include "absl/status/status.h"
20#include "absl/status/statusor.h"
21#include "absl/strings/match.h"
22#include "absl/strings/str_split.h"
37 absl::Status
ParseFile(
const std::string& file_name, Data* data,
42 static const int kNumFields;
45 static const int kFieldStartPos[];
48 static const int kFieldLength[];
51 static const int kSpacePos[];
57 void DisplaySummary();
60 absl::Status SplitLineIntoFields();
66 std::string GetFirstWord()
const;
70 bool IsCommentOrBlank()
const;
73 const std::string& GetField(
int offset,
int index)
const {
74 return fields_[offset +
index];
82 int GetFieldOffset()
const {
return free_form_ ? fields_.size() & 1 : 0; }
85 template <
class DataWrapper>
86 absl::Status ProcessLine(
const std::string& line,
DataWrapper* data);
89 template <
class DataWrapper>
90 absl::Status ProcessObjectiveSenseSection(
DataWrapper* data);
93 template <
class DataWrapper>
94 absl::Status ProcessRowsSection(
bool is_lazy,
DataWrapper* data);
97 template <
class DataWrapper>
98 absl::Status ProcessColumnsSection(
DataWrapper* data);
101 template <
class DataWrapper>
105 template <
class DataWrapper>
106 absl::Status ProcessRangesSection(
DataWrapper* data);
109 template <
class DataWrapper>
110 absl::Status ProcessBoundsSection(
DataWrapper* data);
113 template <
class DataWrapper>
114 absl::Status ProcessIndicatorsSection(
DataWrapper* data);
117 absl::Status ProcessSosSection();
121 absl::StatusOr<double> GetDoubleFromString(
const std::string& str);
122 absl::StatusOr<bool> GetBoolFromString(
const std::string& str);
132 INFINITE_LOWER_BOUND,
133 INFINITE_UPPER_BOUND,
149 template <
class DataWrapper>
150 absl::Status StoreBound(
const std::string& bound_type_mnemonic,
151 const std::string& column_name,
152 const std::string& bound_value,
DataWrapper* data);
155 template <
class DataWrapper>
156 absl::Status StoreCoefficient(
int col,
const std::string& row_name,
157 const std::string& row_value,
161 template <
class DataWrapper>
162 absl::Status StoreRightHandSide(
const std::string& row_name,
163 const std::string& row_value,
167 template <
class DataWrapper>
168 absl::Status StoreRange(
const std::string& row_name,
169 const std::string& range_value,
DataWrapper* data);
173 absl::Status InvalidArgumentError(
const std::string& error_message);
177 absl::Status AppendLineToError(
const absl::Status&
status);
183 std::vector<std::string> fields_;
186 std::string objective_name_;
209 absl::flat_hash_map<std::string, SectionId> section_name_to_id_map_;
212 absl::flat_hash_map<std::string, RowTypeId> row_name_to_id_map_;
215 absl::flat_hash_map<std::string, BoundTypeId> bound_name_to_id_map_;
218 absl::flat_hash_set<std::string> integer_type_names_set_;
228 std::vector<bool> is_binary_by_default_;
233 bool in_integer_section_;
238 int num_unconstrained_rows_;
254 data_->SetDcheckBounds(
false);
261 data_->SetMaximizationProblem(maximize);
265 return data_->FindOrCreateConstraint(
name).value();
272 data_->SetCoefficient(RowIndex(row_index), ColIndex(col_index),
277 <<
"LAZYCONS section detected. It will be handled as an extension of "
281 return data_->constraint_lower_bounds()[RowIndex(row_index)];
284 return data_->constraint_upper_bounds()[RowIndex(row_index)];
288 return data_->FindOrCreateVariable(
name).value();
291 data_->SetVariableType(ColIndex(
index),
295 LOG(
FATAL) <<
"Semi continuous variables are not supported";
304 return data_->IsVariableInteger(ColIndex(
index));
307 return data_->variable_lower_bounds()[ColIndex(
index)];
310 return data_->variable_upper_bounds()[ColIndex(
index)];
315 return absl::UnimplementedError(
316 "LinearProgram does not support indicator constraints.");
337 const auto it = constraint_indices_by_name_.find(
name);
338 if (it != constraint_indices_by_name_.end())
return it->second;
340 const int index = data_->constraint_size();
345 constraint_indices_by_name_[
name] =
index;
363 data_->mutable_constraint(row_index)->set_is_lazy(
true);
366 return data_->constraint(row_index).lower_bound();
369 return data_->constraint(row_index).upper_bound();
373 const auto it = variable_indices_by_name_.find(
name);
374 if (it != variable_indices_by_name_.end())
return it->second;
376 const int index = data_->variable_size();
384 data_->mutable_variable(
index)->set_is_integer(
true);
387 semi_continuous_variables_.push_back(
index);
397 return data_->variable(
index).is_integer();
400 return data_->variable(
index).lower_bound();
403 return data_->variable(
index).upper_bound();
408 const auto it = constraint_indices_by_name_.find(cst_name);
409 if (it == constraint_indices_by_name_.end()) {
410 return absl::InvalidArgumentError(
411 absl::StrCat(
"Constraint \"", cst_name,
"\" doesn't exist."));
413 const int cst_index = it->second;
416 data_->add_general_constraint();
418 absl::StrCat(
"ind_", data_->constraint(cst_index).name()));
424 constraints_to_delete_.insert(cst_index);
426 return absl::OkStatus();
431 constraints_to_delete_);
433 for (
const int index : semi_continuous_variables_) {
444 const int bool_var_index = data_->variable_size();
454 data_->add_general_constraint();
466 data_->add_general_constraint();
500 absl::flat_hash_map<std::string, int> variable_indices_by_name_;
501 absl::flat_hash_map<std::string, int> constraint_indices_by_name_;
502 absl::btree_set<int> constraints_to_delete_;
503 std::vector<int> semi_continuous_variables_;
509 if (data ==
nullptr) {
510 return absl::InvalidArgumentError(
"NULL pointer passed as argument.");
515 return absl::OkStatus();
524 data_wrapper.SetUp();
525 for (
const std::string& line :
529 data_wrapper.CleanUp();
531 return absl::OkStatus();
534template <
class DataWrapper>
535absl::Status MPSReaderImpl::ProcessLine(
const std::string& line,
539 if (IsCommentOrBlank()) {
540 return absl::OkStatus();
542 if (!free_form_ && absl::StrContains(line_,
'\t')) {
543 return InvalidArgumentError(
"File contains tabs.");
546 if (line[0] !=
'\0' && line[0] !=
' ') {
547 section = GetFirstWord();
550 if (section_ == UNKNOWN_SECTION) {
551 return InvalidArgumentError(
"Unknown section.");
553 if (section_ == COMMENT) {
554 return absl::OkStatus();
556 if (section_ == OBJSENSE) {
557 return absl::OkStatus();
559 if (section_ == NAME) {
568 if (fields_.size() >= 2) {
569 data->SetName(fields_[1]);
572 const std::vector<std::string> free_fields =
573 absl::StrSplit(line_, absl::ByAnyChar(
" \t"), absl::SkipEmpty());
574 const std::string free_name =
575 free_fields.size() >= 2 ? free_fields[1] :
"";
576 const std::string fixed_name = fields_.size() >= 3 ? fields_[2] :
"";
577 if (free_name != fixed_name) {
578 return InvalidArgumentError(
579 "Fixed form invalid: name differs between free and fixed "
582 data->SetName(fixed_name);
585 return absl::OkStatus();
590 return InvalidArgumentError(
"Second NAME field.");
592 return ProcessObjectiveSenseSection(data);
594 return ProcessRowsSection(
false, data);
596 return ProcessRowsSection(
true, data);
598 return ProcessColumnsSection(data);
600 return ProcessRhsSection(data);
602 return ProcessRangesSection(data);
604 return ProcessBoundsSection(data);
606 return ProcessIndicatorsSection(data);
608 return ProcessSosSection();
612 return InvalidArgumentError(
"Unknown section.");
614 return absl::OkStatus();
617template <
class DataWrapper>
618absl::Status MPSReaderImpl::ProcessObjectiveSenseSection(DataWrapper* data) {
619 if (fields_.size() != 1 && fields_[0] !=
"MIN" && fields_[0] !=
"MAX") {
620 return InvalidArgumentError(
"Expected objective sense (MAX or MIN).");
622 data->SetObjectiveDirection(fields_[0] ==
"MAX");
623 return absl::OkStatus();
626template <
class DataWrapper>
627absl::Status MPSReaderImpl::ProcessRowsSection(
bool is_lazy,
629 if (fields_.size() < 2) {
630 return InvalidArgumentError(
"Not enough fields in ROWS section.");
632 const std::string row_type_name = fields_[0];
633 const std::string row_name = fields_[1];
636 if (row_type == UNKNOWN_ROW_TYPE) {
637 return InvalidArgumentError(
"Unknown row type.");
641 if (objective_name_.empty() && row_type == NONE) {
642 row_type = OBJECTIVE;
643 objective_name_ = row_name;
645 if (row_type == NONE) {
646 ++num_unconstrained_rows_;
648 const int row = data->FindOrCreateConstraint(row_name);
649 if (is_lazy) data->SetIsLazy(
row);
656 data->ConstraintUpperBound(
row));
659 data->SetConstraintBounds(
row, data->ConstraintLowerBound(
row),
670 return absl::OkStatus();
673template <
class DataWrapper>
674absl::Status MPSReaderImpl::ProcessColumnsSection(DataWrapper* data) {
676 if (absl::StrContains(line_,
"'MARKER'")) {
677 if (absl::StrContains(line_,
"'INTORG'")) {
678 VLOG(2) <<
"Entering integer marker.\n" << line_;
679 if (in_integer_section_) {
680 return InvalidArgumentError(
"Found INTORG inside the integer section.");
682 in_integer_section_ =
true;
683 }
else if (absl::StrContains(line_,
"'INTEND'")) {
684 VLOG(2) <<
"Leaving integer marker.\n" << line_;
685 if (!in_integer_section_) {
686 return InvalidArgumentError(
687 "Found INTEND without corresponding INTORG.");
689 in_integer_section_ =
false;
691 return absl::OkStatus();
693 const int start_index = free_form_ ? 0 : 1;
694 if (fields_.size() < start_index + 3) {
695 return InvalidArgumentError(
"Not enough fields in COLUMNS section.");
697 const std::string& column_name = GetField(start_index, 0);
698 const std::string& row1_name = GetField(start_index, 1);
699 const std::string& row1_value = GetField(start_index, 2);
700 const int col = data->FindOrCreateVariable(column_name);
701 is_binary_by_default_.resize(
col + 1,
false);
702 if (in_integer_section_) {
703 data->SetVariableTypeToInteger(
col);
705 data->SetVariableBounds(
col, 0.0, 1.0);
706 is_binary_by_default_[
col] =
true;
711 if (fields_.size() == start_index + 4) {
712 return InvalidArgumentError(
"Unexpected number of fields.");
714 if (fields_.size() - start_index > 4) {
715 const std::string& row2_name = GetField(start_index, 3);
716 const std::string& row2_value = GetField(start_index, 4);
719 return absl::OkStatus();
722template <
class DataWrapper>
723absl::Status MPSReaderImpl::ProcessRhsSection(DataWrapper* data) {
724 const int start_index = free_form_ ? 0 : 2;
725 const int offset = start_index + GetFieldOffset();
726 if (fields_.size() < offset + 2) {
727 return InvalidArgumentError(
"Not enough fields in RHS section.");
730 const std::string& row1_name = GetField(offset, 0);
731 const std::string& row1_value = GetField(offset, 1);
733 if (fields_.size() - start_index >= 4) {
734 const std::string& row2_name = GetField(offset, 2);
735 const std::string& row2_value = GetField(offset, 3);
738 return absl::OkStatus();
741template <
class DataWrapper>
742absl::Status MPSReaderImpl::ProcessRangesSection(DataWrapper* data) {
743 const int start_index = free_form_ ? 0 : 2;
744 const int offset = start_index + GetFieldOffset();
745 if (fields_.size() < offset + 2) {
746 return InvalidArgumentError(
"Not enough fields in RHS section.");
749 const std::string& row1_name = GetField(offset, 0);
750 const std::string& row1_value = GetField(offset, 1);
752 if (fields_.size() - start_index >= 4) {
753 const std::string& row2_name = GetField(offset, 2);
754 const std::string& row2_value = GetField(offset, 3);
757 return absl::OkStatus();
760template <
class DataWrapper>
761absl::Status MPSReaderImpl::ProcessBoundsSection(DataWrapper* data) {
762 if (fields_.size() < 3) {
763 return InvalidArgumentError(
"Not enough fields in BOUNDS section.");
765 const std::string bound_type_mnemonic = fields_[0];
766 const std::string bound_row_name = fields_[1];
767 const std::string column_name = fields_[2];
768 std::string bound_value;
769 if (fields_.size() >= 4) {
770 bound_value = fields_[3];
772 return StoreBound(bound_type_mnemonic, column_name, bound_value, data);
775template <
class DataWrapper>
776absl::Status MPSReaderImpl::ProcessIndicatorsSection(DataWrapper* data) {
780 if (fields_.size() < 4) {
781 return InvalidArgumentError(
"Not enough fields in INDICATORS section.");
784 const std::string type = fields_[0];
786 return InvalidArgumentError(
787 "Indicator constraints must start with \"IF\".");
789 const std::string row_name = fields_[1];
790 const std::string column_name = fields_[2];
791 const std::string column_value = fields_[3];
796 const int col = data->FindOrCreateVariable(column_name);
798 data->SetVariableTypeToInteger(
col);
799 data->SetVariableBounds(
col,
std::max(0.0, data->VariableLowerBound(
col)),
803 AppendLineToError(data->CreateIndicatorConstraint(row_name,
col,
value)));
805 return absl::OkStatus();
808template <
class DataWrapper>
809absl::Status MPSReaderImpl::StoreCoefficient(
int col,
810 const std::string& row_name,
811 const std::string& row_value,
813 if (row_name.empty() || row_name ==
"$") {
814 return absl::OkStatus();
820 return InvalidArgumentError(
"Constraint coefficients cannot be infinity.");
822 if (
value == 0.0)
return absl::OkStatus();
823 if (row_name == objective_name_) {
824 data->SetObjectiveCoefficient(
col,
value);
826 const int row = data->FindOrCreateConstraint(row_name);
829 return absl::OkStatus();
832template <
class DataWrapper>
833absl::Status MPSReaderImpl::StoreRightHandSide(
const std::string& row_name,
834 const std::string& row_value,
836 if (row_name.empty())
return absl::OkStatus();
838 if (row_name != objective_name_) {
839 const int row = data->FindOrCreateConstraint(row_name);
852 return absl::OkStatus();
855template <
class DataWrapper>
856absl::Status MPSReaderImpl::StoreRange(
const std::string& row_name,
857 const std::string& range_value,
859 if (row_name.empty())
return absl::OkStatus();
861 const int row = data->FindOrCreateConstraint(row_name);
881 return absl::OkStatus();
884template <
class DataWrapper>
885absl::Status MPSReaderImpl::StoreBound(
const std::string& bound_type_mnemonic,
886 const std::string& column_name,
887 const std::string& bound_value,
890 bound_name_to_id_map_, bound_type_mnemonic, UNKNOWN_BOUND_TYPE);
891 if (bound_type_id == UNKNOWN_BOUND_TYPE) {
892 return InvalidArgumentError(
"Unknown bound type.");
894 const int col = data->FindOrCreateVariable(column_name);
895 if (integer_type_names_set_.count(bound_type_mnemonic) != 0) {
896 data->SetVariableTypeToInteger(
col);
898 if (is_binary_by_default_.size() <=
col) {
900 is_binary_by_default_.resize(
col + 1,
false);
903 DCHECK(!is_binary_by_default_[
col] || data->VariableIsInteger(
col));
909 if (is_binary_by_default_[
col]) {
913 switch (bound_type_id) {
917 if (bound_type_mnemonic ==
"LI" &&
lower_bound == 0.0) {
926 case SEMI_CONTINUOUS: {
928 data->SetVariableTypeToSemiContinuous(
col);
931 case FIXED_VARIABLE: {
940 case INFINITE_LOWER_BOUND:
943 case INFINITE_UPPER_BOUND:
950 case UNKNOWN_BOUND_TYPE:
952 return InvalidArgumentError(
"Unknown bound type.");
954 is_binary_by_default_[
col] =
false;
956 return absl::OkStatus();
959const int MPSReaderImpl::kNumFields = 6;
960const int MPSReaderImpl::kFieldStartPos[kNumFields] = {1, 4, 14, 24, 39, 49};
961const int MPSReaderImpl::kFieldLength[kNumFields] = {2, 8, 8, 12, 8, 12};
962const int MPSReaderImpl::kSpacePos[12] = {12, 13, 22, 23, 36, 37,
963 38, 47, 48, 61, 62, 63};
968 section_(UNKNOWN_SECTION),
969 section_name_to_id_map_(),
970 row_name_to_id_map_(),
971 bound_name_to_id_map_(),
972 integer_type_names_set_(),
975 in_integer_section_(false),
976 num_unconstrained_rows_(0) {
977 section_name_to_id_map_[
"*"] = COMMENT;
978 section_name_to_id_map_[
"NAME"] = NAME;
979 section_name_to_id_map_[
"OBJSENSE"] = OBJSENSE;
980 section_name_to_id_map_[
"ROWS"] = ROWS;
981 section_name_to_id_map_[
"LAZYCONS"] = LAZYCONS;
982 section_name_to_id_map_[
"COLUMNS"] = COLUMNS;
983 section_name_to_id_map_[
"RHS"] = RHS;
984 section_name_to_id_map_[
"RANGES"] = RANGES;
985 section_name_to_id_map_[
"BOUNDS"] = BOUNDS;
986 section_name_to_id_map_[
"INDICATORS"] = INDICATORS;
987 section_name_to_id_map_[
"ENDATA"] = ENDATA;
988 row_name_to_id_map_[
"E"] = EQUALITY;
989 row_name_to_id_map_[
"L"] = LESS_THAN;
990 row_name_to_id_map_[
"G"] = GREATER_THAN;
991 row_name_to_id_map_[
"N"] = NONE;
992 bound_name_to_id_map_[
"LO"] = LOWER_BOUND;
993 bound_name_to_id_map_[
"UP"] = UPPER_BOUND;
994 bound_name_to_id_map_[
"FX"] = FIXED_VARIABLE;
995 bound_name_to_id_map_[
"FR"] = FREE_VARIABLE;
996 bound_name_to_id_map_[
"MI"] = INFINITE_LOWER_BOUND;
997 bound_name_to_id_map_[
"PL"] = INFINITE_UPPER_BOUND;
998 bound_name_to_id_map_[
"BV"] = BINARY;
999 bound_name_to_id_map_[
"LI"] = LOWER_BOUND;
1000 bound_name_to_id_map_[
"UI"] = UPPER_BOUND;
1001 bound_name_to_id_map_[
"SC"] = SEMI_CONTINUOUS;
1003 integer_type_names_set_.insert(
"BV");
1004 integer_type_names_set_.insert(
"LI");
1005 integer_type_names_set_.insert(
"UI");
1008void MPSReaderImpl::Reset() {
1009 fields_.resize(kNumFields);
1011 in_integer_section_ =
false;
1012 num_unconstrained_rows_ = 0;
1013 objective_name_.clear();
1016void MPSReaderImpl::DisplaySummary() {
1017 if (num_unconstrained_rows_ > 0) {
1018 VLOG(1) <<
"There are " << num_unconstrained_rows_ + 1
1019 <<
" unconstrained rows. The first of them (" << objective_name_
1020 <<
") was used as the objective.";
1024bool MPSReaderImpl::IsFixedFormat() {
1025 for (
const int i : kSpacePos) {
1026 if (i >= line_.length())
break;
1027 if (line_[i] !=
' ')
return false;
1032absl::Status MPSReaderImpl::SplitLineIntoFields() {
1034 fields_ = absl::StrSplit(line_, absl::ByAnyChar(
" \t"), absl::SkipEmpty());
1035 if (fields_.size() > kNumFields) {
1036 return InvalidArgumentError(
"Found too many fields.");
1043 if (section_ != NAME && !IsFixedFormat()) {
1044 return InvalidArgumentError(
"Line is not in fixed format.");
1046 const int length = line_.length();
1047 for (
int i = 0; i < kNumFields; ++i) {
1048 if (kFieldStartPos[i] < length) {
1049 fields_[i] = line_.substr(kFieldStartPos[i], kFieldLength[i]);
1050 fields_[i].erase(fields_[i].find_last_not_of(
" ") + 1);
1056 return absl::OkStatus();
1059std::string MPSReaderImpl::GetFirstWord()
const {
1060 if (line_[0] ==
' ') {
1061 return std::string(
"");
1063 const int first_space_pos = line_.find(
' ');
1064 const std::string first_word = line_.substr(0, first_space_pos);
1068bool MPSReaderImpl::IsCommentOrBlank()
const {
1069 const char* line = line_.c_str();
1073 for (; *line !=
'\0'; ++line) {
1074 if (*line !=
' ' && *line !=
'\t') {
1081absl::StatusOr<double> MPSReaderImpl::GetDoubleFromString(
1082 const std::string& str) {
1084 if (!absl::SimpleAtod(str, &result)) {
1085 return InvalidArgumentError(
1086 absl::StrCat(
"Failed to convert \"", str,
"\" to double."));
1088 if (std::isnan(result)) {
1089 return InvalidArgumentError(
"Found NaN value.");
1094absl::StatusOr<bool> MPSReaderImpl::GetBoolFromString(
const std::string& str) {
1096 if (!absl::SimpleAtoi(str, &result) || result < 0 || result > 1) {
1097 return InvalidArgumentError(
1098 absl::StrCat(
"Failed to convert \"", str,
"\" to bool."));
1103absl::Status MPSReaderImpl::ProcessSosSection() {
1104 return InvalidArgumentError(
"Section SOS currently not supported.");
1107absl::Status MPSReaderImpl::InvalidArgumentError(
1108 const std::string& error_message) {
1109 return AppendLineToError(absl::InvalidArgumentError(error_message));
1112absl::Status MPSReaderImpl::AppendLineToError(
const absl::Status&
status) {
1114 <<
" Line " << line_num_ <<
": \"" << line_ <<
"\".";
#define LOG_FIRST_N(severity, n)
#define DCHECK_GT(val1, val2)
#define DCHECK(condition)
#define VLOG(verboselevel)
void add_var_index(int32_t value)
void set_name(ArgT0 &&arg0, ArgT... args)
void set_lower_bound(double value)
void add_coefficient(double value)
void set_upper_bound(double value)
::operations_research::MPIndicatorConstraint * mutable_indicator_constraint()
void set_name(ArgT0 &&arg0, ArgT... args)
void set_var_index(int32_t value)
::operations_research::MPConstraintProto * mutable_constraint()
void set_var_value(int32_t value)
void set_is_integer(bool value)
double upper_bound() const
void set_name(ArgT0 &&arg0, ArgT... args)
void set_lower_bound(double value)
double lower_bound() const
void set_upper_bound(double value)
int FindOrCreateConstraint(const std::string &name)
void SetVariableTypeToSemiContinuous(int index)
void SetConstraintBounds(int index, double lower_bound, double upper_bound)
double VariableUpperBound(int index)
void SetVariableTypeToInteger(int index)
void SetObjectiveCoefficient(int index, double coefficient)
void SetConstraintCoefficient(int row_index, int col_index, double coefficient)
double ConstraintUpperBound(int row_index)
double VariableLowerBound(int index)
void SetObjectiveDirection(bool maximize)
absl::Status CreateIndicatorConstraint(std::string row_name, int col_index, bool col_value)
DataWrapper(LinearProgram *data)
int FindOrCreateVariable(const std::string &name)
bool VariableIsInteger(int index)
void SetName(const std::string &name)
void SetIsLazy(int row_index)
double ConstraintLowerBound(int row_index)
void SetVariableBounds(int index, double lower_bound, double upper_bound)
int FindOrCreateConstraint(const std::string &name)
void SetVariableTypeToSemiContinuous(int index)
void SetConstraintBounds(int index, double lower_bound, double upper_bound)
double VariableUpperBound(int index)
void SetVariableTypeToInteger(int index)
void SetObjectiveCoefficient(int index, double coefficient)
void SetConstraintCoefficient(int row_index, int col_index, double coefficient)
double ConstraintUpperBound(int row_index)
double VariableLowerBound(int index)
void SetObjectiveDirection(bool maximize)
int FindOrCreateVariable(const std::string &name)
bool VariableIsInteger(int index)
void SetName(const std::string &name)
void SetIsLazy(int row_index)
DataWrapper(MPModelProto *data)
absl::Status CreateIndicatorConstraint(std::string cst_name, int var_index, bool var_value)
double ConstraintLowerBound(int row_index)
void SetVariableBounds(int index, double lower_bound, double upper_bound)
absl::Status ParseFile(const std::string &file_name, LinearProgram *data, Form form=AUTO_DETECT)
absl::Status ParseFile(const std::string &file_name, Data *data, MPSReader::Form form)
StatusBuilder & SetAppend()
int RemoveAt(RepeatedType *array, const IndexContainer &indices)
const Collection::value_type::second_type & FindWithDefault(const Collection &collection, const typename Collection::value_type::first_type &key, const typename Collection::value_type::second_type &value)
Collection of objects used to extend the Constraint Solver library.
#define ASSIGN_OR_RETURN(lhs, rexpr)
#define RETURN_IF_ERROR(expr)