Change proto to/from file API to use absl::StatusOr; add reader/writer proto_file to model_builder
This commit is contained in:
433
bazel/scip.patch
433
bazel/scip.patch
@@ -1,414 +1,61 @@
|
||||
diff --git a/.gitignore b/.gitignore
|
||||
index 4fbbc0e3b3..964b2d030d 100644
|
||||
--- a/.gitignore
|
||||
+++ b/.gitignore
|
||||
@@ -83,8 +83,6 @@ hooks/
|
||||
localhooks/
|
||||
|
||||
# created when packaging, don't version control this
|
||||
-src/scip/githash.c
|
||||
-src/scip/buildflags.c
|
||||
|
||||
# settings
|
||||
settings/
|
||||
diff --git a/src/scip/benders_xyz.c b/src/scip/benders_xyz.c
|
||||
index 0d812ba6bd..ffe1badee0 100644
|
||||
--- a/src/scip/benders_xyz.c
|
||||
+++ b/src/scip/benders_xyz.c
|
||||
@@ -47,6 +47,7 @@
|
||||
/** Benders' decomposition data */
|
||||
struct SCIP_BendersData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/benderscut_xyz.c b/src/scip/benderscut_xyz.c
|
||||
index 0f05582fe4..7fb99f648a 100644
|
||||
--- a/src/scip/benderscut_xyz.c
|
||||
+++ b/src/scip/benderscut_xyz.c
|
||||
@@ -41,6 +41,7 @@
|
||||
/** Benders' decomposition cut data */
|
||||
struct SCIP_BenderscutData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/branch_xyz.c b/src/scip/branch_xyz.c
|
||||
index 1f13ac7460..e8ded751cf 100644
|
||||
--- a/src/scip/branch_xyz.c
|
||||
+++ b/src/scip/branch_xyz.c
|
||||
@@ -42,6 +42,7 @@
|
||||
/** branching rule data */
|
||||
struct SCIP_BranchruleData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -216,7 +217,7 @@ SCIP_RETCODE SCIPincludeBranchruleXyz(
|
||||
/* use SCIPincludeBranchrule() if you want to set all callbacks explicitly and realize (by getting compiler errors) when
|
||||
* new callbacks are added in future SCIP versions
|
||||
*/
|
||||
- SCIP_CALL( SCIPincludeBranchrule(scip, BRANCHRULE_NAME, BRANCHRULE_DESC, BRANCHRULE_PRIORITY, BRANCHRULE_MAXDEPTH,
|
||||
+ SCIP_CALL( SCIPincludeBranchrule(scip, BRANCHRULE_NAME, BRANCHRULE_DESC, BRANCHRULE_PRIORITY, BRANCHRULE_MAXDEPTH,
|
||||
BRANCHRULE_MAXBOUNDDIST,
|
||||
branchCopyXyz, branchFreeXyz, branchInitXyz, branchExitXyz, branchInitsolXyz, branchExitsolXyz,
|
||||
branchExeclpXyz, branchExecextXyz, branchExecpsXyz,
|
||||
diff --git a/src/scip/compr_xyz.c b/src/scip/compr_xyz.c
|
||||
index 2f6b29e88c..a6142d7785 100644
|
||||
--- a/src/scip/compr_xyz.c
|
||||
+++ b/src/scip/compr_xyz.c
|
||||
@@ -41,6 +41,7 @@
|
||||
/** tree compression data */
|
||||
struct SCIP_ComprData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/cons_xyz.c b/src/scip/cons_xyz.c
|
||||
index 8141039a2e..e3f5d2b94b 100644
|
||||
--- a/src/scip/cons_xyz.c
|
||||
+++ b/src/scip/cons_xyz.c
|
||||
@@ -69,11 +69,13 @@
|
||||
/** constraint data for xyz constraints */
|
||||
struct SCIP_ConsData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
/** constraint handler data */
|
||||
struct SCIP_ConshdlrData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/cutsel_xyz.c b/src/scip/cutsel_xyz.c
|
||||
index c660098bb0..92f3fb9d92 100644
|
||||
--- a/src/scip/cutsel_xyz.c
|
||||
+++ b/src/scip/cutsel_xyz.c
|
||||
@@ -40,6 +40,7 @@
|
||||
/** cut selector data */
|
||||
struct SCIP_CutselData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/dialog_xyz.c b/src/scip/dialog_xyz.c
|
||||
index 1918057017..8506d526e6 100644
|
||||
--- a/src/scip/dialog_xyz.c
|
||||
+++ b/src/scip/dialog_xyz.c
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#define DIALOG_NAME "xyz"
|
||||
#define DIALOG_DESC "xyz user interface dialog"
|
||||
-#define DIALOG_ISSUBMENU FALSE
|
||||
+#define DIALOG_ISSUBMENU FALSE
|
||||
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
/** dialog data */
|
||||
struct SCIP_DialogData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -154,7 +155,7 @@ SCIP_RETCODE SCIPincludeDialogXyz(
|
||||
/* create, include, and release dialog */
|
||||
if( !SCIPdialogHasEntry(parentdialog, DIALOG_NAME) )
|
||||
diff --git a/src/lpi/lpi_glop.cpp b/src/lpi/lpi_glop.cpp
|
||||
index 2471778a8f..17fd1e8c34 100644
|
||||
--- a/src/lpi/lpi_glop.cpp
|
||||
+++ b/src/lpi/lpi_glop.cpp
|
||||
@@ -3190,6 +3190,6 @@ SCIP_RETCODE SCIPlpiReadLP(
|
||||
const std::string filespec(fname);
|
||||
MPModelProto proto;
|
||||
- if ( ! ReadFileToProto(filespec, &proto) )
|
||||
+ if ( ! ReadFileToProto(filespec, &proto).ok() )
|
||||
{
|
||||
- SCIP_CALL( SCIPincludeDialog(scip, &dialog,
|
||||
+ SCIP_CALL( SCIPincludeDialog(scip, &dialog,
|
||||
dialogCopyXyz, dialogExecXyz, dialogDescXyz, dialogFreeXyz,
|
||||
DIALOG_NAME, DIALOG_DESC, DIALOG_ISSUBMENU, dialogdata) );
|
||||
SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
|
||||
diff --git a/src/scip/disp_xyz.c b/src/scip/disp_xyz.c
|
||||
index 6c6a776091..b00cf1e036 100644
|
||||
--- a/src/scip/disp_xyz.c
|
||||
+++ b/src/scip/disp_xyz.c
|
||||
@@ -26,13 +26,13 @@
|
||||
#include "scip/disp_xyz.h"
|
||||
|
||||
|
||||
-#define DISP_NAME "xyz"
|
||||
+#define DISP_NAME "xyz"
|
||||
#define DISP_DESC "xyz display column"
|
||||
-#define DISP_HEADER "xyz"
|
||||
+#define DISP_HEADER "xyz"
|
||||
#define DISP_WIDTH 14 /**< the width of the display column */
|
||||
#define DISP_PRIORITY 110000 /**< the priority of the display column */
|
||||
#define DISP_POSITION 30100 /**< the relative position of the display column */
|
||||
-#define DISP_STRIPLINE TRUE /**< the default for whether the display column should be separated
|
||||
+#define DISP_STRIPLINE TRUE /**< the default for whether the display column should be separated
|
||||
* with a line from its right neighbor */
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
/** display column data */
|
||||
struct SCIP_DispData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -188,10 +189,10 @@ SCIP_RETCODE SCIPincludeDispXyz(
|
||||
/* TODO: (optional) create display column specific data here */
|
||||
|
||||
/* include display column */
|
||||
- SCIP_CALL( SCIPincludeDisp(scip, DISP_NAME, DISP_DESC, DISP_HEADER, SCIP_DISPSTATUS_AUTO,
|
||||
+ SCIP_CALL( SCIPincludeDisp(scip, DISP_NAME, DISP_DESC, DISP_HEADER, SCIP_DISPSTATUS_AUTO,
|
||||
dispCopyXyz,
|
||||
- dispFreeXyz, dispInitXyz, dispExitXyz,
|
||||
- dispInitsolXyz, dispExitsolXyz, dispOutputXyz,
|
||||
+ dispFreeXyz, dispInitXyz, dispExitXyz,
|
||||
+ dispInitsolXyz, dispExitsolXyz, dispOutputXyz,
|
||||
dispdata, DISP_WIDTH, DISP_PRIORITY, DISP_POSITION, DISP_STRIPLINE) );
|
||||
|
||||
/* add xyz display column parameters */
|
||||
diff --git a/src/scip/event_xyz.c b/src/scip/event_xyz.c
|
||||
index 31fd333f98..c793d69bc4 100644
|
||||
--- a/src/scip/event_xyz.c
|
||||
+++ b/src/scip/event_xyz.c
|
||||
@@ -36,6 +36,7 @@
|
||||
/** event handler data */
|
||||
struct SCIP_EventhdlrData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -179,7 +180,7 @@ SCIP_RETCODE SCIPincludeEventHdlrXyz(
|
||||
*/
|
||||
SCIP_CALL( SCIPincludeEventhdlr(scip, EVENTHDLR_NAME, EVENTHDLR_DESC,
|
||||
eventCopyXyz,
|
||||
- eventFreeXyz, eventInitXyz, eventExitXyz,
|
||||
+ eventFreeXyz, eventInitXyz, eventExitXyz,
|
||||
eventInitsolXyz, eventExitsolXyz, eventDeleteXyz, eventExecXyz,
|
||||
eventhdlrdata) );
|
||||
#else
|
||||
diff --git a/src/scip/expr_xyz.c b/src/scip/expr_xyz.c
|
||||
index 2eb7914e1d..4e924b03b5 100644
|
||||
--- a/src/scip/expr_xyz.c
|
||||
+++ b/src/scip/expr_xyz.c
|
||||
@@ -38,11 +38,13 @@
|
||||
/** expression handler data */
|
||||
struct SCIP_ExprhdlrData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
/** expression data */
|
||||
struct SCIP_ExprData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
/*
|
||||
SCIPerrorMessage("Could not read <%s>\n", fname);
|
||||
return SCIP_READERROR;
|
||||
@@ -3214,7 +3214,7 @@ SCIP_RETCODE SCIPlpiWriteLP(
|
||||
MPModelProto proto;
|
||||
LinearProgramToMPModelProto(*lpi->linear_program, &proto);
|
||||
const std::string filespec(fname);
|
||||
- if ( ! WriteProtoToFile(filespec, proto, operations_research::ProtoWriteFormat::kProtoText, true) )
|
||||
+ if ( ! WriteProtoToFile(filespec, proto, operations_research::ProtoWriteFormat::kProtoText, true).ok() )
|
||||
{
|
||||
SCIPerrorMessage("Could not write <%s>\n", fname);
|
||||
return SCIP_READERROR;
|
||||
diff --git a/src/symmetry/compute_symmetry_bliss.cpp b/src/symmetry/compute_symmetry_bliss.cpp
|
||||
index 484627c4b9..27c2895165 100644
|
||||
--- a/src/symmetry/compute_symmetry_bliss.cpp
|
||||
+++ b/src/symmetry/compute_symmetry_bliss.cpp
|
||||
@@ -25,5 +25,5 @@
|
||||
#include "compute_symmetry.h"
|
||||
|
||||
/* include bliss graph */
|
||||
-#include <bliss/defs.hh>
|
||||
-#include <bliss/graph.hh>
|
||||
+#include <bliss-0.73/defs.hh>
|
||||
+#include <bliss-0.73/graph.hh>
|
||||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
diff --git a/src/scip/githash.c b/src/scip/githash.c
|
||||
new file mode 100644
|
||||
index 0000000000..2891bc72de
|
||||
--- /dev/null
|
||||
+++ b/src/scip/githash.c
|
||||
@@ -0,0 +1 @@
|
||||
@@ -0,0 +1,1 @@
|
||||
+#define SCIP_GITHASH "a740f0891e"
|
||||
diff --git a/src/scip/heur_xyz.c b/src/scip/heur_xyz.c
|
||||
index 9f7d804f4d..e33bb83b7c 100644
|
||||
--- a/src/scip/heur_xyz.c
|
||||
+++ b/src/scip/heur_xyz.c
|
||||
@@ -46,6 +46,7 @@
|
||||
/** primal heuristic data */
|
||||
struct SCIP_HeurData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/nlhdlr_xyz.c b/src/scip/nlhdlr_xyz.c
|
||||
index bc90f3dafe..056af7b6d3 100644
|
||||
--- a/src/scip/nlhdlr_xyz.c
|
||||
+++ b/src/scip/nlhdlr_xyz.c
|
||||
@@ -40,11 +40,13 @@
|
||||
/** nonlinear handler data */
|
||||
struct SCIP_NlhdlrData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
/** nonlinear handler expression data */
|
||||
struct SCIP_NlhdlrExprData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
/*
|
||||
diff --git a/src/scip/nlpi_xyz.c b/src/scip/nlpi_xyz.c
|
||||
index 3509410b23..901433d2d4 100644
|
||||
--- a/src/scip/nlpi_xyz.c
|
||||
+++ b/src/scip/nlpi_xyz.c
|
||||
@@ -43,12 +43,14 @@
|
||||
|
||||
struct SCIP_NlpiData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
/* TODO: fill in the necessary NLP problem instance data */
|
||||
|
||||
struct SCIP_NlpiProblem
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/nodesel_xyz.c b/src/scip/nodesel_xyz.c
|
||||
index a5b6d9d7d6..0aacc3c8d2 100644
|
||||
--- a/src/scip/nodesel_xyz.c
|
||||
+++ b/src/scip/nodesel_xyz.c
|
||||
@@ -41,6 +41,7 @@
|
||||
/** node selector data */
|
||||
struct SCIP_NodeselData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/presol_xyz.c b/src/scip/presol_xyz.c
|
||||
index 38ba9df72e..04fe8605f5 100644
|
||||
--- a/src/scip/presol_xyz.c
|
||||
+++ b/src/scip/presol_xyz.c
|
||||
@@ -42,6 +42,7 @@
|
||||
/** presolver data */
|
||||
struct SCIP_PresolData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/pricer_xyz.c b/src/scip/pricer_xyz.c
|
||||
index 16c968b951..5090a91e35 100644
|
||||
--- a/src/scip/pricer_xyz.c
|
||||
+++ b/src/scip/pricer_xyz.c
|
||||
@@ -43,6 +43,7 @@
|
||||
/** variable pricer data */
|
||||
struct SCIP_PricerData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -204,7 +205,7 @@ SCIP_RETCODE SCIPincludePricerXyz(
|
||||
* new callbacks are added in future SCIP versions
|
||||
*/
|
||||
SCIP_CALL( SCIPincludePricer(scip, PRICER_NAME, PRICER_DESC, PRICER_PRIORITY, PRICER_DELAY,
|
||||
- pricerCopyXyz, pricerFreeXyz, pricerInitXyz, pricerExitXyz,
|
||||
+ pricerCopyXyz, pricerFreeXyz, pricerInitXyz, pricerExitXyz,
|
||||
pricerInitsolXyz, pricerExitsolXyz, pricerRedcostXyz, pricerFarkasXyz,
|
||||
pricerdata) );
|
||||
#else
|
||||
diff --git a/src/scip/prop_xyz.c b/src/scip/prop_xyz.c
|
||||
index 431d8e909b..975564f12b 100644
|
||||
--- a/src/scip/prop_xyz.c
|
||||
+++ b/src/scip/prop_xyz.c
|
||||
@@ -28,7 +28,7 @@
|
||||
/* fundamental propagator properties */
|
||||
#define PROP_NAME "xyz"
|
||||
#define PROP_DESC "propagator template"
|
||||
-#define PROP_PRIORITY 0 /**< propagator priority */
|
||||
+#define PROP_PRIORITY 0 /**< propagator priority */
|
||||
#define PROP_FREQ 10 /**< propagator frequency */
|
||||
#define PROP_DELAY FALSE /**< should propagation method be delayed, if other propagators found reductions? */
|
||||
#define PROP_TIMING SCIP_PROPTIMING_BEFORELP/**< propagation timing mask */
|
||||
@@ -50,6 +50,7 @@
|
||||
/** propagator data */
|
||||
struct SCIP_PropData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/reader_xyz.c b/src/scip/reader_xyz.c
|
||||
index 08e5a6ff7b..c8fdd9d4f5 100644
|
||||
--- a/src/scip/reader_xyz.c
|
||||
+++ b/src/scip/reader_xyz.c
|
||||
@@ -40,6 +40,7 @@
|
||||
/** data for xyz reader */
|
||||
struct SCIP_ReaderData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/relax_xyz.c b/src/scip/relax_xyz.c
|
||||
index 4d4acc80b3..74dfbda91f 100644
|
||||
--- a/src/scip/relax_xyz.c
|
||||
+++ b/src/scip/relax_xyz.c
|
||||
@@ -43,6 +43,7 @@
|
||||
/** relaxator data */
|
||||
struct SCIP_RelaxData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/scipbuildflags.c b/src/scip/scipbuildflags.c
|
||||
index b54b9112cb..dc8e62b5e0 100644
|
||||
--- a/src/scip/scipbuildflags.c
|
||||
+++ b/src/scip/scipbuildflags.c
|
||||
@@ -21,10 +21,9 @@
|
||||
|
||||
|
||||
/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
|
||||
|
||||
|
||||
+#define SCIP_BUILDFLAGS " ARCH=x86_64\n COMP=gnu\n DEBUGSOL=false\n EXPRINT=none\n GAMS=false\n SYM=bliss\n GMP=false\n IPOPT=false\n IPOPTOPT=opt\n WORHP=false\n WORHPOPT=opt\n LPS=spx2\n LPSCHECK=false\n LPSOPT=opt\n NOBLKBUFMEM=false\n NOBLKMEM=false\n NOBUFMEM=false\n OPT=opt\n OSTYPE=linux\n PARASCIP=true\n READLINE=false\n SANITIZE=\n SHARED=false\n USRARFLAGS=\n USRCFLAGS=-fPIC\n USRCXXFLAGS=-fPIC\n USRDFLAGS=\n USRFLAGS=\n USRLDFLAGS=\n USROFLAGS=\n VERSION=7.0.1\n ZIMPL=false\n ZIMPLOPT=opt\n ZLIB=true"
|
||||
+
|
||||
#include "scip/scipbuildflags.h"
|
||||
-#ifdef NO_CONFIG_HEADER
|
||||
-#include "buildflags.c"
|
||||
-#endif
|
||||
|
||||
|
||||
/** returns the flags that were used to build SCIP */
|
||||
const char* SCIPgetBuildFlags(
|
||||
diff --git a/src/scip/sepa_xyz.c b/src/scip/sepa_xyz.c
|
||||
index 40d3c1c5f7..f68658951d 100644
|
||||
--- a/src/scip/sepa_xyz.c
|
||||
+++ b/src/scip/sepa_xyz.c
|
||||
@@ -44,6 +44,7 @@
|
||||
/** separator data */
|
||||
struct SCIP_SepaData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/scip/table_xyz.c b/src/scip/table_xyz.c
|
||||
index 2c93a43235..4f1fd28de4 100644
|
||||
--- a/src/scip/table_xyz.c
|
||||
+++ b/src/scip/table_xyz.c
|
||||
@@ -43,6 +43,7 @@
|
||||
/** statistics table data */
|
||||
struct SCIP_TableData
|
||||
{
|
||||
+ void* ptr;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/symmetry/compute_symmetry_bliss.cpp b/src/symmetry/compute_symmetry_bliss.cpp
|
||||
index 484627c4b9..27c2895165 100644
|
||||
--- a/src/symmetry/compute_symmetry_bliss.cpp
|
||||
+++ b/src/symmetry/compute_symmetry_bliss.cpp
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "compute_symmetry.h"
|
||||
|
||||
/* include bliss graph */
|
||||
-#include <bliss/defs.hh>
|
||||
-#include <bliss/graph.hh>
|
||||
+#include <bliss-0.73/defs.hh>
|
||||
+#include <bliss-0.73/graph.hh>
|
||||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
@@ -247,7 +247,7 @@ if(BUILD_SCIP)
|
||||
scip
|
||||
GIT_REPOSITORY "https://github.com/scipopt/scip.git"
|
||||
GIT_TAG "v804"
|
||||
#PATCH_COMMAND git apply --ignore-whitespace "${CMAKE_CURRENT_LIST_DIR}/../../patches/scip-v804.patch"
|
||||
PATCH_COMMAND git apply --ignore-whitespace "${CMAKE_CURRENT_LIST_DIR}/../../patches/scip-v804.patch"
|
||||
)
|
||||
FetchContent_MakeAvailable(scip)
|
||||
set(LPI_GLOP_SRC ${scip_SOURCE_DIR}/src/lpi/lpi_glop.cpp PARENT_SCOPE)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "ortools/base/logging.h"
|
||||
#include "zlib.h"
|
||||
|
||||
bool GunzipString(const std::string& str, std::string* out) {
|
||||
bool GunzipString(absl::string_view str, std::string* out) {
|
||||
z_stream zs;
|
||||
zs.zalloc = Z_NULL;
|
||||
zs.zfree = Z_NULL;
|
||||
|
||||
@@ -103,10 +103,8 @@ void DumpLinearProgramIfRequiredByFlags(const LinearProgram& linear_program,
|
||||
const ProtoWriteFormat write_format = absl::GetFlag(FLAGS_lp_dump_binary_file)
|
||||
? ProtoWriteFormat::kProtoBinary
|
||||
: ProtoWriteFormat::kProtoText;
|
||||
if (!WriteProtoToFile(filespec, proto, write_format,
|
||||
absl::GetFlag(FLAGS_lp_dump_compressed_file))) {
|
||||
LOG(DFATAL) << "Could not write " << filespec;
|
||||
}
|
||||
CHECK_OK(WriteProtoToFile(filespec, proto, write_format,
|
||||
absl::GetFlag(FLAGS_lp_dump_compressed_file)));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -317,7 +317,17 @@ public final class ModelBuilder {
|
||||
* @return true if the model was correctly written.
|
||||
*/
|
||||
public boolean exportToFile(String file) {
|
||||
return helper.writeModelToFile(file);
|
||||
return helper.writeModelToProtoFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* import the model from protocol buffer 'file'.
|
||||
*
|
||||
* @param file file to read the model from.
|
||||
* @return true if the model was correctly loaded.
|
||||
*/
|
||||
public boolean importFromFile(String file) {
|
||||
return helper.readModelFromProtoFile(file);
|
||||
}
|
||||
|
||||
public String exportToMpsString(boolean obfuscate) {
|
||||
|
||||
@@ -376,7 +376,17 @@ public class Model
|
||||
///@return true if the model was correctly written.
|
||||
public bool ExportToFile(String file)
|
||||
{
|
||||
return helper_.WriteModelToFile(file);
|
||||
return helper_.WriteModelToProtoFile(file);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// load the model as a protocol buffer from 'file'.
|
||||
/// </summary>
|
||||
/// @param file file to read the model from.
|
||||
///@return true if the model was correctly loaded.
|
||||
public bool ImportFromFile(String file)
|
||||
{
|
||||
return helper_.ReadModelFromProtoFile(file);
|
||||
}
|
||||
|
||||
public String ExportToMpsString(bool obfuscate)
|
||||
|
||||
@@ -116,7 +116,8 @@ VECTOR_AS_CSHARP_ARRAY(double, double, double, DoubleVector);
|
||||
%rename (ConstraintsCount) operations_research::ModelBuilderHelper::num_constraints;
|
||||
%rename (Name) operations_research::ModelBuilderHelper::name;
|
||||
%unignore operations_research::ModelBuilderHelper::SetName;
|
||||
%unignore operations_research::ModelBuilderHelper::WriteModelToFile;
|
||||
%unignore operations_research::ModelBuilderHelper::ReadModelFromProtoFile;
|
||||
%unignore operations_research::ModelBuilderHelper::WriteModelToProtoFile;
|
||||
%unignore operations_research::ModelBuilderHelper::ImportFromMpsString;
|
||||
%unignore operations_research::ModelBuilderHelper::ImportFromMpsFile;
|
||||
%unignore operations_research::ModelBuilderHelper::ImportFromLpString;
|
||||
|
||||
@@ -174,7 +174,8 @@ class GlobalRefGuard {
|
||||
%rename (numConstraints) operations_research::ModelBuilderHelper::num_constraints;
|
||||
%rename (getName) operations_research::ModelBuilderHelper::name;
|
||||
%rename (setName) operations_research::ModelBuilderHelper::SetName;
|
||||
%rename (writeModelToFile) operations_research::ModelBuilderHelper::WriteModelToFile;
|
||||
%rename (readModelFromProtoFile) operations_research::ModelBuilderHelper::ReadModelFromProtoFile;
|
||||
%rename (writeModelToProtoFile) operations_research::ModelBuilderHelper::WriteModelToProtoFile;
|
||||
%rename (importFromMpsString) operations_research::ModelBuilderHelper::ImportFromMpsString;
|
||||
%rename (importFromMpsFile) operations_research::ModelBuilderHelper::ImportFromMpsFile;
|
||||
%rename (importFromLpString) operations_research::ModelBuilderHelper::ImportFromLpString;
|
||||
|
||||
@@ -578,12 +578,19 @@ class MPSolver {
|
||||
* from `MPSolver::Solve()` which by default sets the feasibility tolerance
|
||||
* and the gap limit (as of 2020/02/11, to 1e-7 and 0.0001, respectively).
|
||||
*/
|
||||
#if !defined(SWIG)
|
||||
ABSL_DEPRECATED("Prefer SolveMPModel() from solve_mp_model.h.")
|
||||
#endif // !defined(SWIG)
|
||||
static void SolveWithProto(const MPModelRequest& model_request,
|
||||
MPSolutionResponse* response,
|
||||
// `interrupt` is non-const because the internal
|
||||
// solver may set it to true itself, in some cases.
|
||||
std::atomic<bool>* interrupt = nullptr);
|
||||
|
||||
#if !defined(SWIG)
|
||||
ABSL_DEPRECATED(
|
||||
"Prefer SolverTypeSupportsInterruption() from solve_mp_model.h.")
|
||||
#endif // !defined(SWIG)
|
||||
static bool SolverTypeSupportsInterruption(
|
||||
const MPModelRequest::SolverType solver) {
|
||||
// Interruption requires that MPSolver::InterruptSolve is supported for the
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
|
||||
@@ -51,12 +52,12 @@ int main(int argc, char** argv) {
|
||||
operations_research::MPModelProto model_proto;
|
||||
if (absl::GetFlag(FLAGS_input_is_mp_model_request)) {
|
||||
operations_research::MPModelRequest request_proto;
|
||||
CHECK(operations_research::ReadFileToProto(absl::GetFlag(FLAGS_input),
|
||||
&request_proto));
|
||||
CHECK_OK(operations_research::ReadFileToProto(absl::GetFlag(FLAGS_input),
|
||||
&request_proto));
|
||||
model_proto.Swap(request_proto.mutable_model());
|
||||
} else {
|
||||
CHECK(operations_research::ReadFileToProto(absl::GetFlag(FLAGS_input),
|
||||
&model_proto));
|
||||
CHECK_OK(operations_research::ReadFileToProto(absl::GetFlag(FLAGS_input),
|
||||
&model_proto));
|
||||
}
|
||||
std::string output_contents;
|
||||
operations_research::MPModelExportOptions options;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <string>
|
||||
|
||||
#include "ortools/linear_solver/linear_solver.pb.h"
|
||||
#include "ortools/sat/sat_parameters.pb.h"
|
||||
#include "ortools/util/logging.h"
|
||||
|
||||
namespace operations_research {
|
||||
@@ -29,7 +28,7 @@ namespace operations_research {
|
||||
// If possible, std::move the request into this function call to avoid a copy.
|
||||
//
|
||||
// If you need to change the solver parameters, please use the
|
||||
// EncodeSatParametersAsString() function below to set the request's
|
||||
// EncodeParametersAsString() function to set the request's
|
||||
// solver_specific_parameters field.
|
||||
//
|
||||
// The optional interrupt_solve can be used to interrupt the solve early. It
|
||||
|
||||
@@ -1460,11 +1460,11 @@ class Model:
|
||||
|
||||
# Objective.
|
||||
def minimize(self, linear_expr: LinearExprT) -> None:
|
||||
"""Minimize the given objective."""
|
||||
"""Minimizes the given objective."""
|
||||
self.__optimize(linear_expr, False)
|
||||
|
||||
def maximize(self, linear_expr: LinearExprT) -> None:
|
||||
"""Maximize the given objective."""
|
||||
"""Maximizes the given objective."""
|
||||
self.__optimize(linear_expr, True)
|
||||
|
||||
def __optimize(self, linear_expr: LinearExprT, maximize: bool) -> None:
|
||||
@@ -1507,11 +1507,11 @@ class Model:
|
||||
|
||||
# Hints.
|
||||
def clear_hints(self):
|
||||
"""Clear all solution hints."""
|
||||
"""Clears all solution hints."""
|
||||
self.__helper.clear_hints()
|
||||
|
||||
def add_hint(self, var: Variable, value: NumberT) -> None:
|
||||
"""Add var == value as a hint to the model.
|
||||
"""Adds var == value as a hint to the model.
|
||||
|
||||
Args:
|
||||
var: The variable of the hint
|
||||
@@ -1537,28 +1537,28 @@ class Model:
|
||||
return mbh.to_mpmodel_proto(self.__helper)
|
||||
|
||||
def import_from_mps_string(self, mps_string: str) -> bool:
|
||||
"""Loads the a model from an MPS string."""
|
||||
"""Reads a model from a MPS string."""
|
||||
return self.__helper.import_from_mps_string(mps_string)
|
||||
|
||||
def import_from_mps_file(self, mps_file: str) -> bool:
|
||||
"""Loads the a model from an MPS file."""
|
||||
"""Reads a model from a .mps file."""
|
||||
return self.__helper.import_from_mps_file(mps_file)
|
||||
|
||||
def import_from_lp_string(self, lp_string: str) -> bool:
|
||||
"""Loads the a model from an LP string."""
|
||||
"""Reads a model from a LP string."""
|
||||
return self.__helper.import_from_lp_string(lp_string)
|
||||
|
||||
def import_from_lp_file(self, lp_file: str) -> bool:
|
||||
"""Loads the a model from an LP file."""
|
||||
"""Reads a model from a .lp file."""
|
||||
return self.__helper.import_from_lp_file(lp_file)
|
||||
|
||||
def import_from_proto_file(self, proto_file: str) -> bool:
|
||||
"""Loads the a model from an proto file."""
|
||||
return self.__helper.load_model_from_file(proto_file)
|
||||
"""Reads a model from a proto file."""
|
||||
return self.__helper.read_model_from_proto_file(proto_file)
|
||||
|
||||
def export_to_proto_file(self, proto_file: str) -> bool:
|
||||
"""Write a model to a proto file."""
|
||||
return self.__helper.write_model_to_file(proto_file)
|
||||
"""Writes a model to a proto file."""
|
||||
return self.__helper.write_model_to_proto_file(proto_file)
|
||||
|
||||
# Model getters and Setters
|
||||
|
||||
|
||||
@@ -175,10 +175,10 @@ PYBIND11_MODULE(model_builder_helper, m) {
|
||||
arg("options") = MPModelExportOptions())
|
||||
.def("export_to_lp_string", &ModelBuilderHelper::ExportToLpString,
|
||||
arg("options") = MPModelExportOptions())
|
||||
.def("write_model_to_file", &ModelBuilderHelper::WriteModelToFile,
|
||||
arg("filename"))
|
||||
.def("load_model_from_file", &ModelBuilderHelper::LoadModelFromFile,
|
||||
arg("filename"))
|
||||
.def("read_model_from_proto_file",
|
||||
&ModelBuilderHelper::ReadModelFromProtoFile, arg("filename"))
|
||||
.def("write_model_to_proto_file",
|
||||
&ModelBuilderHelper::WriteModelToProtoFile, arg("filename"))
|
||||
.def("import_from_mps_string", &ModelBuilderHelper::ImportFromMpsString,
|
||||
arg("mps_string"))
|
||||
.def("import_from_mps_file", &ModelBuilderHelper::ImportFromMpsFile,
|
||||
|
||||
@@ -32,7 +32,7 @@ def main(argv: Sequence[str]) -> None:
|
||||
|
||||
model = model_builder.ModelBuilder()
|
||||
|
||||
# Load MPS file.
|
||||
# Load MPS or proto file.
|
||||
if _INPUT.value.endswith(".mps"):
|
||||
if not model.import_from_mps_file(_INPUT.value):
|
||||
print(f"Cannot import MPS file: '{_INPUT.value}'")
|
||||
@@ -41,7 +41,6 @@ def main(argv: Sequence[str]) -> None:
|
||||
print(f"Cannot import Proto file: '{_INPUT.value}'")
|
||||
return
|
||||
|
||||
|
||||
# Create solver.
|
||||
solver = model_builder.ModelSolver(_SOLVER.value)
|
||||
if not solver.solver_is_supported():
|
||||
|
||||
@@ -30,6 +30,7 @@ def create_data_model():
|
||||
data["bins"] = data["items"]
|
||||
data["bin_capacity"] = 100
|
||||
return data
|
||||
|
||||
# [END data_model]
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ def create_data_model():
|
||||
data["num_vars"] = 5
|
||||
data["num_constraints"] = 4
|
||||
return data
|
||||
|
||||
# [END data_model]
|
||||
|
||||
|
||||
|
||||
@@ -146,8 +146,8 @@ MPModelRequest ReadMipModel(const std::string& input) {
|
||||
QCHECK_OK(glop::MPSReader().ParseFile(input, &model_proto))
|
||||
<< "Error while parsing the mps file '" << input << "'.";
|
||||
} else {
|
||||
ReadFileToProto(input, &model_proto);
|
||||
ReadFileToProto(input, &request_proto);
|
||||
ReadFileToProto(input, &model_proto).IgnoreError();
|
||||
ReadFileToProto(input, &request_proto).IgnoreError();
|
||||
}
|
||||
// If the input is a proto in binary format, both ReadFileToProto could
|
||||
// return true. Instead use the actual number of variables found to test the
|
||||
@@ -326,13 +326,13 @@ void Run() {
|
||||
|
||||
// If requested, save the model and/or request to file.
|
||||
if (!absl::GetFlag(FLAGS_dump_model).empty()) {
|
||||
CHECK(WriteProtoToFile(absl::GetFlag(FLAGS_dump_model),
|
||||
request_proto.model(), write_format,
|
||||
absl::GetFlag(FLAGS_dump_gzip)));
|
||||
CHECK_OK(WriteProtoToFile(absl::GetFlag(FLAGS_dump_model),
|
||||
request_proto.model(), write_format,
|
||||
absl::GetFlag(FLAGS_dump_gzip)));
|
||||
}
|
||||
if (!absl::GetFlag(FLAGS_dump_request).empty()) {
|
||||
CHECK(WriteProtoToFile(absl::GetFlag(FLAGS_dump_request), request_proto,
|
||||
write_format, absl::GetFlag(FLAGS_dump_gzip)));
|
||||
CHECK_OK(WriteProtoToFile(absl::GetFlag(FLAGS_dump_request), request_proto,
|
||||
write_format, absl::GetFlag(FLAGS_dump_gzip)));
|
||||
}
|
||||
|
||||
absl::PrintF(
|
||||
@@ -377,8 +377,8 @@ void Run() {
|
||||
file::Defaults()));
|
||||
}
|
||||
if (!absl::GetFlag(FLAGS_dump_response).empty() && has_solution) {
|
||||
CHECK(WriteProtoToFile(absl::GetFlag(FLAGS_dump_response), response,
|
||||
write_format, absl::GetFlag(FLAGS_dump_gzip)));
|
||||
CHECK_OK(WriteProtoToFile(absl::GetFlag(FLAGS_dump_response), response,
|
||||
write_format, absl::GetFlag(FLAGS_dump_gzip)));
|
||||
}
|
||||
if (!absl::GetFlag(FLAGS_output_csv).empty() && has_solution) {
|
||||
std::string csv_file;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "ortools/base/helpers.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/base/options.h"
|
||||
#include "ortools/linear_solver/linear_solver.h"
|
||||
#include "ortools/linear_solver/linear_solver.pb.h"
|
||||
@@ -60,24 +61,28 @@ std::string ModelBuilderHelper::ExportToLpString(
|
||||
.value_or("");
|
||||
}
|
||||
|
||||
bool ModelBuilderHelper::WriteModelToFile(const std::string& filename) {
|
||||
if (absl::EndsWith(filename, "txt") ||
|
||||
absl::EndsWith(filename, ".textproto")) {
|
||||
bool ModelBuilderHelper::ReadModelFromProtoFile(const std::string& filename) {
|
||||
if (file::GetTextProto(filename, &model_, file::Defaults()).ok() ||
|
||||
file::GetBinaryProto(filename, &model_, file::Defaults()).ok()) {
|
||||
return true;
|
||||
}
|
||||
MPModelRequest request;
|
||||
if (file::GetTextProto(filename, &request, file::Defaults()).ok() ||
|
||||
file::GetBinaryProto(filename, &request, file::Defaults()).ok()) {
|
||||
model_ = request.model();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModelBuilderHelper::WriteModelToProtoFile(const std::string& filename) {
|
||||
if (absl::EndsWith(filename, "txt")) {
|
||||
return file::SetTextProto(filename, model_, file::Defaults()).ok();
|
||||
} else {
|
||||
return file::SetBinaryProto(filename, model_, file::Defaults()).ok();
|
||||
}
|
||||
}
|
||||
|
||||
bool ModelBuilderHelper::LoadModelFromFile(const std::string& filename) {
|
||||
if (absl::EndsWith(filename, "txt") ||
|
||||
absl::EndsWith(filename, ".textproto")) {
|
||||
return file::GetTextProto(filename, &model_, file::Defaults()).ok();
|
||||
} else {
|
||||
return file::GetBinaryProto(filename, &model_, file::Defaults()).ok();
|
||||
}
|
||||
}
|
||||
|
||||
// See comment in the header file why we need to wrap absl::Status code with
|
||||
// code having simpler APIs.
|
||||
bool ModelBuilderHelper::ImportFromMpsString(const std::string& mps_string) {
|
||||
|
||||
@@ -50,8 +50,8 @@ class ModelBuilderHelper {
|
||||
options = MPModelExportOptions());
|
||||
std::string ExportToLpString(const operations_research::MPModelExportOptions&
|
||||
options = MPModelExportOptions());
|
||||
bool WriteModelToFile(const std::string& filename);
|
||||
bool LoadModelFromFile(const std::string& filename);
|
||||
bool ReadModelFromProtoFile(const std::string& filename);
|
||||
bool WriteModelToProtoFile(const std::string& filename);
|
||||
|
||||
bool ImportFromMpsString(const std::string& mps_string);
|
||||
bool ImportFromMpsFile(const std::string& mps_file);
|
||||
|
||||
@@ -29,8 +29,8 @@ bool LoadMPModelProtoFromModelOrRequest(const std::string& input_file_path,
|
||||
MPModelProto* model) {
|
||||
MPModelProto model_proto;
|
||||
MPModelRequest request_proto;
|
||||
ReadFileToProto(input_file_path, &model_proto);
|
||||
ReadFileToProto(input_file_path, &request_proto);
|
||||
ReadFileToProto(input_file_path, &model_proto).IgnoreError();
|
||||
ReadFileToProto(input_file_path, &request_proto).IgnoreError();
|
||||
// If the input proto is in binary format, both ReadFileToProto could return
|
||||
// true. Instead use the actual number of variables found to test the
|
||||
// correct format of the input.
|
||||
|
||||
@@ -183,8 +183,5 @@ py_library(
|
||||
name = "normalize",
|
||||
srcs = ["normalize.py"],
|
||||
visibility = ["//ortools/math_opt/python:__subpackages__"],
|
||||
deps = [
|
||||
# "@com_google_protobuf//protobuf:duration_py_pb2",
|
||||
"@com_google_protobuf//:protobuf_python",
|
||||
],
|
||||
deps = ["@com_google_protobuf//:protobuf_python"],
|
||||
)
|
||||
|
||||
@@ -215,8 +215,8 @@ cc_library(
|
||||
"//ortools/base:protoutil",
|
||||
"//ortools/base:status_macros",
|
||||
"//ortools/linear_solver:linear_solver_cc_proto",
|
||||
"//ortools/linear_solver/proto_solver:sat_proto_solver",
|
||||
"//ortools/linear_solver/proto_solver:proto_utils",
|
||||
"//ortools/linear_solver/proto_solver:sat_proto_solver",
|
||||
"//ortools/math_opt:callback_cc_proto",
|
||||
"//ortools/math_opt:infeasible_subsystem_cc_proto",
|
||||
"//ortools/math_opt:model_cc_proto",
|
||||
|
||||
@@ -69,7 +69,8 @@ QuadraticProgram ReadQuadraticProgramOrDie(const std::string& filename,
|
||||
QuadraticProgram ReadMPModelProtoFileOrDie(
|
||||
const std::string& mpmodel_proto_file, bool include_names) {
|
||||
MPModelProto lp_proto;
|
||||
QCHECK(ReadFileToProto(mpmodel_proto_file, &lp_proto)) << mpmodel_proto_file;
|
||||
QCHECK_OK(ReadFileToProto(mpmodel_proto_file, &lp_proto))
|
||||
<< mpmodel_proto_file;
|
||||
auto result = QpFromMpModelProto(lp_proto, /*relax_integer_variables=*/true,
|
||||
include_names);
|
||||
QCHECK_OK(result);
|
||||
|
||||
@@ -98,7 +98,7 @@ bool LoadProblem(const std::string& filename, CpModelProto* cp_model) {
|
||||
}
|
||||
} else {
|
||||
LOG(INFO) << "Reading a CpModelProto.";
|
||||
*cp_model = ReadFileToProtoOrDie<CpModelProto>(filename);
|
||||
CHECK_OK(ReadFileToProto(filename, cp_model));
|
||||
}
|
||||
if (cp_model->name().empty()) {
|
||||
cp_model->set_name(ExtractName(filename));
|
||||
|
||||
@@ -295,6 +295,7 @@ cc_library(
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings",
|
||||
"//ortools/base",
|
||||
"//ortools/base:dump_vars",
|
||||
"//ortools/base:file",
|
||||
"//ortools/base:hash",
|
||||
"//ortools/base:recordio",
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
#include <string>
|
||||
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "google/protobuf/io/tokenizer.h"
|
||||
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
|
||||
#include "google/protobuf/json/json.h"
|
||||
#include "google/protobuf/message.h"
|
||||
@@ -45,17 +48,23 @@ absl::StatusOr<std::string> ReadFileToString(absl::string_view filename) {
|
||||
return contents;
|
||||
}
|
||||
|
||||
bool ReadFileToProto(absl::string_view filename,
|
||||
google::protobuf::Message* proto, bool allow_partial) {
|
||||
absl::Status ReadFileToProto(absl::string_view filename,
|
||||
google::protobuf::Message* proto,
|
||||
bool allow_partial) {
|
||||
std::string data;
|
||||
CHECK_OK(file::GetContents(filename, &data, file::Defaults()));
|
||||
RETURN_IF_ERROR(file::GetContents(filename, &data, file::Defaults()));
|
||||
return util::StatusBuilder(StringToProto(data, proto, allow_partial))
|
||||
<< " in file '" << filename << "'";
|
||||
}
|
||||
|
||||
absl::Status StringToProto(absl::string_view data,
|
||||
google::protobuf::Message* proto,
|
||||
bool allow_partial) {
|
||||
// Try decompressing it.
|
||||
{
|
||||
std::string uncompressed;
|
||||
if (GunzipString(data, &uncompressed)) {
|
||||
VLOG(1) << "ReadFileToProto(): input is gzipped";
|
||||
data.swap(uncompressed);
|
||||
}
|
||||
std::string uncompressed;
|
||||
if (GunzipString(data, &uncompressed)) {
|
||||
VLOG(1) << "ReadFileToProto(): input is gzipped";
|
||||
data = uncompressed;
|
||||
}
|
||||
// Try binary format first, then text format, then JSON, then proto3 JSON,
|
||||
// then give up.
|
||||
@@ -68,6 +77,7 @@ bool ReadFileToProto(absl::string_view filename,
|
||||
// the case that the proto version changed and some fields are dropped.
|
||||
// We just fail when the difference is too large.
|
||||
constexpr double kMaxBinaryProtoParseShrinkFactor = 2;
|
||||
std::string binary_format_error;
|
||||
if (proto->ParsePartialFromString(data) &&
|
||||
(allow_partial || proto->IsInitialized())) {
|
||||
// NOTE(user): When using ParseFromString() from a generic
|
||||
@@ -78,60 +88,76 @@ bool ReadFileToProto(absl::string_view filename,
|
||||
proto->DiscardUnknownFields();
|
||||
if (proto->ByteSizeLong() <
|
||||
data.size() / kMaxBinaryProtoParseShrinkFactor) {
|
||||
VLOG(1) << "ReadFileToProto(): input may be a binary proto, but of a "
|
||||
"different proto";
|
||||
binary_format_error =
|
||||
"The input may be a binary protobuf payload, but it"
|
||||
" probably is from a different proto class";
|
||||
} else {
|
||||
VLOG(1) << "ReadFileToProto(): input seems to be a binary proto";
|
||||
return true;
|
||||
VLOG(1) << "StringToProto(): input seems to be a binary proto";
|
||||
return absl::OkStatus();
|
||||
}
|
||||
}
|
||||
|
||||
struct : public google::protobuf::io::ErrorCollector {
|
||||
void RecordError(int line, google::protobuf::io::ColumnNumber column,
|
||||
absl::string_view error_message) override {
|
||||
if (!message.empty()) message += ", ";
|
||||
absl::StrAppendFormat(&message, "%d:%d: %s",
|
||||
// We convert the 0-indexed line to 1-indexed.
|
||||
line + 1, column, error_message);
|
||||
}
|
||||
std::string message;
|
||||
} text_format_error;
|
||||
google::protobuf::TextFormat::Parser text_parser;
|
||||
text_parser.RecordErrorsTo(&text_format_error);
|
||||
text_parser.AllowPartialMessage(allow_partial);
|
||||
if (text_parser.ParseFromString(data, proto)) {
|
||||
VLOG(1) << "ReadFileToProto(): input is a text proto";
|
||||
return true;
|
||||
VLOG(1) << "StringToProto(): input is a text proto";
|
||||
return absl::OkStatus();
|
||||
}
|
||||
// We use `auto` here since protobuf does not use absl::Status.
|
||||
const auto status = JsonStringToMessage(data, proto, JsonParseOptions());
|
||||
if (!status.ok()) {
|
||||
VLOG(1) << status;
|
||||
} else {
|
||||
std::string json_error;
|
||||
absl::Status json_status =
|
||||
JsonStringToMessage(data, proto, JsonParseOptions());
|
||||
if (json_status.ok()) {
|
||||
// NOTE(user): We protect against the JSON proto3 parser being very lenient
|
||||
// and easily accepting any JSON as a valid JSON for our proto: if the
|
||||
// parsed proto's size is too small compared to the JSON, we probably parsed
|
||||
// a JSON that wasn't representing a valid proto.
|
||||
constexpr int kMaxJsonToBinaryShrinkFactor = 30;
|
||||
if (proto->ByteSizeLong() < data.size() / kMaxJsonToBinaryShrinkFactor) {
|
||||
VLOG(1) << "ReadFileToProto(): input is probably JSON, but probably not"
|
||||
" of the right proto";
|
||||
json_status = absl::InvalidArgumentError(
|
||||
"The input looks like valid JSON, but probably not"
|
||||
" of the right proto class");
|
||||
} else {
|
||||
VLOG(1) << "ReadFileToProto(): input is a proto JSON";
|
||||
return true;
|
||||
VLOG(1) << "StringToProto(): input is a proto JSON";
|
||||
return absl::OkStatus();
|
||||
}
|
||||
}
|
||||
LOG(WARNING) << "Could not parse protocol buffer";
|
||||
return false;
|
||||
return absl::InvalidArgumentError(absl::StrFormat(
|
||||
"binary format error: '%s', text format error: '%s', json error: '%s'",
|
||||
binary_format_error, text_format_error.message, json_status.message()));
|
||||
}
|
||||
|
||||
bool WriteProtoToFile(absl::string_view filename,
|
||||
const google::protobuf::Message& proto,
|
||||
ProtoWriteFormat proto_write_format, bool gzipped,
|
||||
bool append_extension_to_file_name) {
|
||||
absl::Status WriteProtoToFile(absl::string_view filename,
|
||||
const google::protobuf::Message& proto,
|
||||
ProtoWriteFormat proto_write_format, bool gzipped,
|
||||
bool append_extension_to_file_name) {
|
||||
std::string file_type_suffix;
|
||||
std::string output_string;
|
||||
google::protobuf::io::StringOutputStream stream(&output_string);
|
||||
auto make_error = [filename](absl::string_view error_message) {
|
||||
return absl::InternalError(absl::StrFormat(
|
||||
"WriteProtoToFile('%s') failed: %s", filename, error_message));
|
||||
};
|
||||
switch (proto_write_format) {
|
||||
case ProtoWriteFormat::kProtoBinary:
|
||||
if (!proto.SerializeToZeroCopyStream(&stream)) {
|
||||
LOG(WARNING) << "Serialize to stream failed.";
|
||||
return false;
|
||||
return make_error("SerializeToZeroCopyStream()");
|
||||
}
|
||||
file_type_suffix = ".bin";
|
||||
break;
|
||||
case ProtoWriteFormat::kProtoText:
|
||||
if (!google::protobuf::TextFormat::PrintToString(proto, &output_string)) {
|
||||
LOG(WARNING) << "Printing to string failed.";
|
||||
return false;
|
||||
return make_error("TextFormat::PrintToString()");
|
||||
}
|
||||
break;
|
||||
case ProtoWriteFormat::kJson: {
|
||||
@@ -142,8 +168,7 @@ bool WriteProtoToFile(absl::string_view filename,
|
||||
if (!google::protobuf::util::MessageToJsonString(proto, &output_string,
|
||||
options)
|
||||
.ok()) {
|
||||
LOG(WARNING) << "Printing to stream failed.";
|
||||
return false;
|
||||
return make_error("Printing to stream failed.");
|
||||
}
|
||||
file_type_suffix = ".json";
|
||||
break;
|
||||
@@ -154,8 +179,7 @@ bool WriteProtoToFile(absl::string_view filename,
|
||||
if (!google::protobuf::util::MessageToJsonString(proto, &output_string,
|
||||
options)
|
||||
.ok()) {
|
||||
LOG(WARNING) << "Printing to stream failed.";
|
||||
return false;
|
||||
return make_error("Printing to stream failed.");
|
||||
}
|
||||
file_type_suffix = ".json";
|
||||
break;
|
||||
@@ -168,14 +192,9 @@ bool WriteProtoToFile(absl::string_view filename,
|
||||
}
|
||||
std::string output_filename(filename);
|
||||
if (append_extension_to_file_name) output_filename += file_type_suffix;
|
||||
VLOG(1) << "Writing " << output_string.size() << " bytes to "
|
||||
<< output_filename;
|
||||
if (!file::SetContents(output_filename, output_string, file::Defaults())
|
||||
.ok()) {
|
||||
LOG(WARNING) << "Writing to file failed.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
VLOG(1) << "Writing " << output_string.size() << " bytes to '"
|
||||
<< output_filename << "'";
|
||||
return file::SetContents(output_filename, output_string, file::Defaults());
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
|
||||
@@ -21,9 +21,11 @@
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "google/protobuf/message.h"
|
||||
#include "ortools/base/dump_vars.h"
|
||||
#include "ortools/base/file.h"
|
||||
#include "ortools/base/options.h"
|
||||
#include "ortools/base/recordio.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
@@ -31,23 +33,27 @@ namespace operations_research {
|
||||
absl::StatusOr<std::string> ReadFileToString(absl::string_view filename);
|
||||
|
||||
// Reads a proto from a file. Supports the following formats: binary, text,
|
||||
// JSON, all of those optionally gzipped. Crashes on filesystem failures, e.g.
|
||||
// file unreadable. Returns false on format failures, e.g. the file could be
|
||||
// read, but the contents couldn't be parsed -- or maybe it was a valid JSON,
|
||||
// text proto, or binary proto, but not of the right proto message.
|
||||
// Returns true on success.
|
||||
bool ReadFileToProto(absl::string_view filename,
|
||||
google::protobuf::Message* proto,
|
||||
// If true, unset required fields don't cause errors. This
|
||||
// boolean doesn't work for JSON inputs.
|
||||
bool allow_partial = false);
|
||||
// JSON, all of those optionally gzipped. Returns errors as expected: filesystem
|
||||
// error, parsing errors, or type error: maybe it was a valid JSON, text proto,
|
||||
// or binary proto, but not of the right proto message (this is not an exact
|
||||
// science, but the heuristics used should work well in practice).
|
||||
absl::Status ReadFileToProto(
|
||||
absl::string_view filename, google::protobuf::Message* proto,
|
||||
// If true, unset required fields don't cause errors. This
|
||||
// boolean doesn't work for JSON inputs.
|
||||
bool allow_partial = false);
|
||||
|
||||
// Exaclty like ReadFileToProto(), but directly from the contents.
|
||||
absl::Status StringToProto(absl::string_view data,
|
||||
google::protobuf::Message* proto,
|
||||
bool allow_partial = false);
|
||||
|
||||
template <typename Proto>
|
||||
Proto ReadFileToProtoOrDie(absl::string_view filename,
|
||||
bool allow_partial = false) {
|
||||
absl::StatusOr<Proto> ReadFileToProto(absl::string_view filename,
|
||||
bool allow_partial = false) {
|
||||
Proto proto;
|
||||
CHECK(ReadFileToProto(filename, &proto, allow_partial))
|
||||
<< "with file: '" << filename << "'";
|
||||
RETURN_IF_ERROR(ReadFileToProto(filename, &proto, allow_partial))
|
||||
<< DUMP_VARS(filename);
|
||||
return proto;
|
||||
}
|
||||
|
||||
@@ -56,14 +62,15 @@ Proto ReadFileToProtoOrDie(absl::string_view filename,
|
||||
enum class ProtoWriteFormat { kProtoText, kProtoBinary, kJson, kCanonicalJson };
|
||||
|
||||
// Writes a proto to a file. Supports the following formats: binary, text, JSON,
|
||||
// all of those optionally gzipped. Returns false on failure.
|
||||
// all of those optionally gzipped.
|
||||
// If 'proto_write_format' is kProtoBinary, ".bin" is appended to file_name. If
|
||||
// 'proto_write_format' is kJson or kCanonicalJson, ".json" is appended to
|
||||
// file_name. If 'gzipped' is true, ".gz" is appended to file_name.
|
||||
bool WriteProtoToFile(absl::string_view filename,
|
||||
const google::protobuf::Message& proto,
|
||||
ProtoWriteFormat proto_write_format, bool gzipped = false,
|
||||
bool append_extension_to_file_name = true);
|
||||
absl::Status WriteProtoToFile(absl::string_view filename,
|
||||
const google::protobuf::Message& proto,
|
||||
ProtoWriteFormat proto_write_format,
|
||||
bool gzipped = false,
|
||||
bool append_extension_to_file_name = true);
|
||||
|
||||
namespace internal {
|
||||
// General method to read expected_num_records from a file. If
|
||||
|
||||
Reference in New Issue
Block a user