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,
38 MPSReader::Form form);
44 MPSReader::Form form);
48 static const int kNumFields;
51 static const int kFieldStartPos[];
54 static const int kFieldLength[];
57 static const int kSpacePos[];
63 void DisplaySummary();
66 absl::Status SplitLineIntoFields();
72 std::string GetFirstWord()
const;
76 bool IsCommentOrBlank()
const;
79 const std::string& GetField(
int offset,
int index)
const {
80 return fields_[offset +
index];
88 int GetFieldOffset()
const {
return free_form_ ? fields_.size() & 1 : 0; }
91 template <
class DataWrapper>
92 absl::Status ProcessLine(absl::string_view line,
DataWrapper* data);
95 template <
class DataWrapper>
96 absl::Status ProcessObjectiveSenseSection(
DataWrapper* data);
99 template <
class DataWrapper>
100 absl::Status ProcessRowsSection(
bool is_lazy,
DataWrapper* data);
103 template <
class DataWrapper>
104 absl::Status ProcessColumnsSection(
DataWrapper* data);
107 template <
class DataWrapper>
111 template <
class DataWrapper>
112 absl::Status ProcessRangesSection(
DataWrapper* data);
115 template <
class DataWrapper>
116 absl::Status ProcessBoundsSection(
DataWrapper* data);
119 template <
class DataWrapper>
120 absl::Status ProcessIndicatorsSection(
DataWrapper* data);
123 absl::Status ProcessSosSection();
127 absl::StatusOr<double> GetDoubleFromString(
const std::string& str);
128 absl::StatusOr<bool> GetBoolFromString(
const std::string& str);
138 INFINITE_LOWER_BOUND,
139 INFINITE_UPPER_BOUND,
155 template <
class DataWrapper>
156 absl::Status StoreBound(
const std::string& bound_type_mnemonic,
157 const std::string& column_name,
158 const std::string& bound_value,
DataWrapper* data);
161 template <
class DataWrapper>
162 absl::Status StoreCoefficient(
int col,
const std::string& row_name,
163 const std::string& row_value,
167 template <
class DataWrapper>
168 absl::Status StoreRightHandSide(
const std::string& row_name,
169 const std::string& row_value,
173 template <
class DataWrapper>
174 absl::Status StoreRange(
const std::string& row_name,
175 const std::string& range_value,
DataWrapper* data);
179 absl::Status InvalidArgumentError(
const std::string& error_message);
183 absl::Status AppendLineToError(
const absl::Status&
status);
189 std::vector<std::string> fields_;
192 std::string objective_name_;
215 absl::flat_hash_map<std::string, SectionId> section_name_to_id_map_;
218 absl::flat_hash_map<std::string, RowTypeId> row_name_to_id_map_;
221 absl::flat_hash_map<std::string, BoundTypeId> bound_name_to_id_map_;
224 absl::flat_hash_set<std::string> integer_type_names_set_;
234 std::vector<bool> is_binary_by_default_;
239 bool in_integer_section_;
244 int num_unconstrained_rows_;
260 data_->SetDcheckBounds(
false);
267 data_->SetMaximizationProblem(maximize);
271 return data_->FindOrCreateConstraint(
name).value();
278 data_->SetCoefficient(RowIndex(row_index), ColIndex(col_index),
283 <<
"LAZYCONS section detected. It will be handled as an extension of "
287 return data_->constraint_lower_bounds()[RowIndex(row_index)];
290 return data_->constraint_upper_bounds()[RowIndex(row_index)];
294 return data_->FindOrCreateVariable(
name).value();
297 data_->SetVariableType(ColIndex(
index),
301 LOG(
FATAL) <<
"Semi continuous variables are not supported";
310 return data_->IsVariableInteger(ColIndex(
index));
313 return data_->variable_lower_bounds()[ColIndex(
index)];
316 return data_->variable_upper_bounds()[ColIndex(
index)];
321 return absl::UnimplementedError(
322 "LinearProgram does not support indicator constraints.");
343 const auto it = constraint_indices_by_name_.find(
name);
344 if (it != constraint_indices_by_name_.end())
return it->second;
346 const int index = data_->constraint_size();
347 MPConstraintProto*
const constraint = data_->add_constraint();
348 constraint->set_lower_bound(0.0);
349 constraint->set_upper_bound(0.0);
350 constraint->set_name(
name);
351 constraint_indices_by_name_[
name] =
index;
364 MPConstraintProto*
const constraint = data_->mutable_constraint(row_index);
365 constraint->add_var_index(col_index);
369 data_->mutable_constraint(row_index)->set_is_lazy(
true);
372 return data_->constraint(row_index).lower_bound();
375 return data_->constraint(row_index).upper_bound();
379 const auto it = variable_indices_by_name_.find(
name);
380 if (it != variable_indices_by_name_.end())
return it->second;
382 const int index = data_->variable_size();
383 MPVariableProto*
const variable = data_->add_variable();
384 variable->set_lower_bound(0.0);
385 variable->set_name(
name);
390 data_->mutable_variable(
index)->set_is_integer(
true);
393 semi_continuous_variables_.push_back(
index);
403 return data_->variable(
index).is_integer();
406 return data_->variable(
index).lower_bound();
409 return data_->variable(
index).upper_bound();
414 const auto it = constraint_indices_by_name_.find(cst_name);
415 if (it == constraint_indices_by_name_.end()) {
416 return absl::InvalidArgumentError(
417 absl::StrCat(
"Constraint \"", cst_name,
"\" doesn't exist."));
419 const int cst_index = it->second;
421 MPGeneralConstraintProto*
const constraint =
422 data_->add_general_constraint();
423 constraint->set_name(
424 absl::StrCat(
"ind_", data_->constraint(cst_index).name()));
425 MPIndicatorConstraint*
const indicator =
426 constraint->mutable_indicator_constraint();
427 *indicator->mutable_constraint() = data_->constraint(cst_index);
428 indicator->set_var_index(var_index);
429 indicator->set_var_value(var_value);
430 constraints_to_delete_.insert(cst_index);
432 return absl::OkStatus();
437 constraints_to_delete_);
439 for (
const int index : semi_continuous_variables_) {
440 MPVariableProto* mp_var = data_->mutable_variable(
index);
444 mp_var->lower_bound() == 0 ? 1.0 : mp_var->lower_bound();
446 const double ub = mp_var->upper_bound();
447 mp_var->set_lower_bound(0.0);
450 const int bool_var_index = data_->variable_size();
451 MPVariableProto* bool_var = data_->add_variable();
452 bool_var->set_lower_bound(0.0);
453 bool_var->set_upper_bound(1.0);
454 bool_var->set_is_integer(
true);
459 MPGeneralConstraintProto*
const zero_constraint =
460 data_->add_general_constraint();
461 MPIndicatorConstraint*
const zero_indicator =
462 zero_constraint->mutable_indicator_constraint();
463 zero_indicator->set_var_index(bool_var_index);
464 zero_indicator->set_var_value(0);
465 zero_indicator->mutable_constraint()->set_lower_bound(0.0);
466 zero_indicator->mutable_constraint()->set_upper_bound(0.0);
467 zero_indicator->mutable_constraint()->add_var_index(
index);
468 zero_indicator->mutable_constraint()->add_coefficient(1.0);
471 MPGeneralConstraintProto*
const one_constraint =
472 data_->add_general_constraint();
473 MPIndicatorConstraint*
const one_indicator =
474 one_constraint->mutable_indicator_constraint();
475 one_indicator->set_var_index(bool_var_index);
476 one_indicator->set_var_value(1);
477 one_indicator->mutable_constraint()->set_lower_bound(lb);
478 one_indicator->mutable_constraint()->set_upper_bound(ub);
479 one_indicator->mutable_constraint()->add_var_index(
index);
480 one_indicator->mutable_constraint()->add_coefficient(1.0);
483 MPConstraintProto*
lower = data_->add_constraint();
484 lower->set_lower_bound(0.0);
485 lower->set_upper_bound(std::numeric_limits<double>::infinity());
487 lower->add_coefficient(1.0);
488 lower->add_var_index(bool_var_index);
489 lower->add_coefficient(-lb);
492 MPConstraintProto*
upper = data_->add_constraint();
493 upper->set_lower_bound(-std::numeric_limits<double>::infinity());
494 upper->set_upper_bound(0.0);
496 upper->add_coefficient(1.0);
497 upper->add_var_index(bool_var_index);
498 upper->add_coefficient(-ub);
506 absl::flat_hash_map<std::string, int> variable_indices_by_name_;
507 absl::flat_hash_map<std::string, int> constraint_indices_by_name_;
508 absl::btree_set<int> constraints_to_delete_;
509 std::vector<int> semi_continuous_variables_;
514 MPSReader::Form form) {
515 if (data ==
nullptr) {
516 return absl::InvalidArgumentError(
"NULL pointer passed as argument.");
519 if (form == MPSReader::AUTO_DETECT) {
520 if (
ParseFile(file_name, data, MPSReader::FIXED).ok()) {
521 return absl::OkStatus();
523 return ParseFile(file_name, data, MPSReader::FREE);
526 free_form_ = form == MPSReader::FREE;
529 data_wrapper.SetUp();
530 for (absl::string_view line :
534 data_wrapper.CleanUp();
536 return absl::OkStatus();
542 MPSReader::Form form) {
543 if (form == MPSReader::AUTO_DETECT) {
545 return absl::OkStatus();
550 free_form_ = form == MPSReader::FREE;
553 data_wrapper.SetUp();
554 for (absl::string_view line : absl::StrSplit(source,
'\n')) {
557 data_wrapper.CleanUp();
559 return absl::OkStatus();
562template <
class DataWrapper>
563absl::Status MPSReaderImpl::ProcessLine(absl::string_view line,
567 if (IsCommentOrBlank()) {
568 return absl::OkStatus();
570 if (!free_form_ && absl::StrContains(line_,
'\t')) {
571 return InvalidArgumentError(
"File contains tabs.");
574 if (line[0] !=
'\0' && line[0] !=
' ') {
575 section = GetFirstWord();
578 if (section_ == UNKNOWN_SECTION) {
579 return InvalidArgumentError(
"Unknown section.");
581 if (section_ == COMMENT) {
582 return absl::OkStatus();
584 if (section_ == OBJSENSE) {
585 return absl::OkStatus();
587 if (section_ == NAME) {
596 if (fields_.size() >= 2) {
597 data->SetName(fields_[1]);
600 const std::vector<std::string> free_fields =
601 absl::StrSplit(line_, absl::ByAnyChar(
" \t"), absl::SkipEmpty());
602 const std::string free_name =
603 free_fields.size() >= 2 ? free_fields[1] :
"";
604 const std::string fixed_name = fields_.size() >= 3 ? fields_[2] :
"";
605 if (free_name != fixed_name) {
606 return InvalidArgumentError(
607 "Fixed form invalid: name differs between free and fixed "
610 data->SetName(fixed_name);
613 return absl::OkStatus();
618 return InvalidArgumentError(
"Second NAME field.");
620 return ProcessObjectiveSenseSection(data);
622 return ProcessRowsSection(
false, data);
624 return ProcessRowsSection(
true, data);
626 return ProcessColumnsSection(data);
628 return ProcessRhsSection(data);
630 return ProcessRangesSection(data);
632 return ProcessBoundsSection(data);
634 return ProcessIndicatorsSection(data);
636 return ProcessSosSection();
640 return InvalidArgumentError(
"Unknown section.");
642 return absl::OkStatus();
645template <
class DataWrapper>
646absl::Status MPSReaderImpl::ProcessObjectiveSenseSection(DataWrapper* data) {
647 if (fields_.size() != 1 && fields_[0] !=
"MIN" && fields_[0] !=
"MAX") {
648 return InvalidArgumentError(
"Expected objective sense (MAX or MIN).");
650 data->SetObjectiveDirection(fields_[0] ==
"MAX");
651 return absl::OkStatus();
654template <
class DataWrapper>
655absl::Status MPSReaderImpl::ProcessRowsSection(
bool is_lazy,
657 if (fields_.size() < 2) {
658 return InvalidArgumentError(
"Not enough fields in ROWS section.");
660 const std::string row_type_name = fields_[0];
661 const std::string row_name = fields_[1];
664 if (row_type == UNKNOWN_ROW_TYPE) {
665 return InvalidArgumentError(
"Unknown row type.");
669 if (objective_name_.empty() && row_type == NONE) {
670 row_type = OBJECTIVE;
671 objective_name_ = row_name;
673 if (row_type == NONE) {
674 ++num_unconstrained_rows_;
676 const int row = data->FindOrCreateConstraint(row_name);
677 if (is_lazy) data->SetIsLazy(
row);
684 data->ConstraintUpperBound(
row));
687 data->SetConstraintBounds(
row, data->ConstraintLowerBound(
row),
698 return absl::OkStatus();
701template <
class DataWrapper>
702absl::Status MPSReaderImpl::ProcessColumnsSection(DataWrapper* data) {
704 if (absl::StrContains(line_,
"'MARKER'")) {
705 if (absl::StrContains(line_,
"'INTORG'")) {
706 VLOG(2) <<
"Entering integer marker.\n" << line_;
707 if (in_integer_section_) {
708 return InvalidArgumentError(
"Found INTORG inside the integer section.");
710 in_integer_section_ =
true;
711 }
else if (absl::StrContains(line_,
"'INTEND'")) {
712 VLOG(2) <<
"Leaving integer marker.\n" << line_;
713 if (!in_integer_section_) {
714 return InvalidArgumentError(
715 "Found INTEND without corresponding INTORG.");
717 in_integer_section_ =
false;
719 return absl::OkStatus();
721 const int start_index = free_form_ ? 0 : 1;
722 if (fields_.size() < start_index + 3) {
723 return InvalidArgumentError(
"Not enough fields in COLUMNS section.");
725 const std::string& column_name = GetField(start_index, 0);
726 const std::string& row1_name = GetField(start_index, 1);
727 const std::string& row1_value = GetField(start_index, 2);
728 const int col = data->FindOrCreateVariable(column_name);
729 is_binary_by_default_.resize(
col + 1,
false);
730 if (in_integer_section_) {
731 data->SetVariableTypeToInteger(
col);
733 data->SetVariableBounds(
col, 0.0, 1.0);
734 is_binary_by_default_[
col] =
true;
739 if (fields_.size() == start_index + 4) {
740 return InvalidArgumentError(
"Unexpected number of fields.");
742 if (fields_.size() - start_index > 4) {
743 const std::string& row2_name = GetField(start_index, 3);
744 const std::string& row2_value = GetField(start_index, 4);
747 return absl::OkStatus();
750template <
class DataWrapper>
751absl::Status MPSReaderImpl::ProcessRhsSection(DataWrapper* data) {
752 const int start_index = free_form_ ? 0 : 2;
753 const int offset = start_index + GetFieldOffset();
754 if (fields_.size() < offset + 2) {
755 return InvalidArgumentError(
"Not enough fields in RHS section.");
758 const std::string& row1_name = GetField(offset, 0);
759 const std::string& row1_value = GetField(offset, 1);
761 if (fields_.size() - start_index >= 4) {
762 const std::string& row2_name = GetField(offset, 2);
763 const std::string& row2_value = GetField(offset, 3);
766 return absl::OkStatus();
769template <
class DataWrapper>
770absl::Status MPSReaderImpl::ProcessRangesSection(DataWrapper* data) {
771 const int start_index = free_form_ ? 0 : 2;
772 const int offset = start_index + GetFieldOffset();
773 if (fields_.size() < offset + 2) {
774 return InvalidArgumentError(
"Not enough fields in RHS section.");
777 const std::string& row1_name = GetField(offset, 0);
778 const std::string& row1_value = GetField(offset, 1);
780 if (fields_.size() - start_index >= 4) {
781 const std::string& row2_name = GetField(offset, 2);
782 const std::string& row2_value = GetField(offset, 3);
785 return absl::OkStatus();
788template <
class DataWrapper>
789absl::Status MPSReaderImpl::ProcessBoundsSection(DataWrapper* data) {
790 if (fields_.size() < 3) {
791 return InvalidArgumentError(
"Not enough fields in BOUNDS section.");
793 const std::string bound_type_mnemonic = fields_[0];
794 const std::string bound_row_name = fields_[1];
795 const std::string column_name = fields_[2];
796 std::string bound_value;
797 if (fields_.size() >= 4) {
798 bound_value = fields_[3];
800 return StoreBound(bound_type_mnemonic, column_name, bound_value, data);
803template <
class DataWrapper>
804absl::Status MPSReaderImpl::ProcessIndicatorsSection(DataWrapper* data) {
808 if (fields_.size() < 4) {
809 return InvalidArgumentError(
"Not enough fields in INDICATORS section.");
812 const std::string type = fields_[0];
814 return InvalidArgumentError(
815 "Indicator constraints must start with \"IF\".");
817 const std::string row_name = fields_[1];
818 const std::string column_name = fields_[2];
819 const std::string column_value = fields_[3];
824 const int col = data->FindOrCreateVariable(column_name);
826 data->SetVariableTypeToInteger(
col);
827 data->SetVariableBounds(
col,
std::max(0.0, data->VariableLowerBound(
col)),
831 AppendLineToError(data->CreateIndicatorConstraint(row_name,
col,
value)));
833 return absl::OkStatus();
836template <
class DataWrapper>
837absl::Status MPSReaderImpl::StoreCoefficient(
int col,
838 const std::string& row_name,
839 const std::string& row_value,
841 if (row_name.empty() || row_name ==
"$") {
842 return absl::OkStatus();
848 return InvalidArgumentError(
"Constraint coefficients cannot be infinity.");
850 if (
value == 0.0)
return absl::OkStatus();
851 if (row_name == objective_name_) {
852 data->SetObjectiveCoefficient(
col,
value);
854 const int row = data->FindOrCreateConstraint(row_name);
857 return absl::OkStatus();
860template <
class DataWrapper>
861absl::Status MPSReaderImpl::StoreRightHandSide(
const std::string& row_name,
862 const std::string& row_value,
864 if (row_name.empty())
return absl::OkStatus();
866 if (row_name != objective_name_) {
867 const int row = data->FindOrCreateConstraint(row_name);
880 return absl::OkStatus();
883template <
class DataWrapper>
884absl::Status MPSReaderImpl::StoreRange(
const std::string& row_name,
885 const std::string& range_value,
887 if (row_name.empty())
return absl::OkStatus();
889 const int row = data->FindOrCreateConstraint(row_name);
909 return absl::OkStatus();
912template <
class DataWrapper>
913absl::Status MPSReaderImpl::StoreBound(
const std::string& bound_type_mnemonic,
914 const std::string& column_name,
915 const std::string& bound_value,
918 bound_name_to_id_map_, bound_type_mnemonic, UNKNOWN_BOUND_TYPE);
919 if (bound_type_id == UNKNOWN_BOUND_TYPE) {
920 return InvalidArgumentError(
"Unknown bound type.");
922 const int col = data->FindOrCreateVariable(column_name);
923 if (integer_type_names_set_.count(bound_type_mnemonic) != 0) {
924 data->SetVariableTypeToInteger(
col);
926 if (is_binary_by_default_.size() <=
col) {
928 is_binary_by_default_.resize(
col + 1,
false);
931 DCHECK(!is_binary_by_default_[
col] || data->VariableIsInteger(
col));
937 if (is_binary_by_default_[
col]) {
941 switch (bound_type_id) {
945 if (bound_type_mnemonic ==
"LI" &&
lower_bound == 0.0) {
954 case SEMI_CONTINUOUS: {
956 data->SetVariableTypeToSemiContinuous(
col);
959 case FIXED_VARIABLE: {
968 case INFINITE_LOWER_BOUND:
971 case INFINITE_UPPER_BOUND:
978 case UNKNOWN_BOUND_TYPE:
980 return InvalidArgumentError(
"Unknown bound type.");
982 is_binary_by_default_[
col] =
false;
984 return absl::OkStatus();
987const int MPSReaderImpl::kNumFields = 6;
988const int MPSReaderImpl::kFieldStartPos[kNumFields] = {1, 4, 14, 24, 39, 49};
989const int MPSReaderImpl::kFieldLength[kNumFields] = {2, 8, 8, 12, 8, 12};
990const int MPSReaderImpl::kSpacePos[12] = {12, 13, 22, 23, 36, 37,
991 38, 47, 48, 61, 62, 63};
996 section_(UNKNOWN_SECTION),
997 section_name_to_id_map_(),
998 row_name_to_id_map_(),
999 bound_name_to_id_map_(),
1000 integer_type_names_set_(),
1003 in_integer_section_(false),
1004 num_unconstrained_rows_(0) {
1005 section_name_to_id_map_[
"*"] = COMMENT;
1006 section_name_to_id_map_[
"NAME"] = NAME;
1007 section_name_to_id_map_[
"OBJSENSE"] = OBJSENSE;
1008 section_name_to_id_map_[
"ROWS"] = ROWS;
1009 section_name_to_id_map_[
"LAZYCONS"] = LAZYCONS;
1010 section_name_to_id_map_[
"COLUMNS"] = COLUMNS;
1011 section_name_to_id_map_[
"RHS"] = RHS;
1012 section_name_to_id_map_[
"RANGES"] = RANGES;
1013 section_name_to_id_map_[
"BOUNDS"] = BOUNDS;
1014 section_name_to_id_map_[
"INDICATORS"] = INDICATORS;
1015 section_name_to_id_map_[
"ENDATA"] = ENDATA;
1016 row_name_to_id_map_[
"E"] = EQUALITY;
1017 row_name_to_id_map_[
"L"] = LESS_THAN;
1018 row_name_to_id_map_[
"G"] = GREATER_THAN;
1019 row_name_to_id_map_[
"N"] = NONE;
1020 bound_name_to_id_map_[
"LO"] = LOWER_BOUND;
1021 bound_name_to_id_map_[
"UP"] = UPPER_BOUND;
1022 bound_name_to_id_map_[
"FX"] = FIXED_VARIABLE;
1023 bound_name_to_id_map_[
"FR"] = FREE_VARIABLE;
1024 bound_name_to_id_map_[
"MI"] = INFINITE_LOWER_BOUND;
1025 bound_name_to_id_map_[
"PL"] = INFINITE_UPPER_BOUND;
1026 bound_name_to_id_map_[
"BV"] = BINARY;
1027 bound_name_to_id_map_[
"LI"] = LOWER_BOUND;
1028 bound_name_to_id_map_[
"UI"] = UPPER_BOUND;
1029 bound_name_to_id_map_[
"SC"] = SEMI_CONTINUOUS;
1031 integer_type_names_set_.insert(
"BV");
1032 integer_type_names_set_.insert(
"LI");
1033 integer_type_names_set_.insert(
"UI");
1036void MPSReaderImpl::Reset() {
1037 fields_.resize(kNumFields);
1039 in_integer_section_ =
false;
1040 num_unconstrained_rows_ = 0;
1041 objective_name_.clear();
1044void MPSReaderImpl::DisplaySummary() {
1045 if (num_unconstrained_rows_ > 0) {
1046 VLOG(1) <<
"There are " << num_unconstrained_rows_ + 1
1047 <<
" unconstrained rows. The first of them (" << objective_name_
1048 <<
") was used as the objective.";
1052bool MPSReaderImpl::IsFixedFormat() {
1053 for (
const int i : kSpacePos) {
1054 if (i >= line_.length())
break;
1055 if (line_[i] !=
' ')
return false;
1060absl::Status MPSReaderImpl::SplitLineIntoFields() {
1062 fields_ = absl::StrSplit(line_, absl::ByAnyChar(
" \t"), absl::SkipEmpty());
1063 if (fields_.size() > kNumFields) {
1064 return InvalidArgumentError(
"Found too many fields.");
1071 if (section_ != NAME && !IsFixedFormat()) {
1072 return InvalidArgumentError(
"Line is not in fixed format.");
1074 const int length = line_.length();
1075 for (
int i = 0; i < kNumFields; ++i) {
1076 if (kFieldStartPos[i] < length) {
1077 fields_[i] = line_.substr(kFieldStartPos[i], kFieldLength[i]);
1078 fields_[i].erase(fields_[i].find_last_not_of(
" ") + 1);
1084 return absl::OkStatus();
1087std::string MPSReaderImpl::GetFirstWord()
const {
1088 if (line_[0] ==
' ') {
1089 return std::string(
"");
1091 const int first_space_pos = line_.find(
' ');
1092 const std::string first_word = line_.substr(0, first_space_pos);
1096bool MPSReaderImpl::IsCommentOrBlank()
const {
1097 const char* line = line_.c_str();
1101 for (; *line !=
'\0'; ++line) {
1102 if (*line !=
' ' && *line !=
'\t') {
1109absl::StatusOr<double> MPSReaderImpl::GetDoubleFromString(
1110 const std::string& str) {
1112 if (!absl::SimpleAtod(str, &result)) {
1113 return InvalidArgumentError(
1114 absl::StrCat(
"Failed to convert \"", str,
"\" to double."));
1116 if (std::isnan(result)) {
1117 return InvalidArgumentError(
"Found NaN value.");
1122absl::StatusOr<bool> MPSReaderImpl::GetBoolFromString(
const std::string& str) {
1124 if (!absl::SimpleAtoi(str, &result) || result < 0 || result > 1) {
1125 return InvalidArgumentError(
1126 absl::StrCat(
"Failed to convert \"", str,
"\" to bool."));
1131absl::Status MPSReaderImpl::ProcessSosSection() {
1132 return InvalidArgumentError(
"Section SOS currently not supported.");
1135absl::Status MPSReaderImpl::InvalidArgumentError(
1136 const std::string& error_message) {
1137 return AppendLineToError(absl::InvalidArgumentError(error_message));
1140absl::Status MPSReaderImpl::AppendLineToError(
const absl::Status&
status) {
1142 <<
" Line " << line_num_ <<
": \"" << line_ <<
"\".";
1147 LinearProgram* data, Form form) {
1148 return MPSReaderImpl().ParseFile(file_name, data, form);
1152 MPModelProto* data, Form form) {
1153 return MPSReaderImpl().ParseFile(file_name, data, form);
1158absl::Status MPSReader::ParseProblemFromString(
const std::string& source,
1159 LinearProgram* data,
1160 MPSReader::Form form) {
1161 return MPSReaderImpl().ParseProblemFromString(source, data, form);
1164absl::Status MPSReader::ParseProblemFromString(
const std::string& source,
1166 MPSReader::Form form) {
1167 return MPSReaderImpl().ParseProblemFromString(source, data, form);
1171 const std::string& mps_data) {
1174 mps_data, &
model, MPSReader::AUTO_DETECT));
1179 const std::string& mps_file) {
#define LOG_FIRST_N(severity, n)
#define DCHECK_GT(val1, val2)
#define DCHECK(condition)
#define VLOG(verboselevel)
#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 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, Data *data, MPSReader::Form form)
absl::Status ParseProblemFromString(const std::string &source, 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)
void ParseFile(const std::string &filename, bool presolve)
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.