I am hoping that this is a simple SWIG issue. I am using the Google OR-Tools optimization library. It is a C++ library that is wrapped in SWIG (which I know little about). I am having great difficult getting a Python callback function to work. There is a C++ function
DecisionBuilder* MakePhase(const std::vector<IntVar*>& vars,
IndexEvaluator1* var_evaluator,
IntValueStrategy val_str);
along with
typedef ResultCallback1<int64, int64> IndexEvaluator1;
and the relevant SWIG (I believe) is
DecisionBuilder* VarEvalValStrPhase(
const std::vector<IntVar*>& vars,
ResultCallback1<int64, int64>* var_evaluator,
operations_research::Solver::IntValueStrategy val_str) {
return self->MakePhase(vars, var_evaluator, val_str);
}
and in another SWIG file we have
%{
static int64 PyCallback1Int64Int64(PyObject* pyfunc, int64 i) {
// () needed to force creation of one-element tuple
PyObject* pyresult = PyEval_CallFunction(pyfunc, "(l)", static_cast<long>(i));
int64 result = 0;
if (!pyresult) {
PyErr_SetString(PyExc_RuntimeError,
"ResultCallback1<int64, int64> invocation failed.");
} else {
result = PyInt_AsLong(pyresult);
Py_DECREF(pyresult);
}
return result;
}
%}
%typemap(in) ResultCallback1<int64, int64>* {
if (!PyCallable_Check($input)) {
PyErr_SetString(PyExc_TypeError, "Need a callable object!");
SWIG_fail;
}
$1 = NewPermanentCallback(&PyCallback1Int64Int64, $input);
}
In my Python module I have defined a function, Run1, as follows (and here is where part of me thinks there should be some type casts, but I gather that is not the Python way):
def Run1(index1):
return index1
and set
selector_callback = Run1
solver = pywrapcp.Solver("graph-coloring")
Finally, I call
solver.Phase(nodes,
selector_callback,
solver.INT_VALUE_DEFAULT)
and here alas is where things go kablooie, I always get the following error:
File "C:\dev\Python27\lib\site-packages\ortools-1.3853-py2.7-win-amd64.egg\ortools\constraint_solver\pywrapcp.py", line 457, in Phase
def Phase(self, *args): return _pywrapcp.Solver_Phase(self, *args)
NotImplementedError: Wrong number or type of arguments for overloaded function 'Solver_Phase'.
Possible C/C++ prototypes are:
operations_research::Solver::MakePhase(std::vector< operations_research::IntVar *,std::allocator< operations_research::IntVar * > > const &,operations_research::Solver::IntVarStrategy,operations_research::Solver::IntValueStrategy)
operations_research::Solver::MakePhase(std::vector< operations_research::IntervalVar *,std::allocator< operations_research::IntervalVar * > > const &,operations_research::Solver::IntervalStrategy)
operations_research::Solver::MakePhase(std::vector< operations_research::SequenceVar *,std::allocator< operations_research::SequenceVar * > > const &,operations_research::Solver::SequenceStrategy)
The difficulty is with the callback function in the second argument; if I use one of the built-in values instead of the callback the operation is successful. But, I do need to have my own function in there.
I am not importing any SWIG files in my module. Do I need to do this?
So after days, I found the answer. If I call
solver.VarEvalValStrPhase(nodes,
selector_callback,
solver.INT_VALUE_DEFAULT)
instead of the standard function name Phase
referenced throughout the manuals, it works. If I were to use another argument combination I'd have to use another function name I believe. It appears that overloading fails in this case. Which is fine, but a warning from the developers would have been nice.