22 #include "absl/container/btree_set.h"
23 #include "absl/status/status.h"
24 #include "absl/status/statusor.h"
25 #include "absl/strings/match.h"
26 #include "absl/strings/str_split.h"
41 absl::Status
ParseFile(
const std::string& file_name, Data* data,
42 MPSReader::Form form);
48 MPSReader::Form form);
52 static const int kNumFields;
55 static const int kFieldStartPos[];
58 static const int kFieldLength[];
61 static const int kSpacePos[];
67 void DisplaySummary();
70 absl::Status SplitLineIntoFields();
76 std::string GetFirstWord()
const;
80 bool IsCommentOrBlank()
const;
83 const std::string& GetField(
int offset,
int index)
const {
84 return fields_[offset +
index];
92 int GetFieldOffset()
const {
return free_form_ ? fields_.size() & 1 : 0; }
95 template <
class DataWrapper>
99 template <
class DataWrapper>
100 absl::Status ProcessObjectiveSenseSection(
DataWrapper* data);
103 template <
class DataWrapper>
104 absl::Status ProcessRowsSection(
bool is_lazy,
DataWrapper* data);
107 template <
class DataWrapper>
108 absl::Status ProcessColumnsSection(
DataWrapper* data);
111 template <
class DataWrapper>
115 template <
class DataWrapper>
116 absl::Status ProcessRangesSection(
DataWrapper* data);
119 template <
class DataWrapper>
120 absl::Status ProcessBoundsSection(
DataWrapper* data);
123 template <
class DataWrapper>
124 absl::Status ProcessIndicatorsSection(
DataWrapper* data);
127 absl::Status ProcessSosSection();
131 absl::StatusOr<double> GetDoubleFromString(
const std::string& str);
132 absl::StatusOr<bool> GetBoolFromString(
const std::string& str);
142 INFINITE_LOWER_BOUND,
143 INFINITE_UPPER_BOUND,
159 template <
class DataWrapper>
160 absl::Status StoreBound(
const std::string& bound_type_mnemonic,
161 const std::string& column_name,
162 const std::string& bound_value,
DataWrapper* data);
165 template <
class DataWrapper>
166 absl::Status StoreCoefficient(
int col,
const std::string& row_name,
167 const std::string& row_value,
171 template <
class DataWrapper>
172 absl::Status StoreRightHandSide(
const std::string& row_name,
173 const std::string& row_value,
177 template <
class DataWrapper>
178 absl::Status StoreRange(
const std::string& row_name,
179 const std::string& range_value,
DataWrapper* data);
183 absl::Status InvalidArgumentError(
const std::string& error_message);
187 absl::Status AppendLineToError(
const absl::Status&
status);
193 std::vector<std::string> fields_;
196 std::string objective_name_;
219 absl::flat_hash_map<std::string, SectionId> section_name_to_id_map_;
222 absl::flat_hash_map<std::string, RowTypeId> row_name_to_id_map_;
225 absl::flat_hash_map<std::string, BoundTypeId> bound_name_to_id_map_;
228 absl::flat_hash_set<std::string> integer_type_names_set_;
238 std::vector<bool> is_binary_by_default_;
243 bool in_integer_section_;
248 int num_unconstrained_rows_;
255 template <
class Data>
264 data_->SetDcheckBounds(
false);
271 data_->SetMaximizationProblem(maximize);
275 data_->SetObjectiveOffset(objective_offset);
279 return data_->FindOrCreateConstraint(
name).value();
286 data_->SetCoefficient(RowIndex(row_index), ColIndex(col_index),
290 LOG_FIRST_N(WARNING, 1)
291 <<
"LAZYCONS section detected. It will be handled as an extension of "
295 return data_->constraint_lower_bounds()[RowIndex(row_index)];
298 return data_->constraint_upper_bounds()[RowIndex(row_index)];
302 return data_->FindOrCreateVariable(
name).value();
305 data_->SetVariableType(ColIndex(
index),
309 LOG(FATAL) <<
"Semi continuous variables are not supported";
318 return data_->IsVariableInteger(ColIndex(
index));
321 return data_->variable_lower_bounds()[ColIndex(
index)];
324 return data_->variable_upper_bounds()[ColIndex(
index)];
329 return absl::UnimplementedError(
330 "LinearProgram does not support indicator constraints.");
351 data_->set_objective_offset(objective_offset);
355 const auto it = constraint_indices_by_name_.find(
name);
356 if (it != constraint_indices_by_name_.end())
return it->second;
358 const int index = data_->constraint_size();
359 MPConstraintProto*
const constraint = data_->add_constraint();
360 constraint->set_lower_bound(0.0);
361 constraint->set_upper_bound(0.0);
362 constraint->set_name(
name);
363 constraint_indices_by_name_[
name] =
index;
376 MPConstraintProto*
const constraint = data_->mutable_constraint(row_index);
377 constraint->add_var_index(col_index);
381 data_->mutable_constraint(row_index)->set_is_lazy(
true);
384 return data_->constraint(row_index).lower_bound();
387 return data_->constraint(row_index).upper_bound();
391 const auto it = variable_indices_by_name_.find(
name);
392 if (it != variable_indices_by_name_.end())
return it->second;
394 const int index = data_->variable_size();
395 MPVariableProto*
const variable = data_->add_variable();
396 variable->set_lower_bound(0.0);
397 variable->set_name(
name);
402 data_->mutable_variable(
index)->set_is_integer(
true);
405 semi_continuous_variables_.push_back(
index);
415 return data_->variable(
index).is_integer();
418 return data_->variable(
index).lower_bound();
421 return data_->variable(
index).upper_bound();
426 const auto it = constraint_indices_by_name_.find(cst_name);
427 if (it == constraint_indices_by_name_.end()) {
428 return absl::InvalidArgumentError(
429 absl::StrCat(
"Constraint \"", cst_name,
"\" doesn't exist."));
431 const int cst_index = it->second;
433 MPGeneralConstraintProto*
const constraint =
434 data_->add_general_constraint();
435 constraint->set_name(
436 absl::StrCat(
"ind_", data_->constraint(cst_index).name()));
437 MPIndicatorConstraint*
const indicator =
438 constraint->mutable_indicator_constraint();
439 *indicator->mutable_constraint() = data_->constraint(cst_index);
440 indicator->set_var_index(var_index);
441 indicator->set_var_value(var_value);
442 constraints_to_delete_.insert(cst_index);
444 return absl::OkStatus();
449 constraints_to_delete_);
451 for (
const int index : semi_continuous_variables_) {
452 MPVariableProto* mp_var = data_->mutable_variable(
index);
456 mp_var->lower_bound() == 0 ? 1.0 : mp_var->lower_bound();
458 const double ub = mp_var->upper_bound();
459 mp_var->set_lower_bound(0.0);
462 const int bool_var_index = data_->variable_size();
463 MPVariableProto* bool_var = data_->add_variable();
464 bool_var->set_lower_bound(0.0);
465 bool_var->set_upper_bound(1.0);
466 bool_var->set_is_integer(
true);
471 MPGeneralConstraintProto*
const zero_constraint =
472 data_->add_general_constraint();
473 MPIndicatorConstraint*
const zero_indicator =
474 zero_constraint->mutable_indicator_constraint();
475 zero_indicator->set_var_index(bool_var_index);
476 zero_indicator->set_var_value(0);
477 zero_indicator->mutable_constraint()->set_lower_bound(0.0);
478 zero_indicator->mutable_constraint()->set_upper_bound(0.0);
479 zero_indicator->mutable_constraint()->add_var_index(
index);
480 zero_indicator->mutable_constraint()->add_coefficient(1.0);
483 MPGeneralConstraintProto*
const one_constraint =
484 data_->add_general_constraint();
485 MPIndicatorConstraint*
const one_indicator =
486 one_constraint->mutable_indicator_constraint();
487 one_indicator->set_var_index(bool_var_index);
488 one_indicator->set_var_value(1);
489 one_indicator->mutable_constraint()->set_lower_bound(lb);
490 one_indicator->mutable_constraint()->set_upper_bound(ub);
491 one_indicator->mutable_constraint()->add_var_index(
index);
492 one_indicator->mutable_constraint()->add_coefficient(1.0);
495 MPConstraintProto*
lower = data_->add_constraint();
496 lower->set_lower_bound(0.0);
497 lower->set_upper_bound(std::numeric_limits<double>::infinity());
499 lower->add_coefficient(1.0);
500 lower->add_var_index(bool_var_index);
501 lower->add_coefficient(-lb);
504 MPConstraintProto*
upper = data_->add_constraint();
505 upper->set_lower_bound(-std::numeric_limits<double>::infinity());
506 upper->set_upper_bound(0.0);
508 upper->add_coefficient(1.0);
509 upper->add_var_index(bool_var_index);
510 upper->add_coefficient(-ub);
518 absl::flat_hash_map<std::string, int> variable_indices_by_name_;
519 absl::flat_hash_map<std::string, int> constraint_indices_by_name_;
520 absl::btree_set<int> constraints_to_delete_;
521 std::vector<int> semi_continuous_variables_;
524 template <
class Data>
526 MPSReader::Form form) {
527 if (data ==
nullptr) {
528 return absl::InvalidArgumentError(
"NULL pointer passed as argument.");
531 if (form == MPSReader::AUTO_DETECT) {
532 if (
ParseFile(file_name, data, MPSReader::FIXED).ok()) {
533 return absl::OkStatus();
535 return ParseFile(file_name, data, MPSReader::FREE);
538 free_form_ = form == MPSReader::FREE;
541 data_wrapper.SetUp();
544 for (
const absl::string_view
line :
548 data_wrapper.CleanUp();
550 return absl::OkStatus();
553 template <
class Data>
556 MPSReader::Form form) {
557 if (form == MPSReader::AUTO_DETECT) {
559 return absl::OkStatus();
564 free_form_ = form == MPSReader::FREE;
567 data_wrapper.SetUp();
568 for (absl::string_view
line : absl::StrSplit(source,
'\n')) {
571 data_wrapper.CleanUp();
573 return absl::OkStatus();
576 template <
class DataWrapper>
577 absl::Status MPSReaderImpl::ProcessLine(absl::string_view
line,
581 absl::ConsumeSuffix(&
line,
"\r");
582 line_ = std::string(
line);
583 if (IsCommentOrBlank()) {
584 return absl::OkStatus();
586 if (!free_form_ && absl::StrContains(line_,
'\t')) {
587 return InvalidArgumentError(
"File contains tabs.");
590 if (
line[0] !=
'\0' &&
line[0] !=
' ') {
591 section = GetFirstWord();
594 if (section_ == UNKNOWN_SECTION) {
595 return InvalidArgumentError(
"Unknown section.");
597 if (section_ == COMMENT) {
598 return absl::OkStatus();
600 if (section_ == OBJSENSE) {
601 return absl::OkStatus();
603 if (section_ == NAME) {
612 if (fields_.size() >= 2) {
613 data->SetName(fields_[1]);
616 const std::vector<std::string> free_fields =
617 absl::StrSplit(line_, absl::ByAnyChar(
" \t"), absl::SkipEmpty());
618 const std::string free_name =
619 free_fields.size() >= 2 ? free_fields[1] :
"";
620 const std::string fixed_name = fields_.size() >= 3 ? fields_[2] :
"";
621 if (free_name != fixed_name) {
622 return InvalidArgumentError(
623 "Fixed form invalid: name differs between free and fixed "
626 data->SetName(fixed_name);
629 return absl::OkStatus();
634 return InvalidArgumentError(
"Second NAME field.");
636 return ProcessObjectiveSenseSection(data);
638 return ProcessRowsSection(
false, data);
640 return ProcessRowsSection(
true, data);
642 return ProcessColumnsSection(data);
644 return ProcessRhsSection(data);
646 return ProcessRangesSection(data);
648 return ProcessBoundsSection(data);
650 return ProcessIndicatorsSection(data);
652 return ProcessSosSection();
656 return InvalidArgumentError(
"Unknown section.");
658 return absl::OkStatus();
661 template <
class DataWrapper>
662 absl::Status MPSReaderImpl::ProcessObjectiveSenseSection(DataWrapper* data) {
663 if (fields_.size() != 1 && fields_[0] !=
"MIN" && fields_[0] !=
"MAX") {
664 return InvalidArgumentError(
"Expected objective sense (MAX or MIN).");
666 data->SetObjectiveDirection(fields_[0] ==
"MAX");
667 return absl::OkStatus();
670 template <
class DataWrapper>
671 absl::Status MPSReaderImpl::ProcessRowsSection(
bool is_lazy,
673 if (fields_.size() < 2) {
674 return InvalidArgumentError(
"Not enough fields in ROWS section.");
676 const std::string row_type_name = fields_[0];
677 const std::string row_name = fields_[1];
680 if (row_type == UNKNOWN_ROW_TYPE) {
681 return InvalidArgumentError(
"Unknown row type.");
685 if (objective_name_.empty() && row_type == NONE) {
686 row_type = OBJECTIVE;
687 objective_name_ = row_name;
689 if (row_type == NONE) {
690 ++num_unconstrained_rows_;
692 const int row = data->FindOrCreateConstraint(row_name);
693 if (is_lazy) data->SetIsLazy(
row);
700 data->ConstraintUpperBound(
row));
703 data->SetConstraintBounds(
row, data->ConstraintLowerBound(
row),
714 return absl::OkStatus();
717 template <
class DataWrapper>
718 absl::Status MPSReaderImpl::ProcessColumnsSection(DataWrapper* data) {
720 if (absl::StrContains(line_,
"'MARKER'")) {
721 if (absl::StrContains(line_,
"'INTORG'")) {
722 VLOG(2) <<
"Entering integer marker.\n" << line_;
723 if (in_integer_section_) {
724 return InvalidArgumentError(
"Found INTORG inside the integer section.");
726 in_integer_section_ =
true;
727 }
else if (absl::StrContains(line_,
"'INTEND'")) {
728 VLOG(2) <<
"Leaving integer marker.\n" << line_;
729 if (!in_integer_section_) {
730 return InvalidArgumentError(
731 "Found INTEND without corresponding INTORG.");
733 in_integer_section_ =
false;
735 return absl::OkStatus();
737 const int start_index = free_form_ ? 0 : 1;
738 if (fields_.size() < start_index + 3) {
739 return InvalidArgumentError(
"Not enough fields in COLUMNS section.");
741 const std::string& column_name = GetField(start_index, 0);
742 const std::string& row1_name = GetField(start_index, 1);
743 const std::string& row1_value = GetField(start_index, 2);
744 const int col = data->FindOrCreateVariable(column_name);
745 is_binary_by_default_.resize(
col + 1,
false);
746 if (in_integer_section_) {
747 data->SetVariableTypeToInteger(
col);
749 data->SetVariableBounds(
col, 0.0, 1.0);
750 is_binary_by_default_[
col] =
true;
755 if (fields_.size() == start_index + 4) {
756 return InvalidArgumentError(
"Unexpected number of fields.");
758 if (fields_.size() - start_index > 4) {
759 const std::string& row2_name = GetField(start_index, 3);
760 const std::string& row2_value = GetField(start_index, 4);
763 return absl::OkStatus();
766 template <
class DataWrapper>
767 absl::Status MPSReaderImpl::ProcessRhsSection(DataWrapper* data) {
768 const int start_index = free_form_ ? 0 : 2;
769 const int offset = start_index + GetFieldOffset();
770 if (fields_.size() < offset + 2) {
771 return InvalidArgumentError(
"Not enough fields in RHS section.");
774 const std::string& row1_name = GetField(offset, 0);
775 const std::string& row1_value = GetField(offset, 1);
777 if (fields_.size() - start_index >= 4) {
778 const std::string& row2_name = GetField(offset, 2);
779 const std::string& row2_value = GetField(offset, 3);
782 return absl::OkStatus();
785 template <
class DataWrapper>
786 absl::Status MPSReaderImpl::ProcessRangesSection(DataWrapper* data) {
787 const int start_index = free_form_ ? 0 : 2;
788 const int offset = start_index + GetFieldOffset();
789 if (fields_.size() < offset + 2) {
790 return InvalidArgumentError(
"Not enough fields in RHS section.");
793 const std::string& row1_name = GetField(offset, 0);
794 const std::string& row1_value = GetField(offset, 1);
796 if (fields_.size() - start_index >= 4) {
797 const std::string& row2_name = GetField(offset, 2);
798 const std::string& row2_value = GetField(offset, 3);
801 return absl::OkStatus();
804 template <
class DataWrapper>
805 absl::Status MPSReaderImpl::ProcessBoundsSection(DataWrapper* data) {
806 if (fields_.size() < 3) {
807 return InvalidArgumentError(
"Not enough fields in BOUNDS section.");
809 const std::string bound_type_mnemonic = fields_[0];
810 const std::string bound_row_name = fields_[1];
811 const std::string column_name = fields_[2];
812 std::string bound_value;
813 if (fields_.size() >= 4) {
814 bound_value = fields_[3];
816 return StoreBound(bound_type_mnemonic, column_name, bound_value, data);
819 template <
class DataWrapper>
820 absl::Status MPSReaderImpl::ProcessIndicatorsSection(DataWrapper* data) {
824 if (fields_.size() < 4) {
825 return InvalidArgumentError(
"Not enough fields in INDICATORS section.");
828 const std::string type = fields_[0];
830 return InvalidArgumentError(
831 "Indicator constraints must start with \"IF\".");
833 const std::string row_name = fields_[1];
834 const std::string column_name = fields_[2];
835 const std::string column_value = fields_[3];
840 const int col = data->FindOrCreateVariable(column_name);
842 data->SetVariableTypeToInteger(
col);
843 data->SetVariableBounds(
col,
std::max(0.0, data->VariableLowerBound(
col)),
847 AppendLineToError(data->CreateIndicatorConstraint(row_name,
col,
value)));
849 return absl::OkStatus();
852 template <
class DataWrapper>
853 absl::Status MPSReaderImpl::StoreCoefficient(
int col,
854 const std::string& row_name,
855 const std::string& row_value,
857 if (row_name.empty() || row_name ==
"$") {
858 return absl::OkStatus();
864 return InvalidArgumentError(
"Constraint coefficients cannot be infinity.");
866 if (
value == 0.0)
return absl::OkStatus();
867 if (row_name == objective_name_) {
868 data->SetObjectiveCoefficient(
col,
value);
870 const int row = data->FindOrCreateConstraint(row_name);
873 return absl::OkStatus();
876 template <
class DataWrapper>
877 absl::Status MPSReaderImpl::StoreRightHandSide(
const std::string& row_name,
878 const std::string& row_value,
880 if (row_name.empty())
return absl::OkStatus();
882 if (row_name != objective_name_) {
883 const int row = data->FindOrCreateConstraint(row_name);
901 data->SetObjectiveOffset(-
value);
903 return absl::OkStatus();
906 template <
class DataWrapper>
907 absl::Status MPSReaderImpl::StoreRange(
const std::string& row_name,
908 const std::string& range_value,
910 if (row_name.empty())
return absl::OkStatus();
912 const int row = data->FindOrCreateConstraint(row_name);
932 return absl::OkStatus();
935 template <
class DataWrapper>
936 absl::Status MPSReaderImpl::StoreBound(
const std::string& bound_type_mnemonic,
937 const std::string& column_name,
938 const std::string& bound_value,
941 bound_name_to_id_map_, bound_type_mnemonic, UNKNOWN_BOUND_TYPE);
942 if (bound_type_id == UNKNOWN_BOUND_TYPE) {
943 return InvalidArgumentError(
"Unknown bound type.");
945 const int col = data->FindOrCreateVariable(column_name);
946 if (integer_type_names_set_.count(bound_type_mnemonic) != 0) {
947 data->SetVariableTypeToInteger(
col);
949 if (is_binary_by_default_.size() <=
col) {
951 is_binary_by_default_.resize(
col + 1,
false);
954 DCHECK(!is_binary_by_default_[
col] || data->VariableIsInteger(
col));
960 if (is_binary_by_default_[
col]) {
964 switch (bound_type_id) {
968 if (bound_type_mnemonic ==
"LI" &&
lower_bound == 0.0) {
977 case SEMI_CONTINUOUS: {
979 data->SetVariableTypeToSemiContinuous(
col);
982 case FIXED_VARIABLE: {
991 case INFINITE_LOWER_BOUND:
994 case INFINITE_UPPER_BOUND:
1001 case UNKNOWN_BOUND_TYPE:
1003 return InvalidArgumentError(
"Unknown bound type.");
1005 is_binary_by_default_[
col] =
false;
1007 return absl::OkStatus();
1010 const int MPSReaderImpl::kNumFields = 6;
1011 const int MPSReaderImpl::kFieldStartPos[kNumFields] = {1, 4, 14, 24, 39, 49};
1012 const int MPSReaderImpl::kFieldLength[kNumFields] = {2, 8, 8, 12, 8, 12};
1013 const int MPSReaderImpl::kSpacePos[12] = {12, 13, 22, 23, 36, 37,
1014 38, 47, 48, 61, 62, 63};
1018 fields_(kNumFields),
1019 section_(UNKNOWN_SECTION),
1020 section_name_to_id_map_(),
1021 row_name_to_id_map_(),
1022 bound_name_to_id_map_(),
1023 integer_type_names_set_(),
1026 in_integer_section_(false),
1027 num_unconstrained_rows_(0) {
1028 section_name_to_id_map_[
"*"] = COMMENT;
1029 section_name_to_id_map_[
"NAME"] = NAME;
1030 section_name_to_id_map_[
"OBJSENSE"] = OBJSENSE;
1031 section_name_to_id_map_[
"ROWS"] = ROWS;
1032 section_name_to_id_map_[
"LAZYCONS"] = LAZYCONS;
1033 section_name_to_id_map_[
"COLUMNS"] = COLUMNS;
1034 section_name_to_id_map_[
"RHS"] = RHS;
1035 section_name_to_id_map_[
"RANGES"] = RANGES;
1036 section_name_to_id_map_[
"BOUNDS"] = BOUNDS;
1037 section_name_to_id_map_[
"INDICATORS"] = INDICATORS;
1038 section_name_to_id_map_[
"ENDATA"] = ENDATA;
1039 row_name_to_id_map_[
"E"] = EQUALITY;
1040 row_name_to_id_map_[
"L"] = LESS_THAN;
1041 row_name_to_id_map_[
"G"] = GREATER_THAN;
1042 row_name_to_id_map_[
"N"] = NONE;
1043 bound_name_to_id_map_[
"LO"] = LOWER_BOUND;
1044 bound_name_to_id_map_[
"UP"] = UPPER_BOUND;
1045 bound_name_to_id_map_[
"FX"] = FIXED_VARIABLE;
1046 bound_name_to_id_map_[
"FR"] = FREE_VARIABLE;
1047 bound_name_to_id_map_[
"MI"] = INFINITE_LOWER_BOUND;
1048 bound_name_to_id_map_[
"PL"] = INFINITE_UPPER_BOUND;
1049 bound_name_to_id_map_[
"BV"] = BINARY;
1050 bound_name_to_id_map_[
"LI"] = LOWER_BOUND;
1051 bound_name_to_id_map_[
"UI"] = UPPER_BOUND;
1052 bound_name_to_id_map_[
"SC"] = SEMI_CONTINUOUS;
1054 integer_type_names_set_.insert(
"BV");
1055 integer_type_names_set_.insert(
"LI");
1056 integer_type_names_set_.insert(
"UI");
1059 void MPSReaderImpl::Reset() {
1060 fields_.resize(kNumFields);
1062 in_integer_section_ =
false;
1063 num_unconstrained_rows_ = 0;
1064 objective_name_.clear();
1067 void MPSReaderImpl::DisplaySummary() {
1068 if (num_unconstrained_rows_ > 0) {
1069 VLOG(1) <<
"There are " << num_unconstrained_rows_ + 1
1070 <<
" unconstrained rows. The first of them (" << objective_name_
1071 <<
") was used as the objective.";
1075 bool MPSReaderImpl::IsFixedFormat() {
1076 for (
const int i : kSpacePos) {
1077 if (i >= line_.length())
break;
1078 if (line_[i] !=
' ')
return false;
1083 absl::Status MPSReaderImpl::SplitLineIntoFields() {
1085 fields_ = absl::StrSplit(line_, absl::ByAnyChar(
" \t"), absl::SkipEmpty());
1086 if (fields_.size() > kNumFields) {
1087 return InvalidArgumentError(
"Found too many fields.");
1094 if (section_ != NAME && !IsFixedFormat()) {
1095 return InvalidArgumentError(
"Line is not in fixed format.");
1097 const int length = line_.length();
1098 for (
int i = 0; i < kNumFields; ++i) {
1099 if (kFieldStartPos[i] < length) {
1100 fields_[i] = line_.substr(kFieldStartPos[i], kFieldLength[i]);
1101 fields_[i].erase(fields_[i].find_last_not_of(
" ") + 1);
1107 return absl::OkStatus();
1110 std::string MPSReaderImpl::GetFirstWord()
const {
1111 if (line_[0] ==
' ') {
1112 return std::string(
"");
1114 const int first_space_pos = line_.find(
' ');
1115 const std::string first_word = line_.substr(0, first_space_pos);
1119 bool MPSReaderImpl::IsCommentOrBlank()
const {
1120 const char*
line = line_.c_str();
1125 if (*
line !=
' ' && *
line !=
'\t') {
1132 absl::StatusOr<double> MPSReaderImpl::GetDoubleFromString(
1133 const std::string& str) {
1135 if (!absl::SimpleAtod(str, &result)) {
1136 return InvalidArgumentError(
1137 absl::StrCat(
"Failed to convert \"", str,
"\" to double."));
1139 if (std::isnan(result)) {
1140 return InvalidArgumentError(
"Found NaN value.");
1145 absl::StatusOr<bool> MPSReaderImpl::GetBoolFromString(
const std::string& str) {
1147 if (!absl::SimpleAtoi(str, &result) || result < 0 || result > 1) {
1148 return InvalidArgumentError(
1149 absl::StrCat(
"Failed to convert \"", str,
"\" to bool."));
1154 absl::Status MPSReaderImpl::ProcessSosSection() {
1155 return InvalidArgumentError(
"Section SOS currently not supported.");
1158 absl::Status MPSReaderImpl::InvalidArgumentError(
1159 const std::string& error_message) {
1160 return AppendLineToError(absl::InvalidArgumentError(error_message));
1163 absl::Status MPSReaderImpl::AppendLineToError(
const absl::Status&
status) {
1165 <<
" Line " << line_num_ <<
": \"" << line_ <<
"\".";
1170 LinearProgram* data, Form form) {
1171 return MPSReaderImpl().ParseFile(file_name, data, form);
1175 MPModelProto* data, Form form) {
1176 return MPSReaderImpl().ParseFile(file_name, data, form);
1181 absl::Status MPSReader::ParseProblemFromString(
const std::string& source,
1182 LinearProgram* data,
1183 MPSReader::Form form) {
1184 return MPSReaderImpl().ParseProblemFromString(source, data, form);
1187 absl::Status MPSReader::ParseProblemFromString(
const std::string& source,
1189 MPSReader::Form form) {
1190 return MPSReaderImpl().ParseProblemFromString(source, data, form);
1194 const std::string& mps_data) {
1197 mps_data, &
model, MPSReader::AUTO_DETECT));
1202 const std::string& mps_file) {
#define ASSIGN_OR_RETURN(lhs, rexpr)
#define RETURN_IF_ERROR(expr)
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 SetObjectiveOffset(double objective_offset)
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 SetObjectiveOffset(double objective_offset)
void SetVariableBounds(int index, double lower_bound, double upper_bound)
absl::Status ParseFile(const std::string &file_name, Data *data, MPSReader::Form form)
absl::Status ParseProblemFromString(const std::string &source, Data *data, MPSReader::Form form)
StatusBuilder & SetAppend()
absl::Status Open(const absl::string_view &filename, const absl::string_view &mode, File **f, int flags)
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)
void ParseFile(const std::string &filename, bool presolve)
constexpr double kInfinity
absl::StatusOr< MPModelProto > MpsDataToMPModelProto(const std::string &mps_data)
absl::StatusOr< MPModelProto > MpsFileToMPModelProto(const std::string &mps_file)
Collection of objects used to extend the Constraint Solver library.
const std::optional< Range > & range
#define VLOG(verboselevel)