add model I/O at the solver level
This commit is contained in:
@@ -27,6 +27,7 @@ CPBINARIES = \
|
||||
golomb$E \
|
||||
linear_assignment_example$E \
|
||||
magic_square$E \
|
||||
model_util \
|
||||
network_routing$E \
|
||||
nqueens$E \
|
||||
solve_dimacs_assignment$E \
|
||||
@@ -93,7 +94,9 @@ CONSTRAINT_SOLVER_LIB_OS = \
|
||||
objs/expressions.$O\
|
||||
objs/hybrid.$O\
|
||||
objs/interval.$O\
|
||||
objs/io.$O\
|
||||
objs/local_search.$O\
|
||||
objs/model.pb.$O\
|
||||
objs/nogoods.$O\
|
||||
objs/pack.$O\
|
||||
objs/range_cst.$O\
|
||||
@@ -116,11 +119,11 @@ objs/assignment.pb.$O:gen/constraint_solver/assignment.pb.cc
|
||||
$(CCC) $(CFLAGS) -c gen/constraint_solver/assignment.pb.cc $(OBJOUT)objs/assignment.pb.$O
|
||||
|
||||
gen/constraint_solver/assignment.pb.cc:constraint_solver/assignment.proto
|
||||
$(PROTOBUF_DIR)/bin/protoc --proto_path=constraint_solver --cpp_out=gen/constraint_solver constraint_solver/assignment.proto
|
||||
$(PROTOBUF_DIR)/bin/protoc --proto_path=. --cpp_out=gen constraint_solver/assignment.proto
|
||||
|
||||
gen/constraint_solver/assignment.pb.h:gen/constraint_solver/assignment.pb.cc
|
||||
|
||||
objs/constraint_solver.$O:constraint_solver/constraint_solver.cc
|
||||
objs/constraint_solver.$O:constraint_solver/constraint_solver.cc gen/constraint_solver/model.pb.h
|
||||
$(CCC) $(CFLAGS) -c constraint_solver/constraint_solver.cc $(OBJOUT)objs/constraint_solver.$O
|
||||
|
||||
objs/constraints.$O:constraint_solver/constraints.cc
|
||||
@@ -139,7 +142,7 @@ objs/demon_profiler.pb.$O:gen/constraint_solver/demon_profiler.pb.cc
|
||||
$(CCC) $(CFLAGS) -c gen/constraint_solver/demon_profiler.pb.cc $(OBJOUT)objs/demon_profiler.pb.$O
|
||||
|
||||
gen/constraint_solver/demon_profiler.pb.cc:constraint_solver/demon_profiler.proto
|
||||
$(PROTOBUF_DIR)/bin/protoc --proto_path=constraint_solver --cpp_out=gen/constraint_solver constraint_solver/demon_profiler.proto
|
||||
$(PROTOBUF_DIR)/bin/protoc --proto_path=. --cpp_out=gen constraint_solver/demon_profiler.proto
|
||||
|
||||
gen/constraint_solver/demon_profiler.pb.h:gen/constraint_solver/demon_profiler.pb.cc
|
||||
|
||||
@@ -164,9 +167,20 @@ objs/hybrid.$O:constraint_solver/hybrid.cc
|
||||
objs/interval.$O:constraint_solver/interval.cc
|
||||
$(CCC) $(CFLAGS) -c constraint_solver/interval.cc $(OBJOUT)objs/interval.$O
|
||||
|
||||
objs/io.$O:constraint_solver/io.cc gen/constraint_solver/model.pb.h
|
||||
$(CCC) $(CFLAGS) -c constraint_solver/io.cc $(OBJOUT)objs/io.$O
|
||||
|
||||
objs/local_search.$O:constraint_solver/local_search.cc
|
||||
$(CCC) $(CFLAGS) -c constraint_solver/local_search.cc $(OBJOUT)objs/local_search.$O
|
||||
|
||||
objs/model.pb.$O:gen/constraint_solver/model.pb.cc
|
||||
$(CCC) $(CFLAGS) -c gen/constraint_solver/model.pb.cc $(OBJOUT)objs/model.pb.$O
|
||||
|
||||
gen/constraint_solver/model.pb.cc:constraint_solver/model.proto
|
||||
$(PROTOBUF_DIR)/bin/protoc --proto_path=. --cpp_out=gen constraint_solver/model.proto
|
||||
|
||||
gen/constraint_solver/model.pb.h:gen/constraint_solver/model.pb.cc gen/constraint_solver/search_limit.pb.h
|
||||
|
||||
objs/nogoods.$O:constraint_solver/nogoods.cc
|
||||
$(CCC) $(CFLAGS) -c constraint_solver/nogoods.cc $(OBJOUT)objs/nogoods.$O
|
||||
|
||||
@@ -189,7 +203,7 @@ objs/search_limit.pb.$O:gen/constraint_solver/search_limit.pb.cc
|
||||
$(CCC) $(CFLAGS) -c gen/constraint_solver/search_limit.pb.cc $(OBJOUT)objs/search_limit.pb.$O
|
||||
|
||||
gen/constraint_solver/search_limit.pb.cc:constraint_solver/search_limit.proto
|
||||
$(PROTOBUF_DIR)/bin/protoc --proto_path=constraint_solver --cpp_out=gen/constraint_solver constraint_solver/search_limit.proto
|
||||
$(PROTOBUF_DIR)/bin/protoc --proto_path=. --cpp_out=gen constraint_solver/search_limit.proto
|
||||
|
||||
gen/constraint_solver/search_limit.pb.h:gen/constraint_solver/search_limit.pb.cc
|
||||
|
||||
@@ -234,7 +248,7 @@ objs/linear_solver.pb.$O:gen/linear_solver/linear_solver.pb.cc
|
||||
$(CCC) $(CFLAGS) -c gen/linear_solver/linear_solver.pb.cc $(OBJOUT)objs/linear_solver.pb.$O
|
||||
|
||||
gen/linear_solver/linear_solver.pb.cc:linear_solver/linear_solver.proto
|
||||
$(PROTOBUF_DIR)/bin/protoc --proto_path=linear_solver --cpp_out=gen/linear_solver linear_solver/linear_solver.proto
|
||||
$(PROTOBUF_DIR)/bin/protoc --proto_path=. --cpp_out=gen linear_solver/linear_solver.proto
|
||||
|
||||
gen/linear_solver/linear_solver.pb.h:gen/linear_solver/linear_solver.pb.cc
|
||||
|
||||
@@ -416,64 +430,70 @@ solve_dimacs_assignment$E: $(ALGORITHMS_LIBS) $(BASE_LIBS) $(DIMACS_LIBS) $(GRAP
|
||||
|
||||
# Pure CP and Routing Examples
|
||||
|
||||
objs/costas_array.$O: examples/costas_array.cc
|
||||
objs/costas_array.$O: examples/costas_array.cc constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/costas_array.cc $(OBJOUT)objs/costas_array.$O
|
||||
|
||||
costas_array$E: $(CP_LIBS) $(BASE_LIBS) objs/costas_array.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/costas_array.$O $(CP_LIBS) $(BASE_LIBS) $(EXEOUT)costas_array$E
|
||||
|
||||
objs/cryptarithm.$O:examples/cryptarithm.cc
|
||||
objs/cryptarithm.$O:examples/cryptarithm.cc constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/cryptarithm.cc $(OBJOUT)objs/cryptarithm.$O
|
||||
|
||||
cryptarithm$E: $(CP_LIBS) $(BASE_LIBS) objs/cryptarithm.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/cryptarithm.$O $(CP_LIBS) $(BASE_LIBS) $(EXEOUT)cryptarithm$E
|
||||
|
||||
objs/cvrptw.$O: examples/cvrptw.cc
|
||||
objs/cvrptw.$O: examples/cvrptw.cc constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/cvrptw.cc $(OBJOUT)objs/cvrptw.$O
|
||||
|
||||
cvrptw$E: $(CP_LIBS) $(BASE_LIBS) objs/cvrptw.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/cvrptw.$O $(CP_LIBS) $(BASE_LIBS) $(EXEOUT)cvrptw$E
|
||||
|
||||
objs/dobble_ls.$O:examples/dobble_ls.cc
|
||||
objs/dobble_ls.$O:examples/dobble_ls.cc constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/dobble_ls.cc $(OBJOUT)objs/dobble_ls.$O
|
||||
|
||||
dobble_ls$E: $(CP_LIBS) $(BASE_LIBS) objs/dobble_ls.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/dobble_ls.$O $(CP_LIBS) $(BASE_LIBS) $(EXEOUT)dobble_ls$E
|
||||
|
||||
objs/golomb.$O:examples/golomb.cc
|
||||
objs/golomb.$O:examples/golomb.cc constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/golomb.cc $(OBJOUT)objs/golomb.$O
|
||||
|
||||
golomb$E: $(CP_LIBS) $(BASE_LIBS) objs/golomb.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/golomb.$O $(CP_LIBS) $(BASE_LIBS) $(EXEOUT)golomb$E
|
||||
|
||||
objs/magic_square.$O:examples/magic_square.cc
|
||||
objs/magic_square.$O:examples/magic_square.cc constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/magic_square.cc $(OBJOUT)objs/magic_square.$O
|
||||
|
||||
magic_square$E: $(CP_LIBS) $(BASE_LIBS) objs/magic_square.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/magic_square.$O $(CP_LIBS) $(BASE_LIBS) $(EXEOUT)magic_square$E
|
||||
|
||||
objs/network_routing.$O:examples/network_routing.cc
|
||||
objs/model_util.$O:examples/model_util.cc gen/constraint_solver/model.pb.h constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/model_util.cc $(OBJOUT)objs/model_util.$O
|
||||
|
||||
model_util$E: $(CP_LIBS) $(BASE_LIBS) objs/model_util.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/model_util.$O $(CP_LIBS) $(BASE_LIBS) $(EXEOUT)model_util$E
|
||||
|
||||
objs/network_routing.$O:examples/network_routing.cc constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/network_routing.cc $(OBJOUT)objs/network_routing.$O
|
||||
|
||||
network_routing$E: $(CP_LIBS) $(BASE_LIBS) $(GRAPH_LIBS) objs/network_routing.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/network_routing.$O $(CP_LIBS) $(GRAPH_LIBS) $(BASE_LIBS) $(EXEOUT)network_routing$E
|
||||
|
||||
objs/nqueens.$O: examples/nqueens.cc
|
||||
objs/nqueens.$O: examples/nqueens.cc constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/nqueens.cc $(OBJOUT)objs/nqueens.$O
|
||||
|
||||
nqueens$E: $(CP_LIBS) $(BASE_LIBS) objs/nqueens.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/nqueens.$O $(CP_LIBS) $(BASE_LIBS) $(EXEOUT)nqueens$E
|
||||
|
||||
objs/tricks.$O: examples/tricks.cc
|
||||
objs/tricks.$O: examples/tricks.cc constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/tricks.cc $(OBJOUT)objs/tricks.$O
|
||||
|
||||
objs/global_arith.$O: examples/global_arith.cc
|
||||
objs/global_arith.$O: examples/global_arith.cc constraint_solver/constraint_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/global_arith.cc $(OBJOUT)objs/global_arith.$O
|
||||
|
||||
tricks$E: $(CPLIBS) $(BASE_LIBS) objs/tricks.$O objs/global_arith.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/tricks.$O objs/global_arith.$O $(CPLIBS) $(BASE_LIBS) $(EXEOUT)tricks$E
|
||||
|
||||
objs/tsp.$O: examples/tsp.cc
|
||||
objs/tsp.$O: examples/tsp.cc constraint_solver/routing.h
|
||||
$(CCC) $(CFLAGS) -c examples/tsp.cc $(OBJOUT)objs/tsp.$O
|
||||
|
||||
tsp$E: $(CP_LIBS) $(BASE_LIBS) objs/tsp.$O
|
||||
@@ -481,19 +501,19 @@ tsp$E: $(CP_LIBS) $(BASE_LIBS) objs/tsp.$O
|
||||
|
||||
# Linear Programming Examples
|
||||
|
||||
objs/linear_solver_example.$O: examples/linear_solver_example.cc
|
||||
objs/linear_solver_example.$O: examples/linear_solver_example.cc linear_solver/linear_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/linear_solver_example.cc $(OBJOUT)objs/linear_solver_example.$O
|
||||
|
||||
linear_solver_example$E: $(LP_LIBS) $(BASE_LIBS) objs/linear_solver_example.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/linear_solver_example.$O $(LP_LIBS) $(BASE_LIBS) $(LDLPDEPS) $(EXEOUT)linear_solver_example$E
|
||||
|
||||
objs/linear_solver_example_with_protocol_buffers.$O: examples/linear_solver_example_with_protocol_buffers.cc
|
||||
objs/linear_solver_example_with_protocol_buffers.$O: examples/linear_solver_example_with_protocol_buffers.cc linear_solver/linear_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/linear_solver_example_with_protocol_buffers.cc $(OBJOUT)objs/linear_solver_example_with_protocol_buffers.$O
|
||||
|
||||
linear_solver_example_with_protocol_buffers$E: $(LP_LIBS) $(BASE_LIBS) objs/linear_solver_example_with_protocol_buffers.$O
|
||||
$(CCC) $(CFLAGS) $(LDFLAGS) objs/linear_solver_example_with_protocol_buffers.$O $(LP_LIBS) $(BASE_LIBS) $(LDLPDEPS) $(EXEOUT)linear_solver_example_with_protocol_buffers$E
|
||||
|
||||
objs/integer_solver_example.$O: examples/integer_solver_example.cc
|
||||
objs/integer_solver_example.$O: examples/integer_solver_example.cc linear_solver/linear_solver.h
|
||||
$(CCC) $(CFLAGS) -c examples/integer_solver_example.cc $(OBJOUT)objs/integer_solver_example.$O
|
||||
|
||||
integer_solver_example$E: $(LP_LIBS) $(BASE_LIBS) objs/integer_solver_example.$O
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/scoped_ptr.h"
|
||||
#include "constraint_solver/constraint_solveri.h"
|
||||
#include "util/string_array.h"
|
||||
|
||||
namespace operations_research {
|
||||
namespace {
|
||||
|
||||
@@ -295,8 +295,8 @@ void LoadElement(const hash_map<string, E*>& id_to_element_map,
|
||||
|
||||
bool Assignment::Load(const string& filename) {
|
||||
File::Init();
|
||||
File* file = File::Create(filename, "r");
|
||||
if (file == NULL || !file->Open()) {
|
||||
File* file = File::Open(filename, "r");
|
||||
if (file == NULL) {
|
||||
LOG(INFO) << "Cannot open " << filename;
|
||||
return false;
|
||||
}
|
||||
@@ -382,8 +382,8 @@ void Assignment::Load(const AssignmentProto& assignment_proto) {
|
||||
|
||||
bool Assignment::Save(const string& filename) {
|
||||
File::Init();
|
||||
File* file = File::Create(filename, "w");
|
||||
if (file == NULL || !file->Open()) {
|
||||
File* file = File::Open(filename, "w");
|
||||
if (file == NULL) {
|
||||
LOG(INFO) << "Cannot open " << filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -28,11 +28,14 @@
|
||||
#include "base/macros.h"
|
||||
#include "base/scoped_ptr.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "base/file.h"
|
||||
#include "base/recordio.h"
|
||||
#include "zlib.h"
|
||||
#include "base/stringpiece.h"
|
||||
#include "base/concise_iterator.h"
|
||||
#include "base/map-util.h"
|
||||
#include "constraint_solver/constraint_solveri.h"
|
||||
#include "constraint_solver/model.pb.h"
|
||||
#include "util/const_int_array.h"
|
||||
|
||||
DEFINE_bool(cp_trace_demons, false, "trace all demon executions.");
|
||||
@@ -42,6 +45,8 @@ DEFINE_bool(cp_print_model, false,
|
||||
"use PrintModelVisitor on model before solving.");
|
||||
DEFINE_bool(cp_model_stats, false,
|
||||
"use StatisticsModelVisitor on model before solving.");
|
||||
DEFINE_string(cp_export_file, "", "Export model to file using CPModelProto.");
|
||||
DEFINE_bool(cp_no_solve, false, "Force failure at the beginning of a search");
|
||||
|
||||
void ConstraintSolverFailHere() {
|
||||
VLOG(3) << "Fail";
|
||||
@@ -1352,6 +1357,7 @@ void Solver::Init() {
|
||||
InitCachedIntConstants(); // to be called after the SENTINEL is set.
|
||||
InitCachedConstraint(); // Cache the true constraint.
|
||||
InitBoolVarCaches();
|
||||
InitBuilders();
|
||||
timer_->Restart();
|
||||
}
|
||||
|
||||
@@ -1373,6 +1379,7 @@ Solver::~Solver() {
|
||||
<< "non empty list of searches when ending the solver";
|
||||
delete search;
|
||||
DeleteDemonMonitor(demon_monitor_);
|
||||
DeleteBuilders();
|
||||
}
|
||||
|
||||
const SolverParameters::TrailCompression
|
||||
@@ -1626,6 +1633,25 @@ void Solver::ProcessConstraints() {
|
||||
ModelVisitor* const visitor = MakeStatisticsModelVisitor();
|
||||
Accept(visitor);
|
||||
}
|
||||
if (!FLAGS_cp_export_file.empty()) {
|
||||
File::Init();
|
||||
File* file = File::Open(FLAGS_cp_export_file, "w");
|
||||
if (file == NULL) {
|
||||
LOG(WARNING) << "Cannot open " << FLAGS_cp_export_file;
|
||||
} else {
|
||||
CPModelProto export_proto;
|
||||
ExportModel(&export_proto);
|
||||
VLOG(1) << export_proto.DebugString();
|
||||
RecordWriter writer(file);
|
||||
writer.WriteProtocolMessage(export_proto);
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAGS_cp_no_solve) {
|
||||
LOG(INFO) << "Forcing early failure";
|
||||
Fail();
|
||||
}
|
||||
|
||||
// Clear state before processing constraints.
|
||||
const int constraints_size = constraints_list_.size();
|
||||
@@ -2381,7 +2407,7 @@ void DecisionVisitor::VisitTryRankFirst(Sequence* const sequence, int index) {}
|
||||
|
||||
// ---------- ModelVisitor ----------
|
||||
|
||||
// Enums.
|
||||
// Tags for constraints, arguments, extensions.
|
||||
|
||||
const char ModelVisitor::kAbs[] = "Abs";
|
||||
const char ModelVisitor::kAllDifferent[] = "AllDifferent";
|
||||
|
||||
@@ -101,6 +101,12 @@ class BaseObject;
|
||||
class ClockTimer;
|
||||
class ConstIntArray;
|
||||
class Constraint;
|
||||
class CPArgumentProto;
|
||||
class CPConstraintProto;
|
||||
class CPIntegerExpressionProto;
|
||||
class CPIntervalVariableProto;
|
||||
class CPModelBuilder;
|
||||
class CPModelProto;
|
||||
class Decision;
|
||||
class DecisionBuilder;
|
||||
class DecisionVisitor;
|
||||
@@ -142,6 +148,7 @@ class SymmetryBreaker;
|
||||
class UnequalityVarCstCache;
|
||||
struct StateInfo;
|
||||
struct Trail;
|
||||
template <class T> class ConstPtrArray;
|
||||
template <class T> class SimpleRevFIFO;
|
||||
|
||||
// This enum is used internally to tag states in the search tree.
|
||||
@@ -297,6 +304,17 @@ class Solver {
|
||||
typedef ResultCallback1<int64, int64> IndexEvaluator1;
|
||||
typedef ResultCallback2<int64, int64, int64> IndexEvaluator2;
|
||||
typedef ResultCallback3<int64, int64, int64, int64> IndexEvaluator3;
|
||||
typedef ResultCallback2<IntExpr*,
|
||||
CPModelBuilder*,
|
||||
const CPIntegerExpressionProto&>
|
||||
IntegerExpressionBuilder;
|
||||
typedef ResultCallback2<Constraint*,
|
||||
CPModelBuilder*,
|
||||
const CPConstraintProto&> ConstraintBuilder;
|
||||
typedef ResultCallback2<IntervalVar*,
|
||||
CPModelBuilder*,
|
||||
const CPIntervalVariableProto&>
|
||||
IntervalVariableBuilder;
|
||||
|
||||
// Number of priorities for demons.
|
||||
static const int kNumPriorities = 3;
|
||||
@@ -556,6 +574,37 @@ class Solver {
|
||||
// Abandon the current branch in the search tree. A backtrack will follow.
|
||||
void Fail();
|
||||
|
||||
// Exports the model to protobuf. This code will be called
|
||||
// from inside the solver during the start of the search.
|
||||
void ExportModel(CPModelProto* const proto) const;
|
||||
// Exports the model to protobuf. Search monitors are useful to pass
|
||||
// the objective and limits to the protobuf.
|
||||
void ExportModel(const std::vector<SearchMonitor*>& monitors,
|
||||
CPModelProto* const proto) const;
|
||||
// Loads the model into the solver, and returns true upon success.
|
||||
bool LoadModel(const CPModelProto& proto);
|
||||
// Loads the model into the solver, appends search monitors to monitors,
|
||||
// and returns true upon success.
|
||||
bool LoadModel(const CPModelProto& proto, std::vector<SearchMonitor*>* monitors);
|
||||
// Upgrades the model to the latest version.
|
||||
static bool UpgradeModel(CPModelProto* const proto);
|
||||
|
||||
// Registers a constraint builder. Ownership is passed to the solver.
|
||||
void RegisterBuilder(const string& tag,
|
||||
ConstraintBuilder* const builder);
|
||||
// Registers a integer expression builder. Ownership is passed to the solver.
|
||||
void RegisterBuilder(const string& tag,
|
||||
IntegerExpressionBuilder* const builder);
|
||||
// Registers a interval variable builder. Ownership is passed to the solver.
|
||||
void RegisterBuilder(const string& tag,
|
||||
IntervalVariableBuilder* const builder);
|
||||
|
||||
ConstraintBuilder* GetConstraintBuilder(const string& tag) const;
|
||||
IntegerExpressionBuilder*
|
||||
GetIntegerExpressionBuilder(const string& tag) const;
|
||||
IntervalVariableBuilder* GetIntervalVariableBuilder(const string& tag) const;
|
||||
|
||||
|
||||
// When SaveValue() is not the best way to go, one can create a reversible
|
||||
// action that will be called upon backtrack. The "fast" parameter
|
||||
// indicates whether we need restore all values saved through SaveValue()
|
||||
@@ -2297,6 +2346,8 @@ class Solver {
|
||||
void InitCachedIntConstants();
|
||||
void InitCachedConstraint();
|
||||
void InitBoolVarCaches();
|
||||
void InitBuilders();
|
||||
void DeleteBuilders();
|
||||
|
||||
// Naming
|
||||
string GetName(const PropagationBaseObject* object) const;
|
||||
@@ -2351,6 +2402,11 @@ class Solver {
|
||||
int constraint_index_;
|
||||
int additional_constraint_index_;
|
||||
|
||||
// Support for model loading.
|
||||
hash_map<string, IntegerExpressionBuilder*> expression_builders_;
|
||||
hash_map<string, ConstraintBuilder*> constraint_builders_;
|
||||
hash_map<string, IntervalVariableBuilder*> interval_builders_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Solver);
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
DECLARE_bool(cp_trace_demons);
|
||||
DECLARE_bool(cp_print_model);
|
||||
DECLARE_bool(cp_model_stats);
|
||||
DECLARE_string(cp_export_file);
|
||||
DECLARE_bool(cp_no_solve);
|
||||
|
||||
struct FailureProtect {
|
||||
jmp_buf exception_buffer;
|
||||
@@ -228,6 +230,10 @@ gflags.DEFINE_boolean('cp_print_model', False,
|
||||
'prints the model before solving it.')
|
||||
gflags.DEFINE_boolean('cp_model_stats', False,
|
||||
'displays model statistics before solving it.')
|
||||
gflags.DEFINE_string('cp_export_file', '',
|
||||
'exports model to file using CPModelProto.')
|
||||
gflags.DEFINE_boolean('cp_no_solve', False,
|
||||
'force failures at the beginning of a search.')
|
||||
}
|
||||
%pythoncode {
|
||||
|
||||
@@ -861,20 +867,28 @@ namespace operations_research {
|
||||
// Add display methods on Solver and remove DebugString method.
|
||||
%ignore Solver::DebugString;
|
||||
|
||||
// Indentation is critical here as the code is copied verbatim in the
|
||||
// python code.
|
||||
%feature("pythonappend") Solver::Solver %{
|
||||
Solver.SetPythonFlags(FLAGS.cp_trace_demons,
|
||||
FLAGS.cp_print_model,
|
||||
FLAGS.cp_model_stats)
|
||||
FLAGS.cp_model_stats,
|
||||
FLAGS.cp_export_file,
|
||||
FLAGS.cp_no_solve)
|
||||
%}
|
||||
|
||||
|
||||
%extend Solver {
|
||||
static void SetPythonFlags(bool trace_demon,
|
||||
bool print_model,
|
||||
bool model_stats) {
|
||||
bool model_stats,
|
||||
string export_file,
|
||||
bool no_solve) {
|
||||
FLAGS_cp_trace_demons = trace_demon;
|
||||
FLAGS_cp_print_model = print_model;
|
||||
FLAGS_cp_model_stats = model_stats;
|
||||
FLAGS_cp_export_file = export_file;
|
||||
FLAGS_cp_no_solve = no_solve;
|
||||
}
|
||||
|
||||
Constraint* TreeNoCycle(const std::vector<IntVar*>& nexts,
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "base/bitmap.h"
|
||||
#include "base/map-util.h"
|
||||
#include "constraint_solver/constraint_solver.h"
|
||||
#include "util/vector_map.h"
|
||||
|
||||
class WallTimer;
|
||||
|
||||
@@ -125,47 +126,6 @@ template <class T> class SimpleRevFIFO {
|
||||
int pos_;
|
||||
};
|
||||
|
||||
// ---------- Pretty Print Helpers ----------
|
||||
|
||||
template <class T> string DebugStringArray(T* const* array,
|
||||
int size,
|
||||
const string& separator) {
|
||||
string out;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (i > 0) {
|
||||
out.append(separator);
|
||||
}
|
||||
out.append(array[i]->DebugString());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class T> string NameArray(T* const* array,
|
||||
int size,
|
||||
const string& separator) {
|
||||
string out;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (i > 0) {
|
||||
out.append(separator);
|
||||
}
|
||||
out.append(array[i]->name());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
inline string Int64ArrayToString(const int64* const array,
|
||||
int size,
|
||||
const string& separator) {
|
||||
string out;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (i > 0) {
|
||||
out.append(separator);
|
||||
}
|
||||
StringAppendF(&out, "%" GG_LL_FORMAT "d", array[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// These methods represents generic demons that will call back a
|
||||
// method on the constraint during their Run method.
|
||||
|
||||
@@ -870,6 +830,286 @@ class SearchLog : public SearchMonitor {
|
||||
int sliding_min_depth_;
|
||||
int sliding_max_depth_;
|
||||
};
|
||||
|
||||
// ---------- CPModelBuilder -----------
|
||||
|
||||
class CPModelBuilder {
|
||||
public:
|
||||
explicit CPModelBuilder(Solver* const solver) : solver_(solver) {}
|
||||
~CPModelBuilder() {}
|
||||
|
||||
Solver* solver() const { return solver_; }
|
||||
|
||||
// Builds integer expression from proto and stores it. It returns
|
||||
// true upon success.
|
||||
bool BuildFromProto(const CPIntegerExpressionProto& proto);
|
||||
// Builds constraint from proto and returns it.
|
||||
Constraint* BuildFromProto(const CPConstraintProto& proto);
|
||||
// Builds interval variable from proto and stores it. It returns
|
||||
// true upon success.
|
||||
bool BuildFromProto(const CPIntervalVariableProto& proto);
|
||||
// Returns stored integer expression.
|
||||
IntExpr* IntegerExpression(int index) const;
|
||||
// Returns stored interval variable.
|
||||
IntervalVar* IntervalVariable(int index) const;
|
||||
|
||||
bool ScanOneArgument(int type_index,
|
||||
const CPArgumentProto& arg_proto,
|
||||
int64* to_fill);
|
||||
|
||||
bool ScanOneArgument(int type_index,
|
||||
const CPArgumentProto& arg_proto ,
|
||||
IntExpr** to_fill);
|
||||
|
||||
bool ScanOneArgument(int type_index,
|
||||
const CPArgumentProto& arg_proto,
|
||||
std::vector<int64>* to_fill);
|
||||
|
||||
bool ScanOneArgument(int type_index,
|
||||
const CPArgumentProto& arg_proto,
|
||||
std::vector<std::vector<int64> >* to_fill);
|
||||
|
||||
bool ScanOneArgument(int type_index,
|
||||
const CPArgumentProto& arg_proto,
|
||||
std::vector<IntVar*>* to_fill);
|
||||
|
||||
bool ScanOneArgument(int type_index,
|
||||
const CPArgumentProto& arg_proto,
|
||||
IntervalVar** to_fill);
|
||||
|
||||
bool ScanOneArgument(int type_index,
|
||||
const CPArgumentProto& arg_proto,
|
||||
std::vector<IntervalVar*>* to_fill);
|
||||
|
||||
template <class P, class A> bool ScanArguments(const string& type,
|
||||
const P& proto,
|
||||
A* to_fill) {
|
||||
const int index = tags_.Index(type);
|
||||
for (int i = 0; i < proto.arguments_size(); ++i) {
|
||||
if (ScanOneArgument(index, proto.arguments(i), to_fill)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int TagIndex(const string& tag) const { return tags_.Index(tag); }
|
||||
|
||||
void AddTag(const string& tag) { tags_.Add(tag); }
|
||||
|
||||
private:
|
||||
Solver* const solver_;
|
||||
std::vector<IntExpr*> expressions_;
|
||||
std::vector<IntervalVar*> intervals_;
|
||||
VectorMap<string> tags_;
|
||||
};
|
||||
|
||||
// Implements a complete cache for model elements: expressions and constraints.
|
||||
// Caching is based on the signature of the elements, as well as their type.
|
||||
class ModelCache {
|
||||
public:
|
||||
enum VoidConstraintType {
|
||||
VOID_FALSE_CONSTRAINT = 0,
|
||||
VOID_TRUE_CONSTRAINT,
|
||||
VOID_CONSTRAINT_MAX,
|
||||
};
|
||||
|
||||
enum VarConstantConstraintType {
|
||||
VAR_CONSTANT_EQUALITY = 0,
|
||||
VAR_CONSTANT_GREATER_OR_EQUAL,
|
||||
VAR_CONSTANT_LESS_OR_EQUAL,
|
||||
VAR_CONSTANT_NON_EQUALITY,
|
||||
VAR_CONSTANT_CONSTRAINT_MAX,
|
||||
};
|
||||
|
||||
enum VarConstantConstantConstraintType {
|
||||
VAR_CONSTANT_CONSTANT_BETWEEN = 0,
|
||||
VAR_CONSTANT_CONSTANT_CONSTRAINT_MAX,
|
||||
};
|
||||
|
||||
enum VarVarConstraintType {
|
||||
VAR_VAR_EQUALITY = 0,
|
||||
VAR_VAR_GREATER,
|
||||
VAR_VAR_GREATER_OR_EQUAL,
|
||||
VAR_VAR_LESS,
|
||||
VAR_VAR_LESS_OR_EQUAL,
|
||||
VAR_VAR_NON_EQUALITY,
|
||||
VAR_VAR_CONSTRAINT_MAX,
|
||||
};
|
||||
|
||||
enum VarExpressionType {
|
||||
VAR_OPPOSITE = 0,
|
||||
VAR_ABS,
|
||||
VAR_SQUARE,
|
||||
VAR_EXPRESSION_MAX,
|
||||
};
|
||||
|
||||
enum VarConstantExpressionType {
|
||||
VAR_CONSTANT_DIFFERENCE = 0,
|
||||
VAR_CONSTANT_DIVIDE,
|
||||
VAR_CONSTANT_PROD,
|
||||
VAR_CONSTANT_MAX,
|
||||
VAR_CONSTANT_MIN,
|
||||
VAR_CONSTANT_SUM,
|
||||
VAR_CONSTANT_EXPRESSION_MAX,
|
||||
};
|
||||
|
||||
enum VarVarExpressionType {
|
||||
VAR_VAR_DIFFERENCE = 0,
|
||||
VAR_VAR_PROD,
|
||||
VAR_VAR_MAX,
|
||||
VAR_VAR_MIN,
|
||||
VAR_VAR_SUM,
|
||||
VAR_VAR_EXPRESSION_MAX,
|
||||
};
|
||||
|
||||
enum VarConstantConstantExpressionType {
|
||||
VAR_CONSTANT_CONSTANT_SEMI_CONTINUOUS = 0,
|
||||
VAR_CONSTANT_CONSTANT_EXPRESSION_MAX,
|
||||
};
|
||||
|
||||
enum VarConstantArrayExpressionType {
|
||||
VAR_CONSTANT_ARRAY_ELEMENT = 0,
|
||||
VAR_CONSTANT_ARRAY_EXPRESSION_MAX,
|
||||
};
|
||||
|
||||
enum VarArrayExpressionType {
|
||||
VAR_ARRAY_MAX = 0,
|
||||
VAR_ARRAY_MIN,
|
||||
VAR_ARRAY_SUM,
|
||||
VAR_ARRAY_EXPRESSION_MAX,
|
||||
};
|
||||
|
||||
explicit ModelCache(Solver* const solver);
|
||||
virtual ~ModelCache();
|
||||
|
||||
// Void constraints.
|
||||
|
||||
virtual Constraint* FindVoidConstraint(VoidConstraintType type) const = 0;
|
||||
|
||||
virtual void InsertVoidConstraint(Constraint* const ct,
|
||||
VoidConstraintType type) = 0;
|
||||
|
||||
// Var Constant Constraints.
|
||||
|
||||
virtual Constraint* FindVarConstantConstraint(
|
||||
IntVar* const var,
|
||||
int64 value,
|
||||
VarConstantConstraintType type) const = 0;
|
||||
|
||||
virtual void InsertVarConstantConstraint(
|
||||
Constraint* const ct,
|
||||
IntVar* const var,
|
||||
int64 value,
|
||||
VarConstantConstraintType type) = 0;
|
||||
|
||||
// Var Constant Constant Constraints.
|
||||
|
||||
virtual Constraint* FindVarConstantConstantConstraint(
|
||||
IntVar* const var,
|
||||
int64 value1,
|
||||
int64 value2,
|
||||
VarConstantConstantConstraintType type) const = 0;
|
||||
|
||||
virtual void InsertVarConstantConstantConstraint(
|
||||
Constraint* const ct,
|
||||
IntVar* const var,
|
||||
int64 value1,
|
||||
int64 value2,
|
||||
VarConstantConstantConstraintType type) = 0;
|
||||
|
||||
// Var Var Constraints.
|
||||
|
||||
virtual Constraint* FindVarVarConstraint(
|
||||
IntVar* const var1,
|
||||
IntVar* const var2,
|
||||
VarVarConstraintType type) const = 0;
|
||||
|
||||
virtual void InsertVarVarConstraint(Constraint* const ct,
|
||||
IntVar* const var1,
|
||||
IntVar* const var2,
|
||||
VarVarConstraintType type) = 0;
|
||||
|
||||
// Var Expressions.
|
||||
|
||||
virtual IntExpr* FindVarExpression(
|
||||
IntVar* const var,
|
||||
VarExpressionType type) const = 0;
|
||||
|
||||
virtual void InsertVarExpression(IntExpr* const expression,
|
||||
IntVar* const var,
|
||||
VarExpressionType type) = 0;
|
||||
|
||||
// Var Constant Expressions .
|
||||
|
||||
virtual IntExpr* FindVarConstantExpression(
|
||||
IntVar* const var,
|
||||
int64 value,
|
||||
VarConstantExpressionType type) const = 0;
|
||||
|
||||
virtual void InsertVarConstantExpression(
|
||||
IntExpr* const expression,
|
||||
IntVar* const var,
|
||||
int64 value,
|
||||
VarConstantExpressionType type) = 0;
|
||||
|
||||
// Var Var Expressions.
|
||||
|
||||
virtual IntExpr* FindVarVarExpression(
|
||||
IntVar* const var1,
|
||||
IntVar* const var2,
|
||||
VarVarExpressionType type) const = 0;
|
||||
|
||||
virtual void InsertVarVarExpression(
|
||||
IntExpr* const expression,
|
||||
IntVar* const var1,
|
||||
IntVar* const var2,
|
||||
VarVarExpressionType type) = 0;
|
||||
|
||||
// Var Constant Constant Expressions.
|
||||
|
||||
virtual IntExpr* FindVarConstantConstantExpression(
|
||||
IntVar* const var,
|
||||
int64 value1,
|
||||
int64 value2,
|
||||
VarConstantConstantExpressionType type) const = 0;
|
||||
|
||||
virtual void InsertVarConstantConstantExpression(
|
||||
IntExpr* const expression,
|
||||
IntVar* const var,
|
||||
int64 value1,
|
||||
int64 value2,
|
||||
VarConstantConstantExpressionType type) = 0;
|
||||
|
||||
// Var Constant Array Expressions.
|
||||
|
||||
virtual IntExpr* FindVarConstantArrayExpression(
|
||||
IntVar* const var,
|
||||
ConstIntArray* const values,
|
||||
VarConstantArrayExpressionType type) const = 0;
|
||||
|
||||
virtual void InsertVarConstantArrayExpression(
|
||||
IntExpr* const expression,
|
||||
IntVar* const var,
|
||||
ConstIntArray* const values,
|
||||
VarConstantArrayExpressionType type) = 0;
|
||||
|
||||
// Var Array Expressions.
|
||||
|
||||
virtual IntExpr* FindVarArrayExpression(
|
||||
ConstPtrArray<IntVar>* const vars,
|
||||
VarArrayExpressionType type) const = 0;
|
||||
|
||||
virtual void InsertVarArrayExpression(
|
||||
IntExpr* const expression,
|
||||
ConstPtrArray<IntVar>* const vars,
|
||||
VarArrayExpressionType type) = 0;
|
||||
|
||||
Solver* solver() const;
|
||||
|
||||
private:
|
||||
Solver* const solver_;
|
||||
};
|
||||
} // namespace operations_research
|
||||
|
||||
#endif // OR_TOOLS_CONSTRAINT_SOLVER_CONSTRAINT_SOLVERI_H_
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "base/stringprintf.h"
|
||||
#include "base/concise_iterator.h"
|
||||
#include "constraint_solver/constraint_solveri.h"
|
||||
#include "util/string_array.h"
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "base/mathutil.h"
|
||||
#include "constraint_solver/constraint_solver.h"
|
||||
#include "constraint_solver/constraint_solveri.h"
|
||||
#include "util/string_array.h"
|
||||
|
||||
namespace operations_research {
|
||||
// Deviation Constraint, a constraint for the average absolute
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "base/stringprintf.h"
|
||||
#include "constraint_solver/constraint_solveri.h"
|
||||
#include "util/const_int_array.h"
|
||||
#include "util/string_array.h"
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "base/scoped_ptr.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "constraint_solver/constraint_solveri.h"
|
||||
#include "util/string_array.h"
|
||||
|
||||
namespace operations_research {
|
||||
namespace {
|
||||
|
||||
2261
constraint_solver/io.cc
Normal file
2261
constraint_solver/io.cc
Normal file
File diff suppressed because it is too large
Load Diff
89
constraint_solver/model.proto
Normal file
89
constraint_solver/model.proto
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright 2010-2011 Google
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto2";
|
||||
import "constraint_solver/search_limit.proto";
|
||||
|
||||
package operations_research;
|
||||
|
||||
message CPIntegerMatrixProto {
|
||||
required int32 rows = 1;
|
||||
required int32 columns = 2;
|
||||
repeated int64 values = 3;
|
||||
}
|
||||
|
||||
// This message holds one argument of a constraint or expression. It
|
||||
// is referenced by the argument_name. Only one field apart the name
|
||||
// must be set.
|
||||
message CPArgumentProto {
|
||||
required int32 argument_index = 1;
|
||||
optional int64 integer_value = 2;
|
||||
repeated int64 integer_array = 3;
|
||||
optional int32 integer_expression_index = 4;
|
||||
repeated int32 integer_expression_array = 5;
|
||||
optional int32 interval_index = 6;
|
||||
repeated int32 interval_array = 7;
|
||||
optional CPIntegerMatrixProto integer_matrix = 8;
|
||||
}
|
||||
|
||||
message CPExtensionProto {
|
||||
required int32 type_index = 1;
|
||||
repeated CPArgumentProto arguments = 2;
|
||||
}
|
||||
|
||||
message CPIntegerExpressionProto {
|
||||
required int32 index = 1;
|
||||
required int32 type_index = 2;
|
||||
optional string name = 3;
|
||||
repeated CPArgumentProto arguments = 4;
|
||||
repeated CPExtensionProto extensions = 5;
|
||||
}
|
||||
|
||||
message CPIntervalVariableProto {
|
||||
required int32 index = 1;
|
||||
required int32 type_index = 2;
|
||||
optional string name = 3;
|
||||
repeated CPArgumentProto arguments = 4;
|
||||
}
|
||||
|
||||
message CPConstraintProto {
|
||||
required int32 index = 1;
|
||||
required int32 type_index = 2;
|
||||
optional string name = 3;
|
||||
repeated CPArgumentProto arguments = 4;
|
||||
repeated CPExtensionProto extensions = 5;
|
||||
}
|
||||
|
||||
message CPObjectiveProto {
|
||||
required bool maximize = 1;
|
||||
required int64 step = 2;
|
||||
required int32 objective_index = 3;
|
||||
}
|
||||
|
||||
message CPVariableGroup {
|
||||
repeated CPArgumentProto arguments = 1;
|
||||
optional string type = 2;
|
||||
}
|
||||
|
||||
message CPModelProto {
|
||||
required string model = 1;
|
||||
required int32 version = 2;
|
||||
repeated string tags = 3;
|
||||
repeated CPIntegerExpressionProto expressions = 4;
|
||||
repeated CPIntervalVariableProto intervals = 5;
|
||||
repeated CPConstraintProto constraints = 6;
|
||||
optional CPObjectiveProto objective = 7;
|
||||
optional SearchLimitProto search_limit = 8;
|
||||
repeated CPVariableGroup variable_groups = 9;
|
||||
optional string licence_text = 10;
|
||||
}
|
||||
@@ -1235,6 +1235,8 @@ void Pack::AddWeightedSumOfAssignedDimension(const std::vector<int64>& weights,
|
||||
void Pack::AddSumVariableWeightsLessOrEqualConstantDimension(
|
||||
const std::vector<IntVar*>& usage,
|
||||
const std::vector<int64>& capacity) {
|
||||
CHECK_EQ(usage.size(), vsize_);
|
||||
CHECK_EQ(capacity.size(), bins_);
|
||||
Solver* const s = solver();
|
||||
Dimension* const dim =
|
||||
s->RevAlloc(new VariableUsageDimension(s,
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "base/random.h"
|
||||
#include "constraint_solver/constraint_solveri.h"
|
||||
#include "constraint_solver/search_limit.pb.h"
|
||||
#include "util/string_array.h"
|
||||
|
||||
DEFINE_bool(cp_use_sparse_gls_penalties, false,
|
||||
"Use sparse implementation to store Guided Local Search penalties");
|
||||
|
||||
314
examples/model_util.cc
Normal file
314
examples/model_util.cc
Normal file
@@ -0,0 +1,314 @@
|
||||
// Copyright 2010-2011 Google
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/integral_types.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/file.h"
|
||||
#include "base/recordio.h"
|
||||
#include "constraint_solver/constraint_solver.h"
|
||||
#include "constraint_solver/model.pb.h"
|
||||
|
||||
DEFINE_string(input, "", "Input file of the problem.");
|
||||
DEFINE_string(output, "", "Output file when doing modifications.");
|
||||
DEFINE_string(dot_file, "", "Exports model to dot file.");
|
||||
|
||||
DEFINE_bool(print_proto, false, "Prints the raw model protobuf.");
|
||||
DEFINE_bool(test_proto, false, "Performs various tests on the model protobuf.");
|
||||
DEFINE_bool(model_stats, false, "Prints model statistics.");
|
||||
DEFINE_bool(print_model, false, "Pretty print loaded model.");
|
||||
|
||||
DEFINE_string(rename_model, "", "Renames to the model.");
|
||||
DEFINE_bool(strip_limit, false, "Strips limits from the model.");
|
||||
DEFINE_bool(strip_groups, false, "Strips variable groups from the model.");
|
||||
DEFINE_bool(upgrade_proto, false, "Upgrade the model to the latest version.");
|
||||
DEFINE_string(insert_licence, "",
|
||||
"Insert content of the given file into the licence file.");
|
||||
|
||||
namespace operations_research {
|
||||
static const int kProblem = -1;
|
||||
static const int kOk = 0;
|
||||
|
||||
// ----- Export to .dot file -----
|
||||
|
||||
// Appends a string to te file.
|
||||
void Write(File* const file, const string& string) {
|
||||
file->Write(string.c_str(), string.size());
|
||||
}
|
||||
|
||||
// Adds one link in the generated graph.
|
||||
void WriteExprLink(const string& origin,
|
||||
int index,
|
||||
const string& label,
|
||||
File* const file) {
|
||||
const string other = StringPrintf("expr_%i", index);
|
||||
Write(file, StringPrintf("%s -- %s [label=%s]\n",
|
||||
origin.c_str(),
|
||||
other.c_str(),
|
||||
label.c_str()));
|
||||
}
|
||||
|
||||
// Adds one link in the generated graph.
|
||||
void WriteIntervalLink(const string& origin,
|
||||
int index,
|
||||
const string& label,
|
||||
File* const file) {
|
||||
const string other = StringPrintf("interval_%i", index);
|
||||
Write(file, StringPrintf("%s -- %s [label=%s]\n",
|
||||
origin.c_str(),
|
||||
other.c_str(),
|
||||
label.c_str()));
|
||||
}
|
||||
|
||||
// Scans argument to add links in the graph.
|
||||
template <class T> void ExportLinks(const CPModelProto& model,
|
||||
const string& origin,
|
||||
const T& proto,
|
||||
File* const file) {
|
||||
const string& arg_name = model.tags(proto.argument_index());
|
||||
if (proto.has_integer_expression_index()) {
|
||||
WriteExprLink(origin, proto.integer_expression_index(), arg_name, file);
|
||||
}
|
||||
for (int i = 0; i < proto.integer_expression_array_size(); ++i) {
|
||||
WriteExprLink(origin, proto.integer_expression_array(i), arg_name, file);
|
||||
}
|
||||
if (proto.has_interval_index()) {
|
||||
WriteIntervalLink(origin, proto.interval_index(), arg_name, file);
|
||||
}
|
||||
for (int i = 0; i < proto.interval_array_size(); ++i) {
|
||||
WriteIntervalLink(origin, proto.interval_array(i), arg_name, file);
|
||||
}
|
||||
}
|
||||
|
||||
// Declares a labelled expression in the .dot file.
|
||||
void DeclareExpression(int index, const CPModelProto& proto, File* const file) {
|
||||
const CPIntegerExpressionProto& expr = proto.expressions(index);
|
||||
const string short_name = StringPrintf("expr_%i", index);
|
||||
if (expr.has_name()) {
|
||||
Write(file, StringPrintf("%s [shape=oval label=\"%s\" color=green]\n",
|
||||
short_name.c_str(),
|
||||
expr.name().c_str()));
|
||||
} else {
|
||||
const string& type = proto.tags(expr.type_index());
|
||||
Write(file, StringPrintf("%s [shape=oval label=\"%s\"]\n",
|
||||
short_name.c_str(),
|
||||
type.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void DeclareInterval(int index, const CPModelProto& proto, File* const file) {
|
||||
const CPIntervalVariableProto& interval = proto.intervals(index);
|
||||
const string short_name = StringPrintf("interval_%i", index);
|
||||
if (interval.has_name()) {
|
||||
Write(file, StringPrintf("%s [shape=circle label=\"%s\" color=green]\n",
|
||||
short_name.c_str(),
|
||||
interval.name().c_str()));
|
||||
} else {
|
||||
const string& type = proto.tags(interval.type_index());
|
||||
Write(file, StringPrintf("%s [shape=oval label=\"%s\"]\n",
|
||||
short_name.c_str(),
|
||||
type.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void DeclareConstraint(int index, const CPModelProto& proto, File* const file) {
|
||||
const CPConstraintProto& ct = proto.constraints(index);
|
||||
const string& type = proto.tags(ct.type_index());
|
||||
const string short_name = StringPrintf("ct_%i", index);
|
||||
Write(file, StringPrintf("%s [shape=box label=\"%s\"]\n",
|
||||
short_name.c_str(),
|
||||
type.c_str()));
|
||||
}
|
||||
|
||||
// Parses the proto and exports it to a .dot file.
|
||||
void ExportToDot(const CPModelProto& proto, File* const file) {
|
||||
Write(file, StringPrintf("graph %s {\n", proto.model().c_str()));
|
||||
|
||||
for (int i = 0; i < proto.expressions_size(); ++i) {
|
||||
DeclareExpression(i, proto, file);
|
||||
}
|
||||
|
||||
for (int i = 0; i < proto.intervals_size(); ++i) {
|
||||
DeclareInterval(i, proto, file);
|
||||
}
|
||||
|
||||
for (int i = 0; i < proto.constraints_size(); ++i) {
|
||||
DeclareConstraint(i, proto, file);
|
||||
}
|
||||
|
||||
if (proto.has_objective()) {
|
||||
if (proto.objective().maximize()) {
|
||||
Write(file, "obj [shape=diamond label=\"Maximize\" color=red]\n");
|
||||
} else {
|
||||
Write(file, "obj [shape=diamond label=\"Minimize\" color=red]\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < proto.expressions_size(); ++i) {
|
||||
const CPIntegerExpressionProto& expr = proto.expressions(i);
|
||||
const string short_name = StringPrintf("expr_%i", i);
|
||||
for (int j = 0; j < expr.arguments_size(); ++j) {
|
||||
ExportLinks(proto, short_name, expr.arguments(j), file);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < proto.intervals_size(); ++i) {
|
||||
const CPIntervalVariableProto& interval = proto.intervals(i);
|
||||
const string short_name = StringPrintf("interval_%i", i);
|
||||
for (int j = 0; j < interval.arguments_size(); ++j) {
|
||||
ExportLinks(proto, short_name, interval.arguments(j), file);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < proto.constraints_size(); ++i) {
|
||||
const CPConstraintProto& ct = proto.constraints(i);
|
||||
const string short_name = StringPrintf("ct_%i", i);
|
||||
for (int j = 0; j < ct.arguments_size(); ++j) {
|
||||
ExportLinks(proto, short_name, ct.arguments(j), file);
|
||||
}
|
||||
}
|
||||
|
||||
if (proto.has_objective()) {
|
||||
const CPObjectiveProto& obj = proto.objective();
|
||||
WriteExprLink("obj",
|
||||
obj.objective_index(),
|
||||
ModelVisitor::kExpressionArgument,
|
||||
file);
|
||||
}
|
||||
|
||||
Write(file, "}\n");
|
||||
}
|
||||
|
||||
// ----- Main Method -----
|
||||
|
||||
int Run() {
|
||||
// ----- Load input file into protobuf -----
|
||||
|
||||
File::Init();
|
||||
File* const file = File::Open(FLAGS_input, "r");
|
||||
if (file == NULL) {
|
||||
LOG(WARNING) << "Cannot open " << FLAGS_input;
|
||||
return kProblem;
|
||||
}
|
||||
|
||||
CPModelProto model_proto;
|
||||
RecordReader reader(file);
|
||||
if (!(reader.ReadProtocolMessage(&model_proto) && reader.Close())) {
|
||||
LOG(INFO) << "No model found in " << file->CreateFileName();
|
||||
return kProblem;
|
||||
}
|
||||
|
||||
// ----- Display loaded protobuf -----
|
||||
|
||||
LOG(INFO) << "Read model " << model_proto.model();
|
||||
if (model_proto.has_licence_text()) {
|
||||
LOG(INFO) << "Licence = " << model_proto.licence_text();
|
||||
}
|
||||
|
||||
// ----- Modifications -----
|
||||
|
||||
if (!FLAGS_rename_model.empty()) {
|
||||
model_proto.set_model(FLAGS_rename_model);
|
||||
}
|
||||
|
||||
if (FLAGS_strip_limit) {
|
||||
model_proto.clear_search_limit();
|
||||
}
|
||||
|
||||
if (FLAGS_strip_groups) {
|
||||
model_proto.clear_variable_groups();
|
||||
}
|
||||
|
||||
if (FLAGS_upgrade_proto) {
|
||||
if (!Solver::UpgradeModel(&model_proto)) {
|
||||
LOG(ERROR) << "Model upgrade failed";
|
||||
return kProblem;
|
||||
}
|
||||
}
|
||||
|
||||
if (!FLAGS_insert_licence.empty()) {
|
||||
File* const licence = File::Open(FLAGS_insert_licence, "r");
|
||||
if (licence == NULL) {
|
||||
LOG(WARNING) << "Cannot open " << FLAGS_insert_licence;
|
||||
return kProblem;
|
||||
}
|
||||
const int size = licence->Size();
|
||||
char* const text = new char[size + 1];
|
||||
licence->Read(text, size);
|
||||
model_proto.set_licence_text(text);
|
||||
licence->Close();
|
||||
}
|
||||
|
||||
// ----- Reporting -----
|
||||
|
||||
if (FLAGS_print_proto) {
|
||||
LOG(INFO) << model_proto.DebugString();
|
||||
}
|
||||
if (FLAGS_test_proto || FLAGS_model_stats || FLAGS_print_model) {
|
||||
Solver solver(model_proto.model());
|
||||
std::vector<SearchMonitor*> monitors;
|
||||
if (!solver.LoadModel(model_proto, &monitors)) {
|
||||
LOG(INFO) << "Could not load model into the solver";
|
||||
return kProblem;
|
||||
}
|
||||
if (FLAGS_test_proto) {
|
||||
LOG(INFO) << "Model " << model_proto.model() << " loaded OK";
|
||||
}
|
||||
if (FLAGS_model_stats) {
|
||||
ModelVisitor* const visitor = solver.MakeStatisticsModelVisitor();
|
||||
solver.Accept(visitor, monitors);
|
||||
}
|
||||
if (FLAGS_print_model) {
|
||||
ModelVisitor* const visitor = solver.MakePrintModelVisitor();
|
||||
solver.Accept(visitor, monitors);
|
||||
}
|
||||
}
|
||||
|
||||
// ----- Output -----
|
||||
|
||||
if (!FLAGS_output.empty()) {
|
||||
File* const output = File::Open(FLAGS_output, "w");
|
||||
if (output == NULL) {
|
||||
LOG(INFO) << "Cannot open " << FLAGS_output;
|
||||
return kProblem;
|
||||
}
|
||||
RecordWriter writer(output);
|
||||
if (!(writer.WriteProtocolMessage(model_proto) && writer.Close())) {
|
||||
return kProblem;
|
||||
} else {
|
||||
LOG(INFO) << "Model successfully written to " << FLAGS_output;
|
||||
}
|
||||
}
|
||||
|
||||
if (!FLAGS_dot_file.empty()) {
|
||||
File* const dot_file = File::Open(FLAGS_dot_file, "w");
|
||||
if (dot_file == NULL) {
|
||||
LOG(INFO) << "Cannot open " << FLAGS_dot_file;
|
||||
return kProblem;
|
||||
}
|
||||
ExportToDot(model_proto, dot_file);
|
||||
dot_file->Close();
|
||||
}
|
||||
return kOk;
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||
if (FLAGS_input.empty()) {
|
||||
LOG(FATAL) << "Filename not specified";
|
||||
}
|
||||
return operations_research::Run();
|
||||
}
|
||||
Reference in New Issue
Block a user