add model I/O at the solver level

This commit is contained in:
lperron@google.com
2011-09-05 13:45:29 +00:00
parent ce12e94dc1
commit 35677ecf29
16 changed files with 3095 additions and 67 deletions

View File

@@ -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

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -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";

View File

@@ -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);
};

View File

@@ -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,

View File

@@ -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_

View File

@@ -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 {

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

File diff suppressed because it is too large Load Diff

View 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;
}

View File

@@ -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,

View File

@@ -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
View 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();
}