small sync

This commit is contained in:
lperron@google.com
2014-08-15 16:56:56 +00:00
parent 4132bb3623
commit a8082e47eb
4 changed files with 270 additions and 258 deletions

View File

@@ -28,18 +28,18 @@
// Add a char* cast to the SWIG 1.3.21 typemaps to remove a compiler warning.
%typemap(constcode) long long {
PyObject *object = PyLong_FromLongLong($value);
if (object) {
int rc = PyDict_SetItemString(d, (char*) "$symname", object);
Py_DECREF(object);
}
PyObject *object = PyLong_FromLongLong($value);
if (object) {
int rc = PyDict_SetItemString(d, (char*) "$symname", object);
Py_DECREF(object);
}
}
%typemap(constcode) unsigned long long {
PyObject *object = PyLong_FromUnsignedLongLong($value);
if (object) {
int rc = PyDict_SetItemString(d, (char*) "$symname", object);
Py_DECREF(object);
}
PyObject *object = PyLong_FromUnsignedLongLong($value);
if (object) {
int rc = PyDict_SetItemString(d, (char*) "$symname", object);
Py_DECREF(object);
}
}
%{
@@ -70,49 +70,52 @@ Py_DECREF(object);
// std::string
class std::string;
namespace std {
class std::string;
%typemap(typecheck) std::string = char *;
%typemap(typecheck) const std::string & = char *;
%typemap(typecheck) std::string = char *;
%typemap(typecheck) const std::string & = char *;
%typemap(in) std::string {
char * buf;
Py_ssize_t len;
if (PyString_AsStringAndSize($input, &buf, &len) == -1)
return NULL;
$1 = std::string(buf, len);
}
%typemap(in) std::string {
char * buf;
Py_ssize_t len;
if (PyString_AsStringAndSize($input, &buf, &len) == -1)
return NULL;
$1 = std::string(buf, len);
}
%typemap(in) const std::string & (std::string temp) {
char * buf;
Py_ssize_t len;
if (PyString_AsStringAndSize($input, &buf, &len) == -1)
return NULL;
temp = std::string(buf, len);
$1 = &temp;
}
%typemap(in) const std::string & (std::string temp) {
char * buf;
Py_ssize_t len;
if (PyString_AsStringAndSize($input, &buf, &len) == -1)
return NULL;
temp = std::string(buf, len);
$1 = &temp;
}
%typemap(out) std::string {
$result = PyString_FromStringAndSize($1.data(), $1.size());
}
%typemap(out) std::string {
$result = PyString_FromStringAndSize($1.data(), $1.size());
}
%typemap(out) const std::string & {
$result = PyString_FromStringAndSize($1->data(), $1->size());
}
%typemap(out) const std::string & {
$result = PyString_FromStringAndSize($1->data(), $1->size());
}
%typemap(in, numinputs = 0) std::string * OUTPUT (std::string temp) {
temp = std::string();
$1 = &temp;
}
%typemap(in, numinputs = 0) std::string * OUTPUT (std::string temp) {
temp = std::string();
$1 = &temp;
}
%typemap(argout, fragment = "t_output_helper") std::string * OUTPUT {
$result = t_output_helper(
$result,
PyString_FromStringAndSize($1->data(), $1->length()));
}
%typemap(argout, fragment = "t_output_helper") std::string * OUTPUT {
$result = t_output_helper(
$result,
PyString_FromStringAndSize($1->data(), $1->length()));
}
%typemap(varout) std::string {
$result = PyString_FromStringAndSize($1.data(), $1.size());
}
%typemap(varout) std::string {
$result = PyString_FromStringAndSize($1.data(), $1.size());
}
%apply const std::string & {std::string &};
@@ -126,9 +129,9 @@ class std::string;
// Swig2 no longer protects char* from being NULL, so we must use explicit check
// like %apply Pointer NONNULL {const char *};
%typemap(check) Pointer NONNULL {
if ($1 == NULL) {
SWIG_exception(SWIG_TypeError, "'$1_name' must not be None");
}
if ($1 == NULL) {
SWIG_exception(SWIG_TypeError, "'$1_name' must not be None");
}
}
// We no longer provide typemaps for std:: namespace.
@@ -138,43 +141,43 @@ SWIG_exception(SWIG_TypeError, "'$1_name' must not be None");
%typemap(typecheck) const std::string & = char *;
%typemap(in) std::string {
char * buf;
Py_ssize_t len;
if (PyString_AsStringAndSize($input, &buf, &len) == -1)
return NULL;
$1 = std::string(buf, len);
char * buf;
Py_ssize_t len;
if (PyString_AsStringAndSize($input, &buf, &len) == -1)
return NULL;
$1 = std::string(buf, len);
}
%typemap(in) const std::string & (std::string temp) {
char * buf;
Py_ssize_t len;
if (PyString_AsStringAndSize($input, &buf, &len) == -1)
return NULL;
temp = std::string(buf, len);
$1 = &temp;
char * buf;
Py_ssize_t len;
if (PyString_AsStringAndSize($input, &buf, &len) == -1)
return NULL;
temp = std::string(buf, len);
$1 = &temp;
}
%typemap(out) std::string {
$result = PyString_FromStringAndSize($1.data(), $1.size());
$result = PyString_FromStringAndSize($1.data(), $1.size());
}
%typemap(out) const std::string & {
$result = PyString_FromStringAndSize($1->data(), $1->size());
$result = PyString_FromStringAndSize($1->data(), $1->size());
}
%typemap(in, numinputs = 0) std::string * OUTPUT (std::string temp) {
temp = std::string();
$1 = &temp;
temp = std::string();
$1 = &temp;
}
%typemap(argout, fragment = "t_output_helper") std::string * OUTPUT {
$result = t_output_helper(
$result,
PyString_FromStringAndSize($1->data(), $1->length()));
$result = t_output_helper(
$result,
PyString_FromStringAndSize($1->data(), $1->length()));
}
%typemap(varout) std::string {
$result = PyString_FromStringAndSize($1.data(), $1.size());
$result = PyString_FromStringAndSize($1.data(), $1.size());
}
%apply const std::string & {std::string &};
@@ -182,18 +185,18 @@ $result = PyString_FromStringAndSize($1.data(), $1.size());
// Support for those popular buffer-pointer/length input pairs
%typemap(in) (void *INPUT, unsigned int LENGTH) (Py_ssize_t len) {
if (PyObject_AsReadBuffer($input, (const void**) &$1, &len) != 0)
return NULL;
if (((Py_ssize_t)($2_type)len) != len) {
SWIG_exception(SWIG_ValueError, "input data too large");
}
$2 = ($2_type)len;
if (PyObject_AsReadBuffer($input, (const void**) &$1, &len) != 0)
return NULL;
if (((Py_ssize_t)($2_type)len) != len) {
SWIG_exception(SWIG_ValueError, "input data too large");
}
$2 = ($2_type)len;
}
%typemap(in) (void *INPUT, uint64 LENGTH) (Py_ssize_t len) {
if (PyObject_AsReadBuffer($input, (const void**) &$1, &len) != 0)
return NULL;
$2 = len;
if (PyObject_AsReadBuffer($input, (const void**) &$1, &len) != 0)
return NULL;
$2 = len;
}
// char **
@@ -201,9 +204,9 @@ $2 = len;
%typemap(in, numinputs=0) char ** OUTPUT {
}
%typemap(argout, fragment="t_output_helper") char ** OUTPUT {
char* tmpstr = NULL;
if ($1 != NULL) tmpstr = *$1;
$result = t_output_helper($result, PyString_FromString(tmpstr));
char* tmpstr = NULL;
if ($1 != NULL) tmpstr = *$1;
$result = t_output_helper($result, PyString_FromString(tmpstr));
}
@@ -217,36 +220,36 @@ $result = t_output_helper($result, PyString_FromString(tmpstr));
%define LIST_OUTPUT_TYPEMAP(type, py_converter)
%typemap(in) std::vector<type>(std::vector<type> temp) {
if (!vector_input_helper($input, &temp, PyObjAs<type>)) {
if (!PyErr_Occurred())
SWIG_Error(SWIG_TypeError, "sequence(type) expected");
return NULL;
}
$1 = temp;
if (!vector_input_helper($input, &temp, PyObjAs<type>)) {
if (!PyErr_Occurred())
SWIG_Error(SWIG_TypeError, "sequence(type) expected");
return NULL;
}
$1 = temp;
}
%typemap(in) const std::vector<type>& (std::vector<type> temp),
const std::vector<type>* (std::vector<type> temp) {
if (!vector_input_helper($input, &temp, PyObjAs<type>)) {
if (!PyErr_Occurred())
SWIG_Error(SWIG_TypeError, "sequence(type) expected");
return NULL;
}
$1 = &temp;
const std::vector<type>* (std::vector<type> temp) {
if (!vector_input_helper($input, &temp, PyObjAs<type>)) {
if (!PyErr_Occurred())
SWIG_Error(SWIG_TypeError, "sequence(type) expected");
return NULL;
}
$1 = &temp;
}
%typemap(in,numinputs=0)
std::vector<type>* OUTPUT (std::vector<type> temp),
hash_set<type>* OUTPUT (hash_set<type> temp),
std::set<type>* OUTPUT (std::set<type> temp) {
$1 = &temp;
std::vector<type>* OUTPUT (std::vector<type> temp),
hash_set<type>* OUTPUT (hash_set<type> temp),
std::set<type>* OUTPUT (std::set<type> temp) {
$1 = &temp;
}
%typemap(argout) std::vector<type>* OUTPUT, std::set<type>* OUTPUT, hash_set<type>* OUTPUT {
%append_output(list_output_helper($1, &py_converter));
%append_output(list_output_helper($1, &py_converter));
}
%typemap(out) std::vector<type> {
$result = vector_output_helper(&$1, &py_converter);
$result = vector_output_helper(&$1, &py_converter);
}
%typemap(out) std::vector<type>*, const std::vector<type>& {
$result = vector_output_helper($1, &py_converter);
$result = vector_output_helper($1, &py_converter);
}
%enddef
@@ -309,34 +312,34 @@ COPY_TYPEMAPS(uint64, Fprint);
#undef COPY_TYPEMAPS
%apply (void * INPUT, unsigned int LENGTH)
{ (void * INPUT, uint32 LENGTH) }
{ (void * INPUT, uint32 LENGTH) }
%apply (void * INPUT, uint64 LENGTH)
{ (void * INPUT, size_t LENGTH) };
{ (void * INPUT, size_t LENGTH) };
%apply (void * INPUT, unsigned int LENGTH)
{ (const void * INPUT, unsigned int LENGTH) };
{ (const void * INPUT, unsigned int LENGTH) };
%apply (void * INPUT, unsigned int LENGTH)
{ (const void * INPUT, uint32 LENGTH) };
{ (const void * INPUT, uint32 LENGTH) };
%apply (void * INPUT, uint64 LENGTH)
{ (const void * INPUT, size_t LENGTH) };
{ (const void * INPUT, size_t LENGTH) };
%apply (void * INPUT, unsigned int LENGTH)
{ (const char * INPUT, unsigned int LENGTH) };
{ (const char * INPUT, unsigned int LENGTH) };
%apply (void * INPUT, unsigned int LENGTH)
{ (const char * INPUT, uint32 LENGTH) };
{ (const char * INPUT, uint32 LENGTH) };
%apply (void * INPUT, uint64 LENGTH)
{ (const char * INPUT, size_t LENGTH) };
{ (const char * INPUT, size_t LENGTH) };
// We accept either python ints or longs for uint64 arguments.
%typemap(in) uint64 {
if (PyInt_Check($input)) {
$1 = static_cast<uint64>(PyInt_AsLong($input));
} else if (PyLong_Check($input)) {
$1 = static_cast<uint64>(PyLong_AsUnsignedLongLong($input));
} else {
SWIG_exception(SWIG_TypeError,
"int or long value expected for argument \"$1_name\"")
}
if (PyInt_Check($input)) {
$1 = static_cast<uint64>(PyInt_AsLong($input));
} else if (PyLong_Check($input)) {
$1 = static_cast<uint64>(PyLong_AsUnsignedLongLong($input));
} else {
SWIG_exception(SWIG_TypeError,
"int or long value expected for argument \"$1_name\"")
}
}
// When a method returns a pointer or reference to a subobject of the
@@ -345,11 +348,11 @@ SWIG_exception(SWIG_TypeError,
// the parent object alive, which indirectly keeps the subobject alive.
%define SWIG_RETURN_POINTER_TO_SUBOBJECT(cpp_method, py_method)
%feature("shadow") cpp_method %{
def py_method(*args):
result = $action(*args)
if result is not None:
result.keepalive = args[0]
return result
def py_method(*args):
result = $action(*args)
if result is not None:
result.keepalive = args[0]
return result
%}
%enddef
@@ -385,23 +388,23 @@ return result
%typemap(in) std::string
%{ if(!$input) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
$1.assign($1_pstr);
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
$1.assign($1_pstr);
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
%typemap(directorout) std::string
%{ if(!$input) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
$result.assign($1_pstr);
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
$result.assign($1_pstr);
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
%typemap(directorin,descriptor="Ljava/lang/String;") std::string
%{ $input = jenv->NewStringUTF($1.c_str()); %}
@@ -412,14 +415,14 @@ jenv->ReleaseStringUTFChars($input, $1_pstr); %}
%typemap(javain) std::string "$javainput"
%typemap(javaout) std::string {
return $jnicall;
}
return $jnicall;
}
%typemap(typecheck) std::string = char *;
%typemap(throws) std::string
%{ SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, $1.c_str());
return $null; %}
return $null; %}
// const std::string &
%typemap(jni) const std::string & "jstring"
@@ -430,27 +433,27 @@ return $null; %}
%typemap(in) const std::string &
%{ if(!$input) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
std::string $1_str($1_pstr);
$1 = &$1_str;
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
std::string $1_str($1_pstr);
$1 = &$1_str;
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
%typemap(directorout,warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) const std::string &
%{ if(!$input) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
/* possible thread - reentrant code problem */
static std::string $1_str;
$1_str = $1_pstr;
$result = &$1_str;
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
/* possible thread - reentrant code problem */
static std::string $1_str;
$1_str = $1_pstr;
$result = &$1_str;
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
%typemap(directorin,descriptor="Ljava/lang/String;") const std::string &
%{ $input = jenv->NewStringUTF($1.c_str()); %}
@@ -461,14 +464,14 @@ jenv->ReleaseStringUTFChars($input, $1_pstr); %}
%typemap(javain) const std::string & "$javainput"
%typemap(javaout) const std::string & {
return $jnicall;
}
return $jnicall;
}
%typemap(typecheck) const std::string & = char *;
%typemap(throws) const std::string &
%{ SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, $1.c_str());
return $null;
return $null;
%}
%define COPY_TYPEMAPS(oldtype, newtype)

View File

@@ -11,6 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm>
#include "base/unique_ptr.h"
#include <string>
@@ -260,8 +261,7 @@ IntVar* BuildDomainIntVar(Solver* const solver, std::vector<int64>* values);
class IntExprElement : public BaseIntExprElement {
public:
IntExprElement(Solver* const s, const std::vector<int64>& vals,
IntVar* const expr)
IntExprElement(Solver* const s, const std::vector<int64>& vals, IntVar* const expr)
: BaseIntExprElement(s, expr), values_(vals) {}
virtual ~IntExprElement() {}
@@ -369,8 +369,9 @@ class IncreasingIntExprElement : public BaseIntExpr {
IntVar* const index_;
};
IncreasingIntExprElement::IncreasingIntExprElement(
Solver* const s, const std::vector<int64>& values, IntVar* const index)
IncreasingIntExprElement::IncreasingIntExprElement(Solver* const s,
const std::vector<int64>& values,
IntVar* const index)
: BaseIntExpr(s), values_(values), index_(index) {
DCHECK(index);
DCHECK(s);
@@ -517,8 +518,7 @@ IntExpr* BuildElement(Solver* const solver, const std::vector<int64>& values,
}
} // namespace
IntExpr* Solver::MakeElement(const std::vector<int64>& values,
IntVar* const index) {
IntExpr* Solver::MakeElement(const std::vector<int64>& values, IntVar* const index) {
DCHECK(index);
DCHECK_EQ(this, index->solver());
if (index->Bound()) {
@@ -527,8 +527,7 @@ IntExpr* Solver::MakeElement(const std::vector<int64>& values,
return BuildElement(this, values, index);
}
IntExpr* Solver::MakeElement(const std::vector<int>& values,
IntVar* const index) {
IntExpr* Solver::MakeElement(const std::vector<int>& values, IntVar* const index) {
DCHECK(index);
DCHECK_EQ(this, index->solver());
if (index->Bound()) {
@@ -1505,16 +1504,14 @@ Constraint* Solver::MakeIndexOfConstraint(const std::vector<IntVar*>& vars,
}
}
IntExpr* Solver::MakeIndexExpression(const std::vector<IntVar*>& vars,
int64 value) {
IntExpr* Solver::MakeIndexExpression(const std::vector<IntVar*>& vars, int64 value) {
IntExpr* const cache = model_cache_->FindVarArrayConstantExpression(
vars, value, ModelCache::VAR_ARRAY_CONSTANT_INDEX);
if (cache != nullptr) {
return cache->Var();
} else {
const std::string name =
StringPrintf("Index(%s, %" GG_LL_FORMAT "d)",
JoinNamePtr(vars, ", ").c_str(), value);
const std::string name = StringPrintf("Index(%s, %" GG_LL_FORMAT "d)",
JoinNamePtr(vars, ", ").c_str(), value);
IntVar* const index = MakeIntVar(0, vars.size() - 1, name);
AddConstraint(MakeIndexOfConstraint(vars, index, value));
model_cache_->InsertVarArrayConstantExpression(

View File

@@ -288,21 +288,27 @@ class SumConstraint : public TreeArrayConstraint {
Demon* sum_demon_;
};
// This constraint implements sum(vars) == sum_var.
// This constraint implements sum(vars) == target_var.
class SmallSumConstraint : public Constraint {
public:
SmallSumConstraint(Solver* const solver, const std::vector<IntVar*>& vars,
IntVar* const target_var)
: Constraint(solver), vars_(vars), target_var_(target_var),
computed_min_(0), computed_max_(0), sum_demon_(nullptr) {}
: Constraint(solver),
vars_(vars),
target_var_(target_var),
computed_min_(0),
computed_max_(0),
sum_demon_(nullptr) {}
virtual ~SmallSumConstraint() {}
virtual void Post() {
for (int i = 0; i < vars_.size(); ++i) {
Demon* const demon = MakeConstraintDemon1(
solver(), this, &SmallSumConstraint::VarChanged, "VarChanged", i);
vars_[i]->WhenRange(demon);
if (!vars_[i]->Bound()) {
Demon* const demon = MakeConstraintDemon1(
solver(), this, &SmallSumConstraint::VarChanged, "VarChanged", i);
vars_[i]->WhenRange(demon);
}
}
sum_demon_ = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
solver(), this, &SmallSumConstraint::SumChanged, "SumChanged"));
@@ -775,16 +781,21 @@ class SmallMinConstraint : public Constraint {
public:
SmallMinConstraint(Solver* const solver, const std::vector<IntVar*>& vars,
IntVar* const target_var)
: Constraint(solver), vars_(vars), target_var_(target_var),
computed_min_(0), computed_max_(0) {}
: Constraint(solver),
vars_(vars),
target_var_(target_var),
computed_min_(0),
computed_max_(0) {}
virtual ~SmallMinConstraint() {}
virtual void Post() {
for (int i = 0; i < vars_.size(); ++i) {
Demon* const demon = MakeConstraintDemon1(
solver(), this, &SmallMinConstraint::VarChanged, "VarChanged", i);
vars_[i]->WhenRange(demon);
if (!vars_[i]->Bound()) {
Demon* const demon = MakeConstraintDemon1(
solver(), this, &SmallMinConstraint::VarChanged, "VarChanged", i);
vars_[i]->WhenRange(demon);
}
}
Demon* const mdemon = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
solver(), this, &SmallMinConstraint::MinVarChanged, "MinVarChanged"));
@@ -837,8 +848,7 @@ class SmallMinConstraint : public Constraint {
min_min = std::min(min_min, var->Min());
min_max = std::min(min_max, var->Max());
}
if (min_min > computed_min_.Value() ||
min_max < computed_max_.Value()) {
if (min_min > computed_min_.Value() || min_max < computed_max_.Value()) {
computed_min_.SetValue(solver(), min_min);
computed_max_.SetValue(solver(), min_max);
target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
@@ -851,8 +861,7 @@ class SmallMinConstraint : public Constraint {
const int64 new_min = target_var_->Min();
const int64 new_max = target_var_->Max();
// Nothing to do?
if (new_min <= computed_min_.Value() &&
new_max >= computed_max_.Value()) {
if (new_min <= computed_min_.Value() && new_max >= computed_max_.Value()) {
return;
}
@@ -1050,16 +1059,21 @@ class SmallMaxConstraint : public Constraint {
public:
SmallMaxConstraint(Solver* const solver, const std::vector<IntVar*>& vars,
IntVar* const target_var)
: Constraint(solver), vars_(vars), target_var_(target_var),
computed_min_(0), computed_max_(0) {}
: Constraint(solver),
vars_(vars),
target_var_(target_var),
computed_min_(0),
computed_max_(0) {}
virtual ~SmallMaxConstraint() {}
virtual void Post() {
for (int i = 0; i < vars_.size(); ++i) {
Demon* const demon = MakeConstraintDemon1(
solver(), this, &SmallMaxConstraint::VarChanged, "VarChanged", i);
vars_[i]->WhenRange(demon);
if (!vars_[i]->Bound()) {
Demon* const demon = MakeConstraintDemon1(
solver(), this, &SmallMaxConstraint::VarChanged, "VarChanged", i);
vars_[i]->WhenRange(demon);
}
}
Demon* const mdemon = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
solver(), this, &SmallMaxConstraint::MaxVarChanged, "MinVarChanged"));
@@ -1112,8 +1126,7 @@ class SmallMaxConstraint : public Constraint {
max_min = std::max(max_min, var->Min());
max_max = std::max(max_max, var->Max());
}
if (max_min > computed_min_.Value() ||
max_max < computed_max_.Value()) {
if (max_min > computed_min_.Value() || max_max < computed_max_.Value()) {
computed_min_.SetValue(solver(), max_min);
computed_max_.SetValue(solver(), max_max);
target_var_->SetRange(computed_min_.Value(), computed_max_.Value());
@@ -1126,8 +1139,7 @@ class SmallMaxConstraint : public Constraint {
const int64 new_min = target_var_->Min();
const int64 new_max = target_var_->Max();
// Nothing to do?
if (new_min <= computed_min_.Value() &&
new_max >= computed_max_.Value()) {
if (new_min <= computed_min_.Value() && new_max >= computed_max_.Value()) {
return;
}
@@ -3413,7 +3425,7 @@ Constraint* Solver::MakeSumEquality(const std::vector<IntVar*>& vars,
return MakeEquality(vars[0], var);
} else if (size == 2) {
return MakeEquality(MakeSum(vars[0], vars[1]), var);
} else {
} else {
if (DetectSumOverflow(vars)) {
return RevAlloc(new SafeSumConstraint(this, vars, var));
} else if (size <= parameters_.array_split_size) {

View File

@@ -91,15 +91,14 @@ namespace operations_research {
typedef int PathNodeIndex;
template <typename T>
class HamiltonianPathSolver {
template <typename CostType> class HamiltonianPathSolver {
// HamiltonianPathSolver computes a minimum Hamiltonian path over a graph
// defined by a cost matrix. The cost matrix need not be symmetric.
// The Hamiltonian path can be closed, in this case it's a Hamiltonian cycle,
// i.e. the algorithm solves the Travelling Salesman Problem.
// Example:
// std::vector<std::vector<int> > cost_mat;
// std::vector<std::vector<int>> cost_mat;
// ... fill in cost matrix
// HamiltonianPathSolver<int> mhp(cost_mat); // no computation done
// printf("%d\n", mhp.TravelingSalesmanCost()); // computation done and
@@ -114,20 +113,20 @@ class HamiltonianPathSolver {
// This is why we define the type NodeSet to be 32-bit wide.
typedef uint32 NodeSet;
explicit HamiltonianPathSolver(const std::vector<std::vector<T> >& cost);
explicit HamiltonianPathSolver(const std::vector<std::vector<CostType>>& cost);
~HamiltonianPathSolver();
// Replaces the cost matrix while avoiding re-allocating memory.
void ChangeCostMatrix(const std::vector<std::vector<T> >& cost);
void ChangeCostMatrix(const std::vector<std::vector<CostType>>& cost);
// Returns the Hamiltonian path cost.
T HamiltonianCost();
CostType HamiltonianCost();
// Returns the Hamiltonian path in the vector pointed to by the argument.
void HamiltonianPath(std::vector<PathNodeIndex>* path);
// Returns the cost of the TSP tour.
T TravelingSalesmanCost();
CostType TravelingSalesmanCost();
// Returns the TSP tour in the vector pointed to by the argument.
void TravelingSalesmanPath(std::vector<PathNodeIndex>* path);
@@ -150,10 +149,10 @@ class HamiltonianPathSolver {
void ComputeShortestPath(NodeSet s, PathNodeIndex dest);
// Copies the cost matrix passed as argument to the internal data structure.
void CopyCostMatrix(const std::vector<std::vector<T> >& cost);
void CopyCostMatrix(const std::vector<std::vector<CostType>>& cost);
// Reserves memory. Used in constructor and ChangeCostMatrix.
void Init(const std::vector<std::vector<T> >& cost);
void Init(const std::vector<std::vector<CostType>>& cost);
// Frees memory. Used in destructor and ChangeCostMatrix.
void Free();
@@ -170,15 +169,16 @@ class HamiltonianPathSolver {
bool triangle_inequality_checked_;
bool solved_;
PathNodeIndex num_nodes_;
T** cost_;
CostType **cost_;
NodeSet two_power_num_nodes_;
T** memory_;
CostType **memory_;
};
static const int kHamiltonianPathSolverPadValue = 1557;
template <typename T>
HamiltonianPathSolver<T>::HamiltonianPathSolver(const std::vector<std::vector<T> >& cost)
template <typename CostType>
HamiltonianPathSolver<CostType>::HamiltonianPathSolver(
const std::vector<std::vector<CostType>>& cost)
: robust_(true),
triangle_inequality_ok_(true),
robustness_checked_(false),
@@ -191,13 +191,12 @@ HamiltonianPathSolver<T>::HamiltonianPathSolver(const std::vector<std::vector<T>
Init(cost);
}
template <typename T>
HamiltonianPathSolver<T>::~HamiltonianPathSolver() {
template <typename CostType>
HamiltonianPathSolver<CostType>::~HamiltonianPathSolver() {
Free();
}
template <typename T>
void HamiltonianPathSolver<T>::Free() {
template <typename CostType> void HamiltonianPathSolver<CostType>::Free() {
if (num_nodes_ > 0) {
delete[] memory_[0];
delete[] memory_;
@@ -208,9 +207,9 @@ void HamiltonianPathSolver<T>::Free() {
}
}
template <typename T>
void HamiltonianPathSolver<T>::ChangeCostMatrix(
const std::vector<std::vector<T> >& cost) {
template <typename CostType>
void HamiltonianPathSolver<CostType>::ChangeCostMatrix(
const std::vector<std::vector<CostType>>& cost) {
robustness_checked_ = false;
triangle_inequality_checked_ = false;
solved_ = false;
@@ -222,8 +221,9 @@ void HamiltonianPathSolver<T>::ChangeCostMatrix(
}
}
template <typename T>
void HamiltonianPathSolver<T>::CopyCostMatrix(const std::vector<std::vector<T> >& cost) {
template <typename CostType>
void HamiltonianPathSolver<CostType>::CopyCostMatrix(
const std::vector<std::vector<CostType>>& cost) {
for (int i = 0; i < num_nodes_; ++i) {
CHECK_EQ(num_nodes_, cost[i].size()) << "Cost matrix must be square";
for (int j = 0; j < num_nodes_; ++j) {
@@ -232,26 +232,25 @@ void HamiltonianPathSolver<T>::CopyCostMatrix(const std::vector<std::vector<T> >
}
}
template <typename T>
bool HamiltonianPathSolver<T>::IsRobust() {
template <typename CostType> bool HamiltonianPathSolver<CostType>::IsRobust() {
if (!robustness_checked_) {
CheckRobustness();
}
return robust_;
}
template <typename T>
bool HamiltonianPathSolver<T>::VerifiesTriangleInequality() {
template <typename CostType>
bool HamiltonianPathSolver<CostType>::VerifiesTriangleInequality() {
if (!triangle_inequality_checked_) {
CheckTriangleInequality();
}
return triangle_inequality_ok_;
}
template <typename T>
void HamiltonianPathSolver<T>::CheckRobustness() {
T min_cost = std::numeric_limits<T>::max();
T max_cost = std::numeric_limits<T>::min();
template <typename CostType>
void HamiltonianPathSolver<CostType>::CheckRobustness() {
CostType min_cost = std::numeric_limits<CostType>::max();
CostType max_cost = std::numeric_limits<CostType>::min();
// We compute the min and max for the cost matrix.
for (int i = 0; i < num_nodes_; ++i) {
@@ -266,20 +265,20 @@ void HamiltonianPathSolver<T>::CheckRobustness() {
if (min_cost < 0) {
robust_ = false;
} else {
robust_ =
(min_cost > num_nodes_ * max_cost * std::numeric_limits<T>::epsilon());
robust_ = (min_cost > num_nodes_ * max_cost *
std::numeric_limits<CostType>::epsilon());
}
robustness_checked_ = true;
}
template <typename T>
void HamiltonianPathSolver<T>::CheckTriangleInequality() {
template <typename CostType>
void HamiltonianPathSolver<CostType>::CheckTriangleInequality() {
triangle_inequality_ok_ = true;
triangle_inequality_checked_ = true;
for (int k = 0; k < num_nodes_; ++k) {
for (int i = 0; i < num_nodes_; ++i) {
for (int j = 0; j < num_nodes_; ++j) {
T detour_cost = cost_[i][k] + cost_[k][j];
CostType detour_cost = cost_[i][k] + cost_[k][j];
if (detour_cost < cost_[i][j]) {
triangle_inequality_ok_ = false;
return;
@@ -289,13 +288,14 @@ void HamiltonianPathSolver<T>::CheckTriangleInequality() {
}
}
template <typename T>
void HamiltonianPathSolver<T>::Init(const std::vector<std::vector<T> >& cost) {
template <typename CostType>
void HamiltonianPathSolver<CostType>::Init(
const std::vector<std::vector<CostType>>& cost) {
num_nodes_ = cost.size();
if (num_nodes_ > 0) {
cost_ = new T* [num_nodes_];
cost_ = new CostType* [num_nodes_];
for (int i = 0; i < num_nodes_; ++i) {
cost_[i] = new T[num_nodes_];
cost_[i] = new CostType[num_nodes_];
}
CopyCostMatrix(cost);
@@ -312,17 +312,17 @@ void HamiltonianPathSolver<T>::Init(const std::vector<std::vector<T> >& cost) {
const int padded_size =
two_power_num_nodes_ + kHamiltonianPathSolverPadValue;
memory_ = new T* [num_nodes_];
memory_[0] = new T[num_nodes_ * padded_size];
memory_ = new CostType* [num_nodes_];
memory_[0] = new CostType[num_nodes_ * padded_size];
for (int i = 1; i < num_nodes_; ++i) {
memory_[i] = memory_[i - 1] + padded_size;
}
}
}
template <typename T>
void HamiltonianPathSolver<T>::ComputeShortestPath(NodeSet subset,
PathNodeIndex dest) {
template <typename CostType>
void HamiltonianPathSolver<CostType>::ComputeShortestPath(NodeSet subset,
PathNodeIndex dest) {
// We iterate on the set bits in the NodeSet subset, instead of checking
// which bits are set as in the loop:
// for (int src = 0; src < num_nodes_; ++src) {
@@ -334,13 +334,13 @@ void HamiltonianPathSolver<T>::ComputeShortestPath(NodeSet subset,
const PathNodeIndex first_src =
LeastSignificantBitPosition32(first_singleton);
NodeSet start_subset = subset - first_singleton;
T min_cost = memory_[first_src][start_subset] + cost_[first_src][dest];
CostType min_cost = memory_[first_src][start_subset] + cost_[first_src][dest];
NodeSet copy = start_subset;
while (copy != 0) {
const NodeSet singleton = LeastSignificantBitWord32(copy);
const PathNodeIndex src = LeastSignificantBitPosition32(singleton);
const NodeSet new_subset = subset - singleton;
const T cost = memory_[src][new_subset] + cost_[src][dest];
const CostType cost = memory_[src][new_subset] + cost_[src][dest];
if (cost < min_cost) {
min_cost = cost;
}
@@ -349,8 +349,7 @@ void HamiltonianPathSolver<T>::ComputeShortestPath(NodeSet subset,
memory_[dest][subset] = min_cost;
}
template <typename T>
void HamiltonianPathSolver<T>::Solve() {
template <typename CostType> void HamiltonianPathSolver<CostType>::Solve() {
if (solved_) return;
for (PathNodeIndex dest = 0; dest < num_nodes_; ++dest) {
memory_[dest][0] = cost_[0][dest];
@@ -363,8 +362,8 @@ void HamiltonianPathSolver<T>::Solve() {
solved_ = true;
}
template <typename T>
T HamiltonianPathSolver<T>::HamiltonianCost() {
template <typename CostType>
CostType HamiltonianPathSolver<CostType>::HamiltonianCost() {
if (num_nodes_ <= 1) {
return 0;
}
@@ -372,8 +371,9 @@ T HamiltonianPathSolver<T>::HamiltonianCost() {
return memory_[num_nodes_ - 1][two_power_num_nodes_ - 1];
}
template <typename T>
void HamiltonianPathSolver<T>::HamiltonianPath(std::vector<PathNodeIndex>* path) {
template <typename CostType>
void HamiltonianPathSolver<CostType>::HamiltonianPath(
std::vector<PathNodeIndex>* path) {
if (num_nodes_ <= 1) {
path->resize(1);
(*path)[0] = 0;
@@ -412,9 +412,9 @@ void HamiltonianPathSolver<T>::HamiltonianPath(std::vector<PathNodeIndex>* path)
// that there are also less cache misses, there is a factor 2.5x in speed
// when using this trick.
template <typename T>
void HamiltonianPathSolver<T>::Path(PathNodeIndex end,
std::vector<PathNodeIndex>* path) {
template <typename CostType>
void HamiltonianPathSolver<CostType>::Path(PathNodeIndex end,
std::vector<PathNodeIndex>* path) {
PathNodeIndex dest = end;
NodeSet current_set = two_power_num_nodes_ - 1;
// It may happen that node 0 be on a segment (node i, node j), in which case
@@ -431,10 +431,10 @@ void HamiltonianPathSolver<T>::Path(PathNodeIndex end,
const double current_cost = memory_[dest][current_set];
const double incumbent_cost =
memory_[src][incumbent_set] + cost_[src][dest];
// We take precision into account in case T is float or double.
// There is no visible penalty in the case T is an integer type.
// We take precision into account in case CostType is float or double.
// There is no visible penalty in the case CostType is an integer type.
if (fabs(current_cost - incumbent_cost) <=
std::numeric_limits<T>::epsilon() * current_cost) {
std::numeric_limits<CostType>::epsilon() * current_cost) {
current_set = incumbent_set;
dest = src;
(*path)[i] = dest;
@@ -446,8 +446,8 @@ void HamiltonianPathSolver<T>::Path(PathNodeIndex end,
}
}
template <typename T>
T HamiltonianPathSolver<T>::TravelingSalesmanCost() {
template <typename CostType>
CostType HamiltonianPathSolver<CostType>::TravelingSalesmanCost() {
if (num_nodes_ <= 1) {
return 0;
}
@@ -455,8 +455,8 @@ T HamiltonianPathSolver<T>::TravelingSalesmanCost() {
return memory_[0][two_power_num_nodes_ - 1];
}
template <typename T>
void HamiltonianPathSolver<T>::TravelingSalesmanPath(
template <typename CostType>
void HamiltonianPathSolver<CostType>::TravelingSalesmanPath(
std::vector<PathNodeIndex>* path) {
if (num_nodes_ <= 1) {
path->resize(1);