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"
36 absl::Status
ParseFile(
const std::string& file_name, Data* data,
41 static const int kNumFields;
44 static const int kFieldStartPos[];
47 static const int kFieldLength[];
50 static const int kSpacePos[];
56 void DisplaySummary();
59 absl::Status SplitLineIntoFields();
65 std::string GetFirstWord()
const;
69 bool IsCommentOrBlank()
const;
72 const std::string& GetField(
int offset,
int index)
const {
73 return fields_[offset +
index];
81 int GetFieldOffset()
const {
return free_form_ ? fields_.size() & 1 : 0; }
84 template <
class DataWrapper>
85 absl::Status ProcessLine(
const std::string& line,
DataWrapper* data);
88 template <
class DataWrapper>
89 absl::Status ProcessObjectiveSenseSection(
DataWrapper* data);
92 template <
class DataWrapper>
93 absl::Status ProcessRowsSection(
bool is_lazy,
DataWrapper* data);
96 template <
class DataWrapper>
97 absl::Status ProcessColumnsSection(
DataWrapper* data);
100 template <
class DataWrapper>
104 template <
class DataWrapper>
105 absl::Status ProcessRangesSection(
DataWrapper* data);
108 template <
class DataWrapper>
109 absl::Status ProcessBoundsSection(
DataWrapper* data);
112 template <
class DataWrapper>
113 absl::Status ProcessIndicatorsSection(
DataWrapper* data);
116 absl::Status ProcessSosSection();
120 absl::StatusOr<double> GetDoubleFromString(
const std::string& str);
121 absl::StatusOr<bool> GetBoolFromString(
const std::string& str);
131 INFINITE_LOWER_BOUND,
132 INFINITE_UPPER_BOUND,
148 template <
class DataWrapper>
149 absl::Status StoreBound(
const std::string& bound_type_mnemonic,
150 const std::string& column_name,
151 const std::string& bound_value,
DataWrapper* data);
154 template <
class DataWrapper>
155 absl::Status StoreCoefficient(
int col,
const std::string& row_name,
156 const std::string& row_value,
160 template <
class DataWrapper>
161 absl::Status StoreRightHandSide(
const std::string& row_name,
162 const std::string& row_value,
166 template <
class DataWrapper>
167 absl::Status StoreRange(
const std::string& row_name,
168 const std::string& range_value,
DataWrapper* data);
172 absl::Status InvalidArgumentError(
const std::string& error_message);
176 absl::Status AppendLineToError(
const absl::Status& status);
182 std::vector<std::string> fields_;
185 std::string objective_name_;
208 absl::flat_hash_map<std::string, SectionId> section_name_to_id_map_;
211 absl::flat_hash_map<std::string, RowTypeId> row_name_to_id_map_;
214 absl::flat_hash_map<std::string, BoundTypeId> bound_name_to_id_map_;
217 absl::flat_hash_set<std::string> integer_type_names_set_;
227 std::vector<bool> is_binary_by_default_;
232 bool in_integer_section_;
237 int num_unconstrained_rows_;
253 data_->SetDcheckBounds(
false);
260 data_->SetMaximizationProblem(maximize);
264 return data_->FindOrCreateConstraint(
name).value();
271 data_->SetCoefficient(RowIndex(row_index), ColIndex(col_index),
276 <<
"LAZYCONS section detected. It will be handled as an extension of "
280 return data_->constraint_lower_bounds()[RowIndex(row_index)];
283 return data_->constraint_upper_bounds()[RowIndex(row_index)];
287 return data_->FindOrCreateVariable(
name).value();
290 data_->SetVariableType(ColIndex(
index),
294 LOG(
FATAL) <<
"Semi continuous variables are not supported";
303 return data_->IsVariableInteger(ColIndex(
index));
306 return data_->variable_lower_bounds()[ColIndex(
index)];
309 return data_->variable_upper_bounds()[ColIndex(
index)];
314 return absl::UnimplementedError(
315 "LinearProgram does not support indicator constraints.");
336 const auto it = constraint_indices_by_name_.find(
name);
337 if (it != constraint_indices_by_name_.end())
return it->second;
339 const int index = data_->constraint_size();
344 constraint_indices_by_name_[
name] =
index;
362 data_->mutable_constraint(row_index)->set_is_lazy(
true);
365 return data_->constraint(row_index).lower_bound();
368 return data_->constraint(row_index).upper_bound();
372 const auto it = variable_indices_by_name_.find(
name);
373 if (it != variable_indices_by_name_.end())
return it->second;
375 const int index = data_->variable_size();
383 data_->mutable_variable(
index)->set_is_integer(
true);
386 semi_continuous_variables_.push_back(
index);
396 return data_->variable(
index).is_integer();
399 return data_->variable(
index).lower_bound();
402 return data_->variable(
index).upper_bound();
407 const auto it = constraint_indices_by_name_.find(cst_name);
408 if (it == constraint_indices_by_name_.end()) {
409 return absl::InvalidArgumentError(
410 absl::StrCat(
"Constraint \"", cst_name,
"\" doesn't exist."));
412 const int cst_index = it->second;
415 data_->add_general_constraint();
417 absl::StrCat(
"ind_", data_->constraint(cst_index).name()));
423 constraints_to_delete_.insert(cst_index);
425 return absl::OkStatus();
430 constraints_to_delete_);
432 for (
const int index : semi_continuous_variables_) {
443 const int bool_var_index = data_->variable_size();
453 data_->add_general_constraint();
465 data_->add_general_constraint();
499 absl::flat_hash_map<std::string, int> variable_indices_by_name_;
500 absl::flat_hash_map<std::string, int> constraint_indices_by_name_;
501 absl::btree_set<int> constraints_to_delete_;
502 std::vector<int> semi_continuous_variables_;
508 if (data ==
nullptr) {
509 return absl::InvalidArgumentError(
"NULL pointer passed as argument.");
514 return absl::OkStatus();
523 data_wrapper.SetUp();
524 for (
const std::string& line :
528 data_wrapper.CleanUp();
530 return absl::OkStatus();
533template <
class DataWrapper>
534absl::Status MPSReaderImpl::ProcessLine(
const std::string& line,
538 if (IsCommentOrBlank()) {
539 return absl::OkStatus();
541 if (!free_form_ && absl::StrContains(line_,
'\t')) {
542 return InvalidArgumentError(
"File contains tabs.");
545 if (line[0] !=
'\0' && line[0] !=
' ') {
546 section = GetFirstWord();
549 if (section_ == UNKNOWN_SECTION) {
550 return InvalidArgumentError(
"Unknown section.");
552 if (section_ == COMMENT) {
553 return absl::OkStatus();
555 if (section_ == OBJSENSE) {
556 return absl::OkStatus();
558 if (section_ == NAME) {
567 if (fields_.size() >= 2) {
568 data->SetName(fields_[1]);
571 const std::vector<std::string> free_fields =
572 absl::StrSplit(line_, absl::ByAnyChar(
" \t"), absl::SkipEmpty());
573 const std::string free_name =
574 free_fields.size() >= 2 ? free_fields[1] :
"";
575 const std::string fixed_name = fields_.size() >= 3 ? fields_[2] :
"";
576 if (free_name != fixed_name) {
577 return InvalidArgumentError(
578 "Fixed form invalid: name differs between free and fixed "
581 data->SetName(fixed_name);
584 return absl::OkStatus();
589 return InvalidArgumentError(
"Second NAME field.");
591 return ProcessObjectiveSenseSection(data);
593 return ProcessRowsSection(
false, data);
595 return ProcessRowsSection(
true, data);
597 return ProcessColumnsSection(data);
599 return ProcessRhsSection(data);
601 return ProcessRangesSection(data);
603 return ProcessBoundsSection(data);
605 return ProcessIndicatorsSection(data);
607 return ProcessSosSection();
611 return InvalidArgumentError(
"Unknown section.");
613 return absl::OkStatus();
616template <
class DataWrapper>
617absl::Status MPSReaderImpl::ProcessObjectiveSenseSection(DataWrapper* data) {
618 if (fields_.size() != 1 && fields_[0] !=
"MIN" && fields_[0] !=
"MAX") {
619 return InvalidArgumentError(
"Expected objective sense (MAX or MIN).");
621 data->SetObjectiveDirection(fields_[0] ==
"MAX");
622 return absl::OkStatus();
625template <
class DataWrapper>
626absl::Status MPSReaderImpl::ProcessRowsSection(
bool is_lazy,
628 if (fields_.size() < 2) {
629 return InvalidArgumentError(
"Not enough fields in ROWS section.");
631 const std::string row_type_name = fields_[0];
632 const std::string row_name = fields_[1];
635 if (row_type == UNKNOWN_ROW_TYPE) {
636 return InvalidArgumentError(
"Unknown row type.");
640 if (objective_name_.empty() && row_type == NONE) {
641 row_type = OBJECTIVE;
642 objective_name_ = row_name;
644 if (row_type == NONE) {
645 ++num_unconstrained_rows_;
647 const int row = data->FindOrCreateConstraint(row_name);
648 if (is_lazy) data->SetIsLazy(
row);
655 data->ConstraintUpperBound(
row));
658 data->SetConstraintBounds(
row, data->ConstraintLowerBound(
row),
669 return absl::OkStatus();
672template <
class DataWrapper>
673absl::Status MPSReaderImpl::ProcessColumnsSection(DataWrapper* data) {
675 if (absl::StrContains(line_,
"'MARKER'")) {
676 if (absl::StrContains(line_,
"'INTORG'")) {
677 VLOG(2) <<
"Entering integer marker.\n" << line_;
678 if (in_integer_section_) {
679 return InvalidArgumentError(
"Found INTORG inside the integer section.");
681 in_integer_section_ =
true;
682 }
else if (absl::StrContains(line_,
"'INTEND'")) {
683 VLOG(2) <<
"Leaving integer marker.\n" << line_;
684 if (!in_integer_section_) {
685 return InvalidArgumentError(
686 "Found INTEND without corresponding INTORG.");
688 in_integer_section_ =
false;
690 return absl::OkStatus();
692 const int start_index = free_form_ ? 0 : 1;
693 if (fields_.size() < start_index + 3) {
694 return InvalidArgumentError(
"Not enough fields in COLUMNS section.");
696 const std::string& column_name = GetField(start_index, 0);
697 const std::string& row1_name = GetField(start_index, 1);
698 const std::string& row1_value = GetField(start_index, 2);
699 const int col = data->FindOrCreateVariable(column_name);
700 is_binary_by_default_.resize(
col + 1,
false);
701 if (in_integer_section_) {
702 data->SetVariableTypeToInteger(
col);
704 data->SetVariableBounds(
col, 0.0, 1.0);
705 is_binary_by_default_[
col] =
true;
710 if (fields_.size() == start_index + 4) {
711 return InvalidArgumentError(
"Unexpected number of fields.");
713 if (fields_.size() - start_index > 4) {
714 const std::string& row2_name = GetField(start_index, 3);
715 const std::string& row2_value = GetField(start_index, 4);
718 return absl::OkStatus();
721template <
class DataWrapper>
722absl::Status MPSReaderImpl::ProcessRhsSection(DataWrapper* data) {
723 const int start_index = free_form_ ? 0 : 2;
724 const int offset = start_index + GetFieldOffset();
725 if (fields_.size() < offset + 2) {
726 return InvalidArgumentError(
"Not enough fields in RHS section.");
729 const std::string& row1_name = GetField(offset, 0);
730 const std::string& row1_value = GetField(offset, 1);
732 if (fields_.size() - start_index >= 4) {
733 const std::string& row2_name = GetField(offset, 2);
734 const std::string& row2_value = GetField(offset, 3);
737 return absl::OkStatus();
740template <
class DataWrapper>
741absl::Status MPSReaderImpl::ProcessRangesSection(DataWrapper* data) {
742 const int start_index = free_form_ ? 0 : 2;
743 const int offset = start_index + GetFieldOffset();
744 if (fields_.size() < offset + 2) {
745 return InvalidArgumentError(
"Not enough fields in RHS section.");
748 const std::string& row1_name = GetField(offset, 0);
749 const std::string& row1_value = GetField(offset, 1);
751 if (fields_.size() - start_index >= 4) {
752 const std::string& row2_name = GetField(offset, 2);
753 const std::string& row2_value = GetField(offset, 3);
756 return absl::OkStatus();
759template <
class DataWrapper>
760absl::Status MPSReaderImpl::ProcessBoundsSection(DataWrapper* data) {
761 if (fields_.size() < 3) {
762 return InvalidArgumentError(
"Not enough fields in BOUNDS section.");
764 const std::string bound_type_mnemonic = fields_[0];
765 const std::string bound_row_name = fields_[1];
766 const std::string column_name = fields_[2];
767 std::string bound_value;
768 if (fields_.size() >= 4) {
769 bound_value = fields_[3];
771 return StoreBound(bound_type_mnemonic, column_name, bound_value, data);
774template <
class DataWrapper>
775absl::Status MPSReaderImpl::ProcessIndicatorsSection(DataWrapper* data) {
779 if (fields_.size() < 4) {
780 return InvalidArgumentError(
"Not enough fields in INDICATORS section.");
783 const std::string type = fields_[0];
785 return InvalidArgumentError(
786 "Indicator constraints must start with \"IF\".");
788 const std::string row_name = fields_[1];
789 const std::string column_name = fields_[2];
790 const std::string column_value = fields_[3];
795 const int col = data->FindOrCreateVariable(column_name);
797 data->SetVariableTypeToInteger(
col);
798 data->SetVariableBounds(
col,
std::max(0.0, data->VariableLowerBound(
col)),
802 AppendLineToError(data->CreateIndicatorConstraint(row_name,
col,
value)));
804 return absl::OkStatus();
807template <
class DataWrapper>
808absl::Status MPSReaderImpl::StoreCoefficient(
int col,
809 const std::string& row_name,
810 const std::string& row_value,
812 if (row_name.empty() || row_name ==
"$") {
813 return absl::OkStatus();
819 return InvalidArgumentError(
"Constraint coefficients cannot be infinity.");
821 if (
value == 0.0)
return absl::OkStatus();
822 if (row_name == objective_name_) {
823 data->SetObjectiveCoefficient(
col,
value);
825 const int row = data->FindOrCreateConstraint(row_name);
828 return absl::OkStatus();
831template <
class DataWrapper>
832absl::Status MPSReaderImpl::StoreRightHandSide(
const std::string& row_name,
833 const std::string& row_value,
835 if (row_name.empty())
return absl::OkStatus();
837 if (row_name != objective_name_) {
838 const int row = data->FindOrCreateConstraint(row_name);
851 return absl::OkStatus();
854template <
class DataWrapper>
855absl::Status MPSReaderImpl::StoreRange(
const std::string& row_name,
856 const std::string& range_value,
858 if (row_name.empty())
return absl::OkStatus();
860 const int row = data->FindOrCreateConstraint(row_name);
880 return absl::OkStatus();
883template <
class DataWrapper>
884absl::Status MPSReaderImpl::StoreBound(
const std::string& bound_type_mnemonic,
885 const std::string& column_name,
886 const std::string& bound_value,
889 bound_name_to_id_map_, bound_type_mnemonic, UNKNOWN_BOUND_TYPE);
890 if (bound_type_id == UNKNOWN_BOUND_TYPE) {
891 return InvalidArgumentError(
"Unknown bound type.");
893 const int col = data->FindOrCreateVariable(column_name);
894 if (integer_type_names_set_.count(bound_type_mnemonic) != 0) {
895 data->SetVariableTypeToInteger(
col);
897 if (is_binary_by_default_.size() <=
col) {
899 is_binary_by_default_.resize(
col + 1,
false);
902 DCHECK(!is_binary_by_default_[
col] || data->VariableIsInteger(
col));
908 if (is_binary_by_default_[
col]) {
912 switch (bound_type_id) {
916 if (bound_type_mnemonic ==
"LI" &&
lower_bound == 0.0) {
925 case SEMI_CONTINUOUS: {
927 data->SetVariableTypeToSemiContinuous(
col);
930 case FIXED_VARIABLE: {
939 case INFINITE_LOWER_BOUND:
942 case INFINITE_UPPER_BOUND:
949 case UNKNOWN_BOUND_TYPE:
951 return InvalidArgumentError(
"Unknown bound type.");
953 is_binary_by_default_[
col] =
false;
955 return absl::OkStatus();
958const int MPSReaderImpl::kNumFields = 6;
959const int MPSReaderImpl::kFieldStartPos[kNumFields] = {1, 4, 14, 24, 39, 49};
960const int MPSReaderImpl::kFieldLength[kNumFields] = {2, 8, 8, 12, 8, 12};
961const int MPSReaderImpl::kSpacePos[12] = {12, 13, 22, 23, 36, 37,
962 38, 47, 48, 61, 62, 63};
967 section_(UNKNOWN_SECTION),
968 section_name_to_id_map_(),
969 row_name_to_id_map_(),
970 bound_name_to_id_map_(),
971 integer_type_names_set_(),
974 in_integer_section_(false),
975 num_unconstrained_rows_(0) {
976 section_name_to_id_map_[
"*"] = COMMENT;
977 section_name_to_id_map_[
"NAME"] = NAME;
978 section_name_to_id_map_[
"OBJSENSE"] = OBJSENSE;
979 section_name_to_id_map_[
"ROWS"] = ROWS;
980 section_name_to_id_map_[
"LAZYCONS"] = LAZYCONS;
981 section_name_to_id_map_[
"COLUMNS"] = COLUMNS;
982 section_name_to_id_map_[
"RHS"] = RHS;
983 section_name_to_id_map_[
"RANGES"] = RANGES;
984 section_name_to_id_map_[
"BOUNDS"] = BOUNDS;
985 section_name_to_id_map_[
"INDICATORS"] = INDICATORS;
986 section_name_to_id_map_[
"ENDATA"] = ENDATA;
987 row_name_to_id_map_[
"E"] = EQUALITY;
988 row_name_to_id_map_[
"L"] = LESS_THAN;
989 row_name_to_id_map_[
"G"] = GREATER_THAN;
990 row_name_to_id_map_[
"N"] = NONE;
991 bound_name_to_id_map_[
"LO"] = LOWER_BOUND;
992 bound_name_to_id_map_[
"UP"] = UPPER_BOUND;
993 bound_name_to_id_map_[
"FX"] = FIXED_VARIABLE;
994 bound_name_to_id_map_[
"FR"] = FREE_VARIABLE;
995 bound_name_to_id_map_[
"MI"] = INFINITE_LOWER_BOUND;
996 bound_name_to_id_map_[
"PL"] = INFINITE_UPPER_BOUND;
997 bound_name_to_id_map_[
"BV"] = BINARY;
998 bound_name_to_id_map_[
"LI"] = LOWER_BOUND;
999 bound_name_to_id_map_[
"UI"] = UPPER_BOUND;
1000 bound_name_to_id_map_[
"SC"] = SEMI_CONTINUOUS;
1002 integer_type_names_set_.insert(
"BV");
1003 integer_type_names_set_.insert(
"LI");
1004 integer_type_names_set_.insert(
"UI");
1007void MPSReaderImpl::Reset() {
1008 fields_.resize(kNumFields);
1010 in_integer_section_ =
false;
1011 num_unconstrained_rows_ = 0;
1012 objective_name_.clear();
1015void MPSReaderImpl::DisplaySummary() {
1016 if (num_unconstrained_rows_ > 0) {
1017 VLOG(1) <<
"There are " << num_unconstrained_rows_ + 1
1018 <<
" unconstrained rows. The first of them (" << objective_name_
1019 <<
") was used as the objective.";
1023bool MPSReaderImpl::IsFixedFormat() {
1024 for (
const int i : kSpacePos) {
1025 if (i >= line_.length())
break;
1026 if (line_[i] !=
' ')
return false;
1031absl::Status MPSReaderImpl::SplitLineIntoFields() {
1033 fields_ = absl::StrSplit(line_, absl::ByAnyChar(
" \t"), absl::SkipEmpty());
1034 if (fields_.size() > kNumFields) {
1035 return InvalidArgumentError(
"Found too many fields.");
1042 if (section_ != NAME && !IsFixedFormat()) {
1043 return InvalidArgumentError(
"Line is not in fixed format.");
1045 const int length = line_.length();
1046 for (
int i = 0; i < kNumFields; ++i) {
1047 if (kFieldStartPos[i] < length) {
1048 fields_[i] = line_.substr(kFieldStartPos[i], kFieldLength[i]);
1049 fields_[i].erase(fields_[i].find_last_not_of(
" ") + 1);
1055 return absl::OkStatus();
1058std::string MPSReaderImpl::GetFirstWord()
const {
1059 if (line_[0] ==
' ') {
1060 return std::string(
"");
1062 const int first_space_pos = line_.find(
' ');
1063 const std::string first_word = line_.substr(0, first_space_pos);
1067bool MPSReaderImpl::IsCommentOrBlank()
const {
1068 const char* line = line_.c_str();
1072 for (; *line !=
'\0'; ++line) {
1073 if (*line !=
' ' && *line !=
'\t') {
1080absl::StatusOr<double> MPSReaderImpl::GetDoubleFromString(
1081 const std::string& str) {
1083 if (!absl::SimpleAtod(str, &result)) {
1084 return InvalidArgumentError(
1085 absl::StrCat(
"Failed to convert \"", str,
"\" to double."));
1087 if (std::isnan(result)) {
1088 return InvalidArgumentError(
"Found NaN value.");
1093absl::StatusOr<bool> MPSReaderImpl::GetBoolFromString(
const std::string& str) {
1095 if (!absl::SimpleAtoi(str, &result) || result < 0 || result > 1) {
1096 return InvalidArgumentError(
1097 absl::StrCat(
"Failed to convert \"", str,
"\" to bool."));
1102absl::Status MPSReaderImpl::ProcessSosSection() {
1103 return InvalidArgumentError(
"Section SOS currently not supported.");
1106absl::Status MPSReaderImpl::InvalidArgumentError(
1107 const std::string& error_message) {
1108 return AppendLineToError(absl::InvalidArgumentError(error_message));
1111absl::Status MPSReaderImpl::AppendLineToError(
const absl::Status& status) {
1113 <<
" 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)