14#ifndef OR_TOOLS_LP_DATA_MPS_READER_TEMPLATE_H_
15#define OR_TOOLS_LP_DATA_MPS_READER_TEMPLATE_H_
282#include "absl/container/flat_hash_map.h"
283#include "absl/container/flat_hash_set.h"
284#include "absl/container/inlined_vector.h"
285#include "absl/log/check.h"
286#include "absl/status/status.h"
287#include "absl/status/statusor.h"
288#include "absl/strings/ascii.h"
289#include "absl/strings/match.h"
290#include "absl/strings/numbers.h"
291#include "absl/strings/str_cat.h"
292#include "absl/strings/str_split.h"
293#include "absl/strings/string_view.h"
302enum class MPSReaderFormat { kAutoDetect,
kFree, kFixed };
308static constexpr int kNumMpsFields = 6;
311enum class MPSSectionId {
336 static absl::StatusOr<MPSLineInfo> Create(int64_t line_num,
bool free_form,
337 absl::string_view line);
340 absl::string_view GetLine()
const {
return line_; }
344 bool IsNewSection()
const {
return line_[0] !=
'\0' && line_[0] !=
' '; }
349 int GetFieldsSize()
const {
return fields_.size(); }
353 absl::string_view GetFirstWord()
const;
357 bool IsCommentOrBlank()
const;
366 absl::string_view GetField(
int index)
const {
return fields_[index]; }
377 int GetFieldOffset()
const {
return free_form_ ? fields_.size() & 1 : 0; }
381 absl::Status InvalidArgumentError(absl::string_view error_message)
const;
385 absl::Status AppendLineToError(
const absl::Status& status)
const;
388 MPSLineInfo(int64_t line_num,
bool free_form, absl::string_view line)
389 : free_form_{free_form}, line_num_{line_num}, line_{line} {}
392 absl::Status SplitLineIntoFields();
395 bool IsFixedFormat()
const;
398 const bool free_form_;
401 absl::InlinedVector<absl::string_view, internal::kNumMpsFields> fields_;
404 const int64_t line_num_;
409 const absl::string_view line_;
493template <
class DataWrapper>
506 absl::StatusOr<MPSReaderFormat>
ParseFile(
507 absl::string_view file_name, DataWrapper* data,
508 MPSReaderFormat form = MPSReaderFormat::kAutoDetect);
516 absl::string_view source, DataWrapper* data,
517 MPSReaderFormat form = MPSReaderFormat::kAutoDetect);
520 static constexpr double kInfinity = std::numeric_limits<double>::infinity();
526 void DisplaySummary();
529 absl::Status ProcessLine(absl::string_view line, DataWrapper* data);
532 absl::Status ProcessObjectiveSenseSection(
533 const internal::MPSLineInfo& line_info, DataWrapper* data);
536 absl::Status ProcessRowsSection(
const internal::MPSLineInfo& line_info,
537 bool is_lazy, DataWrapper* data);
540 absl::Status ProcessColumnsSection(
const internal::MPSLineInfo& line_info,
544 absl::Status ProcessRhsSection(
const internal::MPSLineInfo& line_info,
548 absl::Status ProcessRangesSection(
const internal::MPSLineInfo& line_info,
552 absl::Status ProcessBoundsSection(
const internal::MPSLineInfo& line_info,
556 absl::Status ProcessIndicatorsSection(
const internal::MPSLineInfo& line_info,
561 absl::StatusOr<double> GetDoubleFromString(
562 absl::string_view str,
const internal::MPSLineInfo& line_info);
563 absl::StatusOr<bool> GetBoolFromString(
564 absl::string_view str,
const internal::MPSLineInfo& line_info);
568 enum class BoundTypeId {
581 enum class RowTypeId {
591 absl::Status StoreBound(
const internal::MPSLineInfo& line_info,
592 absl::string_view bound_type_mnemonic,
593 absl::string_view column_name,
594 absl::string_view bound_value, DataWrapper* data);
597 absl::Status StoreCoefficient(
const internal::MPSLineInfo& line_info,
598 IndexType col, absl::string_view row_name,
599 absl::string_view row_value, DataWrapper* data);
602 absl::Status StoreRightHandSide(
const internal::MPSLineInfo& line_info,
603 absl::string_view row_name,
604 absl::string_view row_value,
608 absl::Status StoreRange(
const internal::MPSLineInfo& line_info,
609 absl::string_view row_name,
610 absl::string_view range_value, DataWrapper* data);
616 std::string objective_name_;
619 internal::MPSSectionId section_;
622 absl::flat_hash_map<std::string, internal::MPSSectionId>
623 section_name_to_id_map_;
626 absl::flat_hash_map<std::string, RowTypeId> row_name_to_id_map_;
629 absl::flat_hash_map<std::string, BoundTypeId> bound_name_to_id_map_;
632 absl::flat_hash_set<std::string> integer_type_names_set_;
641 std::vector<bool> is_binary_by_default_;
646 bool in_integer_section_;
651 IndexType num_unconstrained_rows_;
654template <
class DataWrapper>
656 const absl::string_view file_name, DataWrapper*
const data,
657 const MPSReaderFormat form) {
658 if (data ==
nullptr) {
659 return absl::InvalidArgumentError(
"NULL pointer passed as argument.");
662 if (form != MPSReaderFormat::kFree && form != MPSReaderFormat::kFixed) {
663 if (
ParseFile(file_name, data, MPSReaderFormat::kFixed).ok()) {
664 return MPSReaderFormat::kFixed;
666 return ParseFile(file_name, data, MPSReaderFormat::kFree);
669 DCHECK(form == MPSReaderFormat::kFree || form == MPSReaderFormat::kFixed);
670 free_form_ = form == MPSReaderFormat::kFree;
675 for (
const absl::string_view line :
684template <
class DataWrapper>
686 absl::string_view source, DataWrapper*
const data,
687 const MPSReaderFormat form) {
688 if (form != MPSReaderFormat::kFree && form != MPSReaderFormat::kFixed) {
689 if (
ParseString(source, data, MPSReaderFormat::kFixed).ok()) {
690 return MPSReaderFormat::kFixed;
692 return ParseString(source, data, MPSReaderFormat::kFree);
695 DCHECK(form == MPSReaderFormat::kFree || form == MPSReaderFormat::kFixed);
696 free_form_ = form == MPSReaderFormat::kFree;
699 for (absl::string_view line : absl::StrSplit(source,
'\n')) {
707template <
class DataWrapper>
708absl::Status MPSReaderTemplate<DataWrapper>::ProcessLine(absl::string_view line,
712 internal::MPSLineInfo::Create(line_num_, free_form_, line));
713 if (line_info.IsCommentOrBlank()) {
714 return absl::OkStatus();
718 if (line_info.IsNewSection()) {
719 if (
const auto it = section_name_to_id_map_.find(line_info.GetFirstWord());
720 it != section_name_to_id_map_.end()) {
721 section_ = it->second;
723 return line_info.InvalidArgumentError(
"Unknown section.");
726 if (section_ == internal::MPSSectionId::kName) {
734 if (line_info.GetFieldsSize() >= 2) {
735 data->SetName(line_info.GetField(1));
738 const std::vector<absl::string_view> free_fields = absl::StrSplit(
739 line_info.GetLine(), absl::ByAnyChar(
" \t"), absl::SkipEmpty());
740 const absl::string_view free_name =
741 free_fields.size() >= 2 ? free_fields[1] :
"";
742 const absl::string_view fixed_name =
743 line_info.GetFieldsSize() >= 3 ? line_info.GetField(2) :
"";
744 if (free_name != fixed_name) {
745 return line_info.InvalidArgumentError(
746 "Fixed form invalid: name differs between free and fixed "
749 data->SetName(fixed_name);
755 if (section_ == internal::MPSSectionId::kObjsense &&
756 line_info.GetFieldsSize() == 2 && free_form_) {
757 if (absl::StrContains(line_info.GetField(1),
"MIN")) {
758 data->SetObjectiveDirection(
false);
759 }
else if (absl::StrContains(line_info.GetField(1),
"MAX")) {
760 data->SetObjectiveDirection(
true);
762 return line_info.InvalidArgumentError(
763 "Invalid inline objective direction.");
767 return absl::OkStatus();
770 case internal::MPSSectionId::kName:
771 return line_info.InvalidArgumentError(
"Second NAME field.");
772 case internal::MPSSectionId::kObjsense:
773 return ProcessObjectiveSenseSection(line_info, data);
774 case internal::MPSSectionId::kRows:
775 return ProcessRowsSection(line_info,
false, data);
776 case internal::MPSSectionId::kLazycons:
777 return ProcessRowsSection(line_info,
true, data);
778 case internal::MPSSectionId::kColumns:
779 return ProcessColumnsSection(line_info, data);
780 case internal::MPSSectionId::kRhs:
781 return ProcessRhsSection(line_info, data);
782 case internal::MPSSectionId::kRanges:
783 return ProcessRangesSection(line_info, data);
784 case internal::MPSSectionId::kBounds:
785 return ProcessBoundsSection(line_info, data);
786 case internal::MPSSectionId::kIndicators:
787 return ProcessIndicatorsSection(line_info, data);
788 case internal::MPSSectionId::kEndData:
791 return line_info.InvalidArgumentError(
"Unknown section.");
793 return absl::OkStatus();
796template <
class DataWrapper>
797absl::Status MPSReaderTemplate<DataWrapper>::ProcessObjectiveSenseSection(
798 const internal::MPSLineInfo& line_info, DataWrapper* data) {
799 absl::string_view field = absl::StripAsciiWhitespace(line_info.GetLine());
800 if (field !=
"MIN" && field !=
"MAX") {
801 return line_info.InvalidArgumentError(
802 "Expected objective sense (MAX or MIN).");
804 data->SetObjectiveDirection(field ==
"MAX");
805 return absl::OkStatus();
808template <
class DataWrapper>
809absl::Status MPSReaderTemplate<DataWrapper>::ProcessRowsSection(
810 const internal::MPSLineInfo& line_info,
bool is_lazy, DataWrapper* data) {
811 if (line_info.GetFieldsSize() < 2) {
812 return line_info.InvalidArgumentError(
"Not enough fields in ROWS section.");
814 const absl::string_view row_type_name = line_info.GetField(0);
815 const absl::string_view row_name = line_info.GetField(1);
816 const auto it = row_name_to_id_map_.find(row_type_name);
817 if (it == row_name_to_id_map_.end()) {
818 return line_info.InvalidArgumentError(
"Unknown row type.");
820 RowTypeId row_type = it->second;
823 if (objective_name_.empty() && row_type == RowTypeId::kNone) {
824 row_type = RowTypeId::kObjective;
825 objective_name_ = std::string(row_name);
827 if (row_type == RowTypeId::kNone) {
828 ++num_unconstrained_rows_;
830 const IndexType row = data->FindOrCreateConstraint(row_name);
831 if (is_lazy) data->SetIsLazy(row);
836 case RowTypeId::kLessThan:
837 data->SetConstraintBounds(row, -
kInfinity,
838 data->ConstraintUpperBound(row));
840 case RowTypeId::kGreaterThan:
841 data->SetConstraintBounds(row, data->ConstraintLowerBound(row),
844 case RowTypeId::kNone:
847 case RowTypeId::kEquality:
852 return absl::OkStatus();
859template <
typename T,
typename IndexType>
861 const T extend_with_value,
862 std::vector<T>& container) {
863 if (container.size() > until)
return;
864 std::fill_n(std::back_inserter(container), until + 1 - container.size(),
870template <
class DataWrapper>
871absl::Status MPSReaderTemplate<DataWrapper>::ProcessColumnsSection(
872 const internal::MPSLineInfo& line_info, DataWrapper* data) {
874 if (absl::StrContains(line_info.GetLine(),
"'MARKER'")) {
875 if (absl::StrContains(line_info.GetLine(),
"'INTORG'")) {
876 VLOG(2) <<
"Entering integer marker.\n" << line_info.GetLine();
877 if (in_integer_section_) {
878 return line_info.InvalidArgumentError(
879 "Found INTORG inside the integer section.");
881 in_integer_section_ =
true;
882 }
else if (absl::StrContains(line_info.GetLine(),
"'INTEND'")) {
883 VLOG(2) <<
"Leaving integer marker.\n" << line_info.GetLine();
884 if (!in_integer_section_) {
885 return line_info.InvalidArgumentError(
886 "Found INTEND without corresponding INTORG.");
888 in_integer_section_ =
false;
890 return absl::OkStatus();
892 const int start_index = free_form_ ? 0 : 1;
893 if (line_info.GetFieldsSize() < start_index + 3) {
894 return line_info.InvalidArgumentError(
895 "Not enough fields in COLUMNS section.");
897 const absl::string_view column_name = line_info.GetField(start_index + 0);
898 const absl::string_view row1_name = line_info.GetField(start_index + 1);
899 const absl::string_view row1_value = line_info.GetField(start_index + 2);
900 const IndexType col = data->FindOrCreateVariable(column_name);
902 if (in_integer_section_) {
903 data->SetVariableTypeToInteger(col);
905 data->SetVariableBounds(col, 0.0, 1.0);
906 is_binary_by_default_[col] =
true;
908 data->SetVariableBounds(col, 0.0,
kInfinity);
911 StoreCoefficient(line_info, col, row1_name, row1_value, data));
912 if (line_info.GetFieldsSize() == start_index + 4) {
913 return line_info.InvalidArgumentError(
"Unexpected number of fields.");
915 if (line_info.GetFieldsSize() - start_index > 4) {
916 const absl::string_view row2_name = line_info.GetField(start_index + 3);
917 const absl::string_view row2_value = line_info.GetField(start_index + 4);
919 StoreCoefficient(line_info, col, row2_name, row2_value, data));
921 return absl::OkStatus();
924template <
class DataWrapper>
925absl::Status MPSReaderTemplate<DataWrapper>::ProcessRhsSection(
926 const internal::MPSLineInfo& line_info, DataWrapper* data) {
927 const int start_index = free_form_ ? 0 : 2;
928 const int offset = start_index + line_info.GetFieldOffset();
929 if (line_info.GetFieldsSize() < offset + 2) {
930 return line_info.InvalidArgumentError(
"Not enough fields in RHS section.");
933 const absl::string_view row1_name = line_info.GetField(offset);
934 const absl::string_view row1_value = line_info.GetField(offset + 1);
935 RETURN_IF_ERROR(StoreRightHandSide(line_info, row1_name, row1_value, data));
936 if (line_info.GetFieldsSize() - start_index >= 4) {
937 const absl::string_view row2_name = line_info.GetField(offset + 2);
938 const absl::string_view row2_value = line_info.GetField(offset + 3);
939 RETURN_IF_ERROR(StoreRightHandSide(line_info, row2_name, row2_value, data));
941 return absl::OkStatus();
944template <
class DataWrapper>
945absl::Status MPSReaderTemplate<DataWrapper>::ProcessRangesSection(
946 const internal::MPSLineInfo& line_info, DataWrapper* data) {
947 const int start_index = free_form_ ? 0 : 2;
948 const int offset = start_index + line_info.GetFieldOffset();
949 if (line_info.GetFieldsSize() < offset + 2) {
950 return line_info.InvalidArgumentError(
"Not enough fields in RHS section.");
953 const absl::string_view row1_name = line_info.GetField(offset);
954 const absl::string_view row1_value = line_info.GetField(offset + 1);
956 if (line_info.GetFieldsSize() - start_index >= 4) {
957 const absl::string_view row2_name = line_info.GetField(offset + 2);
958 const absl::string_view row2_value = line_info.GetField(offset + 3);
961 return absl::OkStatus();
964template <
class DataWrapper>
965absl::Status MPSReaderTemplate<DataWrapper>::ProcessBoundsSection(
966 const internal::MPSLineInfo& line_info, DataWrapper* data) {
967 if (line_info.GetFieldsSize() < 3) {
968 return line_info.InvalidArgumentError(
969 "Not enough fields in BOUNDS section.");
971 const absl::string_view bound_type_mnemonic = line_info.GetField(0);
972 const absl::string_view column_name = line_info.GetField(2);
973 const absl::string_view bound_value =
974 (line_info.GetFieldsSize() >= 4) ? line_info.GetField(3) :
"";
975 return StoreBound(line_info, bound_type_mnemonic, column_name, bound_value,
979template <
class DataWrapper>
980absl::Status MPSReaderTemplate<DataWrapper>::ProcessIndicatorsSection(
981 const internal::MPSLineInfo& line_info, DataWrapper* data) {
985 if (line_info.GetFieldsSize() < 4) {
986 return line_info.InvalidArgumentError(
987 "Not enough fields in INDICATORS section.");
990 const absl::string_view type = line_info.GetField(0);
992 return line_info.InvalidArgumentError(
993 "Indicator constraints must start with \"IF\".");
995 const absl::string_view row_name = line_info.GetField(1);
996 const absl::string_view column_name = line_info.GetField(2);
997 const absl::string_view column_value = line_info.GetField(3);
1002 const IndexType col = data->FindOrCreateVariable(column_name);
1004 data->SetVariableTypeToInteger(col);
1005 data->SetVariableBounds(col, std::max(0.0, data->VariableLowerBound(col)),
1006 std::min(1.0, data->VariableUpperBound(col)));
1009 data->CreateIndicatorConstraint(row_name, col, value)));
1011 return absl::OkStatus();
1014template <
class DataWrapper>
1015absl::Status MPSReaderTemplate<DataWrapper>::StoreCoefficient(
1016 const internal::MPSLineInfo& line_info, IndexType col,
1017 absl::string_view row_name, absl::string_view row_value,
1018 DataWrapper* data) {
1019 if (row_name.empty() || row_name ==
"$") {
1020 return absl::OkStatus();
1026 return line_info.InvalidArgumentError(
1027 "Constraint coefficients cannot be infinity.");
1029 if (value == 0.0)
return absl::OkStatus();
1030 if (row_name == objective_name_) {
1031 data->SetObjectiveCoefficient(col, value);
1033 const IndexType row = data->FindOrCreateConstraint(row_name);
1034 data->SetConstraintCoefficient(row, col, value);
1036 return absl::OkStatus();
1039template <
class DataWrapper>
1040absl::Status MPSReaderTemplate<DataWrapper>::StoreRightHandSide(
1041 const internal::MPSLineInfo& line_info, absl::string_view row_name,
1042 absl::string_view row_value, DataWrapper* data) {
1043 if (row_name.empty())
return absl::OkStatus();
1045 if (row_name != objective_name_) {
1046 const IndexType row = data->FindOrCreateConstraint(row_name);
1053 const double lower_bound =
1055 const double upper_bound =
1057 data->SetConstraintBounds(row, lower_bound, upper_bound);
1064 data->SetObjectiveOffset(-value);
1066 return absl::OkStatus();
1069template <
class DataWrapper>
1070absl::Status MPSReaderTemplate<DataWrapper>::StoreRange(
1071 const internal::MPSLineInfo& line_info, absl::string_view row_name,
1072 absl::string_view range_value, DataWrapper* data) {
1073 if (row_name.empty())
return absl::OkStatus();
1075 const IndexType row = data->FindOrCreateConstraint(row_name);
1079 double lower_bound = data->ConstraintLowerBound(row);
1080 double upper_bound = data->ConstraintUpperBound(row);
1081 if (lower_bound == upper_bound) {
1083 lower_bound += range;
1085 upper_bound += range;
1089 lower_bound = upper_bound - fabs(range);
1092 upper_bound = lower_bound + fabs(range);
1094 data->SetConstraintBounds(row, lower_bound, upper_bound);
1095 return absl::OkStatus();
1098template <
class DataWrapper>
1099absl::Status MPSReaderTemplate<DataWrapper>::StoreBound(
1100 const internal::MPSLineInfo& line_info,
1101 absl::string_view bound_type_mnemonic, absl::string_view column_name,
1102 absl::string_view bound_value, DataWrapper* data) {
1103 const auto it = bound_name_to_id_map_.find(bound_type_mnemonic);
1104 if (it == bound_name_to_id_map_.end()) {
1105 return line_info.InvalidArgumentError(
"Unknown bound type.");
1107 const BoundTypeId bound_type_id = it->second;
1108 const IndexType col = data->FindOrCreateVariable(column_name);
1109 if (integer_type_names_set_.count(bound_type_mnemonic) != 0) {
1110 data->SetVariableTypeToInteger(col);
1113 double lower_bound = data->VariableLowerBound(col);
1114 double upper_bound = data->VariableUpperBound(col);
1118 if (is_binary_by_default_[col]) {
1122 switch (bound_type_id) {
1123 case BoundTypeId::kLowerBound: {
1125 GetDoubleFromString(bound_value, line_info));
1128 if (bound_type_mnemonic ==
"LI" && lower_bound == 0.0) {
1133 case BoundTypeId::kUpperBound: {
1135 GetDoubleFromString(bound_value, line_info));
1138 case BoundTypeId::kSemiContinuous: {
1140 GetDoubleFromString(bound_value, line_info));
1141 data->SetVariableTypeToSemiContinuous(col);
1144 case BoundTypeId::kFixedVariable: {
1146 GetDoubleFromString(bound_value, line_info));
1147 upper_bound = lower_bound;
1150 case BoundTypeId::kFreeVariable:
1154 case BoundTypeId::kInfiniteLowerBound:
1157 case BoundTypeId::kInfiniteUpperBound:
1160 case BoundTypeId::kBinary:
1164 case BoundTypeId::kUnknownBoundType:
1166 return line_info.InvalidArgumentError(
"Unknown bound type.");
1168 is_binary_by_default_[col] =
false;
1169 data->SetVariableBounds(col, lower_bound, upper_bound);
1170 return absl::OkStatus();
1173template <
class DataWrapper>
1176 section_(
internal::MPSSectionId::kUnknownSection),
1177 section_name_to_id_map_(),
1178 row_name_to_id_map_(),
1179 bound_name_to_id_map_(),
1180 integer_type_names_set_(),
1182 in_integer_section_(false),
1183 num_unconstrained_rows_(0) {
1184 section_name_to_id_map_[
"NAME"] = internal::MPSSectionId::kName;
1185 section_name_to_id_map_[
"OBJSENSE"] = internal::MPSSectionId::kObjsense;
1186 section_name_to_id_map_[
"ROWS"] = internal::MPSSectionId::kRows;
1187 section_name_to_id_map_[
"LAZYCONS"] = internal::MPSSectionId::kLazycons;
1188 section_name_to_id_map_[
"COLUMNS"] = internal::MPSSectionId::kColumns;
1189 section_name_to_id_map_[
"RHS"] = internal::MPSSectionId::kRhs;
1190 section_name_to_id_map_[
"RANGES"] = internal::MPSSectionId::kRanges;
1191 section_name_to_id_map_[
"BOUNDS"] = internal::MPSSectionId::kBounds;
1192 section_name_to_id_map_[
"INDICATORS"] = internal::MPSSectionId::kIndicators;
1193 section_name_to_id_map_[
"ENDATA"] = internal::MPSSectionId::kEndData;
1194 row_name_to_id_map_[
"E"] = RowTypeId::kEquality;
1195 row_name_to_id_map_[
"L"] = RowTypeId::kLessThan;
1196 row_name_to_id_map_[
"G"] = RowTypeId::kGreaterThan;
1197 row_name_to_id_map_[
"N"] = RowTypeId::kNone;
1198 bound_name_to_id_map_[
"LO"] = BoundTypeId::kLowerBound;
1199 bound_name_to_id_map_[
"UP"] = BoundTypeId::kUpperBound;
1200 bound_name_to_id_map_[
"FX"] = BoundTypeId::kFixedVariable;
1201 bound_name_to_id_map_[
"FR"] = BoundTypeId::kFreeVariable;
1202 bound_name_to_id_map_[
"MI"] = BoundTypeId::kInfiniteLowerBound;
1203 bound_name_to_id_map_[
"PL"] = BoundTypeId::kInfiniteUpperBound;
1204 bound_name_to_id_map_[
"BV"] = BoundTypeId::kBinary;
1205 bound_name_to_id_map_[
"LI"] = BoundTypeId::kLowerBound;
1206 bound_name_to_id_map_[
"UI"] = BoundTypeId::kUpperBound;
1207 bound_name_to_id_map_[
"SC"] = BoundTypeId::kSemiContinuous;
1209 integer_type_names_set_.insert(
"BV");
1210 integer_type_names_set_.insert(
"LI");
1211 integer_type_names_set_.insert(
"UI");
1214template <
class DataWrapper>
1215void MPSReaderTemplate<DataWrapper>::Reset() {
1217 in_integer_section_ =
false;
1218 num_unconstrained_rows_ = 0;
1219 objective_name_.clear();
1222template <
class DataWrapper>
1223void MPSReaderTemplate<DataWrapper>::DisplaySummary() {
1224 if (num_unconstrained_rows_ > 0) {
1225 VLOG(1) <<
"There are " << num_unconstrained_rows_ + 1
1226 <<
" unconstrained rows. The first of them (" << objective_name_
1227 <<
") was used as the objective.";
1231template <
class DataWrapper>
1232absl::StatusOr<double> MPSReaderTemplate<DataWrapper>::GetDoubleFromString(
1233 absl::string_view str,
const internal::MPSLineInfo& line_info) {
1235 if (!absl::SimpleAtod(str, &result)) {
1236 return line_info.InvalidArgumentError(
1237 absl::StrCat(
"Failed to convert \"", str,
"\" to double."));
1239 if (std::isnan(result)) {
1240 return line_info.InvalidArgumentError(
"Found NaN value.");
1245template <
class DataWrapper>
1246absl::StatusOr<bool> MPSReaderTemplate<DataWrapper>::GetBoolFromString(
1247 absl::string_view str,
const internal::MPSLineInfo& line_info) {
1249 if (!absl::SimpleAtoi(str, &result) || result < 0 || result > 1) {
1250 return line_info.InvalidArgumentError(
1251 absl::StrCat(
"Failed to convert \"", str,
"\" to bool."));
#define ASSIGN_OR_RETURN(lhs, rexpr)
#define RETURN_IF_ERROR(expr)
absl::StatusOr< MPSReaderFormat > ParseFile(absl::string_view file_name, DataWrapper *data, MPSReaderFormat form=MPSReaderFormat::kAutoDetect)
typename DataWrapper::IndexType IndexType
Type for row and column indices, as provided by DataWrapper.
absl::StatusOr< MPSReaderFormat > ParseString(absl::string_view source, DataWrapper *data, MPSReaderFormat form=MPSReaderFormat::kAutoDetect)
absl::Status Open(absl::string_view filename, absl::string_view mode, File **f, Options options)
As of 2016-01, these methods can only be used with flags = file::Defaults().
void ExtendContainerWithValueUntil(const IndexType until, const T extend_with_value, std::vector< T > &container)
End of the interface. Below is the implementation.
@ kFree
The variable/constraint is free (it has no finite bounds).
In SWIG mode, we don't want anything besides these top-level includes.
static constexpr double kInfinity