small sync
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user