Rework C# Callback to use delegates

This commit is contained in:
Corentin Le Molgat
2019-01-18 17:39:13 +01:00
parent f213fede2f
commit ec4a7d6e0d
10 changed files with 312 additions and 489 deletions

View File

@@ -167,7 +167,6 @@ $(GEN_DIR)/ortools/constraint_solver/constraint_solver_csharp_wrap.cc: \
$(SRC_DIR)/ortools/constraint_solver/csharp/constraint_solver.i \
$(SRC_DIR)/ortools/base/base.i \
$(SRC_DIR)/ortools/util/csharp/proto.i \
$(SRC_DIR)/ortools/util/csharp/functions.i \
$(CP_DEPS) \
| $(GEN_DIR)/ortools/constraint_solver
$(SWIG_BINARY) $(SWIG_INC) -I$(INC_DIR) -c++ -csharp \
@@ -739,20 +738,20 @@ clean_dotnet:
-$(DELREC) ortools$Sdotnet$SCreateSigningKey$Sbin
-$(DELREC) ortools$Sdotnet$SCreateSigningKey$Sobj
-$(DEL) $(DOTNET_ORTOOLS_SNK_PATH)
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_NATIVE_ASSEMBLY_NAME)$S$(OR_TOOLS_NATIVE_ASSEMBLY_NAME).csproj
-$(DEL) ortools$Sdotnet$S$(OR_TOOLS_NATIVE_ASSEMBLY_NAME)$S$(OR_TOOLS_NATIVE_ASSEMBLY_NAME)*.csproj
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_NATIVE_ASSEMBLY_NAME)$Sbin
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_NATIVE_ASSEMBLY_NAME)$Sobj
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_ASSEMBLY_NAME)$S$(OR_TOOLS_ASSEMBLY_NAME).csproj
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_ASSEMBLY_NAME)$Sruntime.json
-$(DEL) ortools$Sdotnet$S$(OR_TOOLS_ASSEMBLY_NAME)$S$(OR_TOOLS_ASSEMBLY_NAME)*.csproj
-$(DEL) ortools$Sdotnet$S$(OR_TOOLS_ASSEMBLY_NAME)$Sruntime.json
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_ASSEMBLY_NAME)$Sbin
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_ASSEMBLY_NAME)$Sobj
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_TESTS_ASSEMBLY_NAME)$S$(OR_TOOLS_TESTS_ASSEMBLY_NAME).csproj
-$(DEL) ortools$Sdotnet$S$(OR_TOOLS_TESTS_ASSEMBLY_NAME)$S$(OR_TOOLS_TESTS_ASSEMBLY_NAME)*.csproj
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_TESTS_ASSEMBLY_NAME)$Sbin
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_TESTS_ASSEMBLY_NAME)$Sobj
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_FSHARP_ASSEMBLY_NAME)$S$(OR_TOOLS_FSHARP_ASSEMBLY_NAME).fsproj
-$(DEL) ortools$Sdotnet$S$(OR_TOOLS_FSHARP_ASSEMBLY_NAME)$S$(OR_TOOLS_FSHARP_ASSEMBLY_NAME)*.fsproj
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_FSHARP_ASSEMBLY_NAME)$Sbin
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_FSHARP_ASSEMBLY_NAME)$Sobj
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_FSHARP_TESTS_ASSEMBLY_NAME)$S$(OR_TOOLS_FSHARP_TESTS_ASSEMBLY_NAME).fsproj
-$(DEL) ortools$Sdotnet$S$(OR_TOOLS_FSHARP_TESTS_ASSEMBLY_NAME)$S$(OR_TOOLS_FSHARP_TESTS_ASSEMBLY_NAME)*.fsproj
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_FSHARP_TESTS_ASSEMBLY_NAME)$Sbin
-$(DELREC) ortools$Sdotnet$S$(OR_TOOLS_FSHARP_TESTS_ASSEMBLY_NAME)$Sobj
-$(DELREC) $(PACKAGE_DIR)

View File

@@ -15,9 +15,6 @@ namespace Google.OrTools.ConstraintSolver {
using System;
using System.Collections.Generic;
public delegate long TransitCallback(long FromIndex, long ToIndex);
public delegate long UnaryTransitCallback(long FromIndex);
public partial class Solver : IDisposable {
public IntVar[] MakeIntVarArray(int count, long min, long max) {
IntVar[] array = new IntVar[count];

View File

@@ -17,16 +17,18 @@
using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Generic;
%}
%include "enumsimple.swg"
%include "stdint.i"
%include "exception.i"
%include "std_vector.i"
%include "std_common.i"
%include "std_string.i"
%include "ortools/base/base.i"
%include "ortools/util/csharp/tuple_set.i"
%include "ortools/util/csharp/functions.i"
%include "ortools/util/csharp/proto.i"
// We need to forward-declare the proto here, so that PROTO_INPUT involving it
@@ -37,7 +39,7 @@ class ConstraintSolverParameters;
class SearchLimitParameters;
} // namespace operations_research
%module(directors="1", allprotected="1") operations_research;
%module(directors="1") operations_research;
#pragma SWIG nowarn=473
%feature("director") BaseLns;
@@ -81,8 +83,8 @@ struct FailureProtect {
};
%}
typedef int64_t int64;
typedef uint64_t uint64;
//typedef int64_t int64;
//typedef uint64_t uint64;
/* allow partial c# classes */
%typemap(csclassmodifiers) SWIGTYPE "public partial class"
@@ -161,10 +163,6 @@ CS_TYPEMAP_STDVECTOR_OBJECT(operations_research::LocalSearchOperator, LocalSearc
CS_TYPEMAP_STDVECTOR_OBJECT(operations_research::LocalSearchFilter, LocalSearchFilter)
CS_TYPEMAP_STDVECTOR_OBJECT(operations_research::SymmetryBreaker, SymmetryBreaker)
%ignore operations_research::Solver::MakeIntVarArray;
%ignore operations_research::Solver::MakeBoolVarArray;
%ignore operations_research::Solver::MakeFixedDurationIntervalVarArray;
%ignore operations_research::IntVarLocalSearchFilter::FindIndex;
%ignore operations_research::PropagationBaseObject::set_action_on_fail;
// Generic rename rule.
@@ -198,11 +196,20 @@ CS_TYPEMAP_STDVECTOR_OBJECT(operations_research::SymmetryBreaker, SymmetryBreake
// Rename rule on SearchLimit
%rename (IsCrossed) operations_research::SearchLimit::crossed;
// Rename rules on Solver.
%rename (Add) operations_research::Solver::AddConstraint;
// Rename rule on DisjunctiveConstraint.
%rename (SequenceVar) operations_research::DisjunctiveConstraint::MakeSequenceVar;
// Keep reference to delegate to avoid GC to collect them early
%typemap(cscode) operations_research::DisjunctiveConstraint %{
// Store list of delegates to avoid the GC to reclaim them.
private List<IndexEvaluator2> indexEvaluator2Callbacks;
// Ensure that the GC does not collect any IndexEvaluator1Callback set from C#
// as the underlying C++ class will only store a pointer to it (i.e. no ownership).
private IndexEvaluator2 StoreIndexEvaluator2(IndexEvaluator2 c) {
if (indexEvaluator2Callbacks == null) indexEvaluator2Callbacks = new List<IndexEvaluator2>();
indexEvaluator2Callbacks.Add(c);
return c;
}
%}
// Generic rename rules.
%rename (ToString) *::DebugString;
@@ -282,7 +289,7 @@ CS_TYPEMAP_STDVECTOR_OBJECT(operations_research::SymmetryBreaker, SymmetryBreake
%unignore operations_research::PathOperator::MakeNeighbor;
// LocalSearchFilter
%feature("director") operations_research::IntVarLocalSearchFilter;
%feature("director") operations_research::LocalSearchFilter;
%unignore operations_research::LocalSearchFilter::Accept;
%unignore operations_research::LocalSearchFilter::Synchronize;
%unignore operations_research::LocalSearchFilter::IsIncremental;
@@ -293,6 +300,9 @@ CS_TYPEMAP_STDVECTOR_OBJECT(operations_research::SymmetryBreaker, SymmetryBreake
%feature("director") operations_research::IntVarLocalSearchFilter;
%feature("nodirector") operations_research::IntVarLocalSearchFilter::Synchronize; // Inherited.
%ignore operations_research::IntVarLocalSearchFilter::FindIndex;
%ignore operations_research::IntVarLocalSearchFilter::IntVarLocalSearchFilter(
const std::vector<IntVar*>& vars,
Solver::ObjectiveWatcher objective_callback);
%unignore operations_research::IntVarLocalSearchFilter::AddVars; // Inherited.
%unignore operations_research::IntVarLocalSearchFilter::IsIncremental;
%unignore operations_research::IntVarLocalSearchFilter::OnSynchronize;
@@ -300,11 +310,25 @@ CS_TYPEMAP_STDVECTOR_OBJECT(operations_research::SymmetryBreaker, SymmetryBreake
%unignore operations_research::IntVarLocalSearchFilter::Start;
%unignore operations_research::IntVarLocalSearchFilter::Value;
%unignore operations_research::IntVarLocalSearchFilter::Var; // Inherited.
// Rename NewSearch and EndSearch to add pinning. See the overrides of
// NewSearch in ../../open_source/csharp/constraint_solver/SolverHelper.cs
%rename (NewSearchAux) operations_research::Solver::NewSearch;
%rename (EndSearchAux) operations_research::Solver::EndSearch;
// Extend IntVarLocalSearchFilter with an intuitive API.
%extend operations_research::IntVarLocalSearchFilter {
int Index(IntVar* const var) {
int64 index = -1;
$self->FindIndex(var, &index);
return index;
}
}
// Keep reference to delegate to avoid GC to collect them early
%typemap(cscode) operations_research::IntVarLocalSearchFilter %{
// Store list of delegates to avoid the GC to reclaim them.
private ObjectiveWatcher objectiveWatcherCallbacks;
// Ensure that the GC does not collect any IndexEvaluator1Callback set from C#
// as the underlying C++ class will only store a pointer to it (i.e. no ownership).
private ObjectiveWatcher StoreObjectiveWatcher(ObjectiveWatcher c) {
objectiveWatcherCallbacks = c;
return c;
}
%}
// Transform IntVar.
%ignore operations_research::IntVar::MakeDomainIterator;
@@ -324,10 +348,14 @@ CS_TYPEMAP_STDVECTOR_OBJECT(operations_research::SymmetryBreaker, SymmetryBreake
%typemap(csinterfaces_derived) operations_research::Constraint "IConstraintWithStatus";
// Solver
namespace operations_research {
// Take care of API with function. SWIG doesn't wrap std::function<>
// properly, so we write our custom wrappers for all methods involving
// std::function<>.
// Ignore rules on Solver.
%ignore Solver::MakeIntVarArray;
%ignore Solver::MakeBoolVarArray;
%ignore Solver::MakeFixedDurationIntervalVarArray;
// Take care of API with function. SWIG doesn't wrap std::function<> properly,
// so we write our custom wrappers for all methods involving std::function<>.
%ignore Solver::MakeSearchLog(
int branch_period,
std::function<std::string()> display_callback);
@@ -342,355 +370,168 @@ namespace operations_research {
%ignore Solver::MakeActionDemon;
%ignore Solver::MakeCustomLimit(std::function<bool()> limiter);
%ignore Solver::MakeElement(IndexEvaluator1 values, IntVar* const index);
%ignore Solver::MakeMonotonicElement(IndexEvaluator1 values, bool increasing,
IntVar* const index);
%ignore Solver::MakeElement(IndexEvaluator2 values, IntVar* const index1,
IntVar* const index2);
%ignore Solver::MakePathCumul(const std::vector<IntVar*>& nexts,
const std::vector<IntVar*>& active,
const std::vector<IntVar*>& cumuls,
IndexEvaluator2 transit_evaluator);
%ignore Solver::MakePathCumul(const std::vector<IntVar*>& nexts,
const std::vector<IntVar*>& active,
const std::vector<IntVar*>& cumuls,
const std::vector<IntVar*>& slacks,
IndexEvaluator2 transit_evaluator);
%ignore Solver::MakeNoCycle(const std::vector<IntVar*>& nexts,
const std::vector<IntVar*>& active,
IndexFilter1 sink_handler = nullptr);
%ignore Solver::MakeNoCycle(const std::vector<IntVar*>& nexts,
const std::vector<IntVar*>& active,
IndexFilter1 sink_handler, bool assume_paths);
%ignore Solver::MakeGuidedLocalSearch(bool maximize, IntVar* const objective,
IndexEvaluator2 objective_function,
int64 step, const std::vector<IntVar*>& vars,
double penalty_factor);
%ignore Solver::MakeGuidedLocalSearch(bool maximize, IntVar* const objective,
IndexEvaluator3 objective_function,
int64 step, const std::vector<IntVar*>& vars,
const std::vector<IntVar*>& secondary_vars,
double penalty_factor);
%ignore Solver::MakePhase(const std::vector<IntVar*>& vars,
IndexEvaluator1 var_evaluator,
IntValueStrategy val_str);
%ignore Solver::MakePhase(const std::vector<IntVar*>& vars,
IntVarStrategy var_str, IndexEvaluator2 val_eval);
%ignore Solver::MakePhase(
const std::vector<IntVar*>& vars, IntVarStrategy var_str,
VariableValueComparator var_val1_val2_comparator);
%ignore Solver::MakePhase(const std::vector<IntVar*>& vars,
IndexEvaluator1 var_evaluator,
IndexEvaluator2 val_eval);
%ignore Solver::MakePhase(const std::vector<IntVar*>& vars,
IntVarStrategy var_str, IndexEvaluator2 val_eval,
IndexEvaluator1 tie_breaker);
%ignore Solver::MakePhase(const std::vector<IntVar*>& vars,
IndexEvaluator1 var_evaluator,
IndexEvaluator2 val_eval,
IndexEvaluator1 tie_breaker);
%ignore Solver::MakePhase(const std::vector<IntVar*>& vars,
IndexEvaluator2 evaluator, EvaluatorStrategy str);
%ignore Solver::MakePhase(const std::vector<IntVar*>& vars,
IndexEvaluator2 evaluator,
IndexEvaluator1 tie_breaker,
EvaluatorStrategy str);
%ignore Solver::MakeOperator(const std::vector<IntVar*>& vars,
IndexEvaluator3 evaluator,
EvaluatorLocalSearchOperators op);
%ignore Solver::MakeOperator(const std::vector<IntVar*>& vars,
const std::vector<IntVar*>& secondary_vars,
IndexEvaluator3 evaluator,
EvaluatorLocalSearchOperators op);
%ignore Solver::MakeSumObjectiveFilter(
const std::vector<IntVar*>& vars, IndexEvaluator2 values,
IntVar* const objective, Solver::LocalSearchFilterBound filter_enum);
%ignore Solver::MakeSumObjectiveFilter(
const std::vector<IntVar*>& vars, IndexEvaluator2 values,
ObjectiveWatcher delta_objective_callback, IntVar* const objective,
Solver::LocalSearchFilterBound filter_enum);
%ignore Solver::MakeSumObjectiveFilter(
const std::vector<IntVar*>& vars, const std::vector<IntVar*>& secondary_vars,
Solver::IndexEvaluator3 values, IntVar* const objective,
Solver::LocalSearchFilterBound filter_enum);
%ignore Solver::MakeSumObjectiveFilter(
const std::vector<IntVar*>& vars, const std::vector<IntVar*>& secondary_vars,
Solver::IndexEvaluator3 values, ObjectiveWatcher delta_objective_callback,
IntVar* const objective, Solver::LocalSearchFilterBound filter_enum);
%ignore Solver::ConcatenateOperators(
const std::vector<LocalSearchOperator*>& ops,
std::function<int64(int, int)> evaluator);
%ignore Solver::MakeClosureDemon(std::function<void()> closure);
%ignore Solver::set_fail_intercept;
// Rename rules on Solver.
%rename (Add) Solver::AddConstraint;
// Rename NewSearch and EndSearch to add pinning. See the overrides of
// NewSearch in ../../open_source/csharp/constraint_solver/SolverHelper.cs
%rename (NewSearchAux) Solver::NewSearch;
%rename (EndSearchAux) Solver::EndSearch;
// Define the delegate IndexEvaluator[1-3] callback types.
// This replace the IndexEvaluator[1-3] in the C# proxy class
%typemap(csimports) Solver %{
using System.Collections.Generic; // List<>
public delegate long IndexEvaluator1(long u);
public delegate long IndexEvaluator2(long u, long v);
public delegate long IndexEvaluator3(long u, long v, long w);
public delegate bool IndexFilter1(long u);
public delegate void ObjectiveWatcher(long u);
%}
// Keep reference to delegate to avoid GC to collect them early
%typemap(cscode) Solver %{
// Store list of delegates to avoid the GC to reclaim them.
private List<IndexEvaluator1> indexEvaluator1Callbacks;
private List<IndexEvaluator2> indexEvaluator2Callbacks;
private List<IndexEvaluator3> indexEvaluator3Callbacks;
private List<IndexFilter1> indexFilter1Callbacks;
private List<ObjectiveWatcher> objectiveWatcherCallbacks;
// Ensure that the GC does not collect any IndexEvaluator1Callback set from C#
// as the underlying C++ class will only store a pointer to it (i.e. no ownership).
private IndexEvaluator1 StoreIndexEvaluator1(IndexEvaluator1 c) {
if (indexEvaluator1Callbacks == null) indexEvaluator1Callbacks = new List<IndexEvaluator1>();
indexEvaluator1Callbacks.Add(c);
return c;
}
private IndexEvaluator2 StoreIndexEvaluator2(IndexEvaluator2 c) {
if (indexEvaluator2Callbacks == null) indexEvaluator2Callbacks = new List<IndexEvaluator2>();
indexEvaluator2Callbacks.Add(c);
return c;
}
private IndexEvaluator3 StoreIndexEvaluator3(IndexEvaluator3 c) {
if (indexEvaluator3Callbacks == null) indexEvaluator3Callbacks = new List<IndexEvaluator3>();
indexEvaluator3Callbacks.Add(c);
return c;
}
private IndexFilter1 StoreIndexFilter1(IndexFilter1 c) {
if (indexFilter1Callbacks == null) indexFilter1Callbacks = new List<IndexFilter1>();
indexFilter1Callbacks.Add(c);
return c;
}
private ObjectiveWatcher StoreObjectiveWatcher(ObjectiveWatcher c) {
if (objectiveWatcherCallbacks == null) objectiveWatcherCallbacks = new List<ObjectiveWatcher>();
objectiveWatcherCallbacks.Add(c);
return c;
}
%}
// Types in Foo.cs Foo::f(cstype csinput, ...) {Foo_f_SWIG(csin, ...);}
// e.g.:
// Foo::f(IndexEvaluator1 arg1) {
// ...
// ...PINVOKE.Foo_f_SWIG(..., StoreIndexEvaluator1(arg1), ...);
// }
%typemap(cstype, out="IntPtr") Solver::IndexEvaluator1 "IndexEvaluator1"
%typemap(csin) Solver::IndexEvaluator1 "StoreIndexEvaluator1($csinput)"
%typemap(cstype, out="IntPtr") Solver::IndexEvaluator2 "IndexEvaluator2"
%typemap(csin) Solver::IndexEvaluator2 "StoreIndexEvaluator2($csinput)"
%typemap(cstype, out="IntPtr") Solver::IndexEvaluator3 "IndexEvaluator3"
%typemap(csin) Solver::IndexEvaluator3 "StoreIndexEvaluator3($csinput)"
%typemap(cstype, out="IntPtr") Solver::IndexFilter1 "IndexFilter1"
%typemap(csin) Solver::IndexFilter1 "StoreIndexFilter1($csinput)"
%typemap(cstype, out="IntPtr") Solver::ObjectiveWatcher "ObjectiveWatcher"
%typemap(csin) Solver::ObjectiveWatcher "StoreObjectiveWatcher($csinput)"
// Type in the prototype of PINVOKE function.
%typemap(imtype, out="IntPtr") Solver::IndexEvaluator1 "IndexEvaluator1"
%typemap(imtype, out="IntPtr") Solver::IndexEvaluator2 "IndexEvaluator2"
%typemap(imtype, out="IntPtr") Solver::IndexEvaluator3 "IndexEvaluator3"
%typemap(imtype, out="IntPtr") Solver::IndexFilter1 "IndexFilter1"
%typemap(imtype, out="IntPtr") Solver::ObjectiveWatcher "ObjectiveWatcher"
// Type use in module_csharp_wrap.h function declaration.
// since SWIG generate code as: `ctype argX` we can't use a C function pointer type.
%typemap(ctype) Solver::IndexEvaluator1 "void*" // "int64 (*)(int64)"
%typemap(ctype) Solver::IndexEvaluator2 "void*" // "int64 (*)(int64, int64)"
%typemap(ctype) Solver::IndexEvaluator3 "void*" // "int64 (*)(int64, int64, int64)"
%typemap(ctype) Solver::IndexFilter1 "void*" // "bool (*)(int64)"
%typemap(ctype) Solver::ObjectiveWatcher "void*" // "void (*)(int64)"
// Convert in module_csharp_wrap.cc input argument (delegate marshaled in C function pointer) to original std::function<...>
%typemap(in) Solver::IndexEvaluator1 %{
$1 = [$input](int64 u) -> int64 {
return (*(int64 (*)(int64))$input)(u);
};
%}
%typemap(in) Solver::IndexEvaluator2 %{
$1 = [$input](int64 u, int64 v) -> int64 {
return (*(int64 (*)(int64, int64))$input)(u, v);};
%}
%typemap(in) Solver::IndexEvaluator3 %{
$1 = [$input](int64 u, int64 v, int64 w) -> int64 {
return (*(int64 (*)(int64, int64, int64))$input)(u, v, w);};
%}
%typemap(in) Solver::IndexFilter1 %{
$1 = [$input](int64 u) -> bool {
return (*(bool (*)(int64))$input)(u);};
%}
%typemap(in) Solver::ObjectiveWatcher %{
$1 = [$input](int64 u) -> void {
return (*(void (*)(int64))$input)(u);};
%}
%extend Solver {
IntExpr* MakeElement(swig_util::LongToLong* values, IntVar* const index) {
return $self->MakeElement(
[values](int64 i) { return values->Run(i); }, index);
}
IntExpr* MakeMonotonicElement(swig_util::LongToLong* values, bool increasing,
IntVar* const index) {
return $self->MakeMonotonicElement(
[values](int64 i) { return values->Run(i); }, increasing, index);
}
IntExpr* MakeElement(swig_util::LongLongToLong* values, IntVar* const index1,
IntVar* const index2) {
return $self->MakeElement(
[values](int64 i, int64 j) { return values->Run(i, j); }, index1,
index2);
}
Constraint* MakePathCumul(const std::vector<IntVar*>& nexts,
const std::vector<IntVar*>& active,
const std::vector<IntVar*>& cumuls,
swig_util::LongLongToLong* transit_evaluator) {
return $self->MakePathCumul(
nexts, active, cumuls,
[transit_evaluator](int64 i, int64 j) {
return transit_evaluator->Run(i, j); });
}
Constraint* MakePathCumul(const std::vector<IntVar*>& nexts,
const std::vector<IntVar*>& active,
const std::vector<IntVar*>& cumuls,
const std::vector<IntVar*>& slacks,
swig_util::LongLongToLong* transit_evaluator) {
return $self->MakePathCumul(nexts, active, cumuls, slacks,
[transit_evaluator](int64 i, int64 j) {
return transit_evaluator->Run(i, j); });
}
Constraint* MakeNoCycle(const std::vector<IntVar*>& nexts,
const std::vector<IntVar*>& active,
swig_util::LongToBoolean* sink_handler = nullptr) {
if (sink_handler == nullptr) {
return $self->MakeNoCycle(nexts, active, nullptr);
} else {
return $self->MakeNoCycle(nexts, active,
[sink_handler](int64 i) {
return sink_handler->Run(i); });
}
}
Constraint* MakeNoCycle(const std::vector<IntVar*>& nexts,
const std::vector<IntVar*>& active,
swig_util::LongToBoolean* sink_handler, bool assume_paths) {
return $self->MakeNoCycle(nexts, active,
[sink_handler](int64 i) {
return sink_handler->Run(i); });
}
SearchMonitor* MakeGuidedLocalSearch(bool maximize, IntVar* const objective,
swig_util::LongLongToLong* objective_function,
int64 step, const std::vector<IntVar*>& vars,
double penalty_factor) {
return $self->MakeGuidedLocalSearch(
maximize, objective,
[objective_function](int64 i, int64 j) {
return objective_function->Run(i, j); },
step, vars, penalty_factor);
}
SearchMonitor* MakeGuidedLocalSearch(bool maximize, IntVar* const objective,
swig_util::LongLongLongToLong* objective_function,
int64 step, const std::vector<IntVar*>& vars,
const std::vector<IntVar*>& secondary_vars,
double penalty_factor) {
return $self->MakeGuidedLocalSearch(
maximize, objective,
[objective_function](int64 i, int64 j, int64 k) {
return objective_function->Run(i, j, k); },
step, vars, secondary_vars, penalty_factor);
}
DecisionBuilder* MakePhase(const std::vector<IntVar*>& vars,
swig_util::LongToLong* var_evaluator,
IntValueStrategy val_str) {
return $self->MakePhase(vars, [var_evaluator](int64 i) {
return var_evaluator->Run(i); }, val_str);
}
DecisionBuilder* MakePhase(const std::vector<IntVar*>& vars,
IntVarStrategy var_str,
swig_util::LongLongToLong* val_eval) {
operations_research::Solver::IndexEvaluator2 func =
[val_eval](int64 i, int64 j) { return val_eval->Run(i, j); };
return $self->MakePhase(vars, var_str, func);
}
DecisionBuilder* MakePhase(
const std::vector<IntVar*>& vars, IntVarStrategy var_str,
swig_util::LongLongLongToBoolean* var_val1_val2_comparator) {
operations_research::Solver::VariableValueComparator comp =
[var_val1_val2_comparator](int64 i, int64 j, int64 k) {
return var_val1_val2_comparator->Run(i, j, k); };
return $self->MakePhase(vars, var_str, comp);
}
DecisionBuilder* MakePhase(const std::vector<IntVar*>& vars,
swig_util::LongToLong* var_evaluator,
swig_util::LongLongToLong* val_eval) {
return $self->MakePhase(vars, [var_evaluator](int64 i) { return var_evaluator->Run(i); }, [val_eval](int64 i, int64 j) { return val_eval->Run(i, j); });
}
DecisionBuilder* MakePhase(const std::vector<IntVar*>& vars,
IntVarStrategy var_str,
swig_util::LongLongToLong* val_eval,
swig_util::LongToLong* tie_breaker) {
return $self->MakePhase(
vars, var_str,
[val_eval](int64 i, int64 j) { return val_eval->Run(i, j); },
[tie_breaker](int64 i) { return tie_breaker->Run(i); });
}
DecisionBuilder* MakePhase(const std::vector<IntVar*>& vars,
swig_util::LongToLong* var_evaluator,
swig_util::LongLongToLong* val_eval,
swig_util::LongToLong* tie_breaker) {
return $self->MakePhase(
vars,
[var_evaluator](int64 i) { return var_evaluator->Run(i); },
[val_eval](int64 i, int64 j) { return val_eval->Run(i, j); },
[tie_breaker](int64 i) { return tie_breaker->Run(i); });
}
DecisionBuilder* MakePhase(const std::vector<IntVar*>& vars,
swig_util::LongLongToLong* evaluator,
EvaluatorStrategy str) {
return $self->MakePhase(
vars,
[evaluator](int64 i, int64 j) { return evaluator->Run(i, j); },
str);
}
DecisionBuilder* MakePhase(const std::vector<IntVar*>& vars,
swig_util::LongLongToLong* evaluator,
swig_util::LongToLong* tie_breaker,
EvaluatorStrategy str) {
return $self->MakePhase(
vars,
[evaluator](int64 i, int64 j) { return evaluator->Run(i, j); },
[tie_breaker](int64 i) { return tie_breaker->Run(i); }, str);
}
LocalSearchOperator* MakeOperator(const std::vector<IntVar*>& vars,
swig_util::LongLongLongToLong* evaluator,
EvaluatorLocalSearchOperators op) {
return $self->MakeOperator(
vars,
[evaluator](int64 i, int64 j, int64 k) {
return evaluator->Run(i, j, k); }, op);
}
LocalSearchOperator* MakeOperator(const std::vector<IntVar*>& vars,
const std::vector<IntVar*>& secondary_vars,
swig_util::LongLongLongToLong* evaluator,
EvaluatorLocalSearchOperators op) {
return $self->MakeOperator(
vars, secondary_vars,
[evaluator](int64 i, int64 j, int64 k) {
return evaluator->Run(i, j, k); }, op);
}
LocalSearchFilter* MakeSumObjectiveFilter(
const std::vector<IntVar*>& vars, swig_util::LongLongToLong* values,
IntVar* const objective, Solver::LocalSearchFilterBound filter_enum) {
return $self->MakeSumObjectiveFilter(
vars, [values](int64 i, int64 j) { return values->Run(i, j); },
objective, filter_enum);
}
LocalSearchFilter* MakeSumObjectiveFilter(
const std::vector<IntVar*>& vars, swig_util::LongLongToLong* values,
swig_util::LongToVoid* delta_objective_callback, IntVar* const objective,
Solver::LocalSearchFilterBound filter_enum) {
return $self->MakeSumObjectiveFilter(
vars, [values](int64 i, int64 j) { return values->Run(i, j); },
[delta_objective_callback](int64 i) {
return delta_objective_callback->Run(i); },
objective, filter_enum);
}
LocalSearchFilter* MakeSumObjectiveFilter(
const std::vector<IntVar*>& vars, const std::vector<IntVar*>& secondary_vars,
swig_util::LongLongLongToLong* values, IntVar* const objective,
Solver::LocalSearchFilterBound filter_enum) {
return $self->MakeSumObjectiveFilter(
vars, secondary_vars,
[values](int64 i, int64 j, int64 k) { return values->Run(i, j, k); },
objective, filter_enum);
}
LocalSearchFilter* MakeSumObjectiveFilter(
const std::vector<IntVar*>& vars,
const std::vector<IntVar*>& secondary_vars,
swig_util::LongLongLongToLong* values,
swig_util::LongToVoid* delta_objective_callback,
IntVar* const objective, Solver::LocalSearchFilterBound filter_enum) {
return $self->MakeSumObjectiveFilter(
vars, secondary_vars,
[values](int64 i, int64 j, int64 k) { return values->Run(i, j, k); },
[delta_objective_callback](int64 i) {
return delta_objective_callback->Run(i); },
objective, filter_enum);
}
LocalSearchOperator* ConcatenateOperators(
const std::vector<LocalSearchOperator*>& ops,
swig_util::IntIntToLong* evaluator) {
return $self->ConcatenateOperators(ops, [evaluator](int i, int64 j) {
return evaluator->Run(i, j); });
}
SearchMonitor* MakeSearchLog(
int branch_count,
OptimizeVar* const objective,
swig_util::VoidToString* display_callback) {
return $self->MakeSearchLog(branch_count, objective, [display_callback]() {
return display_callback->Run();
});
}
SearchMonitor* MakeSearchLog(
int branch_count,
IntVar* const obj_var,
swig_util::VoidToString* display_callback) {
return $self->MakeSearchLog(branch_count, obj_var, [display_callback]() {
return display_callback->Run();
});
}
SearchMonitor* MakeSearchLog(
int branch_count,
swig_util::VoidToString* display_callback) {
return $self->MakeSearchLog(branch_count, [display_callback]() {
return display_callback->Run();
});
}
SearchLimit* MakeCustomLimit(swig_util::VoidToBoolean* limiter) {
return $self->MakeCustomLimit([limiter]() { return limiter->Run(); });
}
Demon* MakeClosureDemon(swig_util::VoidToVoid* closure) {
return $self->MakeClosureDemon([closure]() { return closure->Run(); });
}
//LocalSearchOperator* ConcatenateOperators(
// const std::vector<LocalSearchOperator*>& ops,
// swig_util::IntIntToLong* evaluator) {
// return $self->ConcatenateOperators(ops, [evaluator](int i, int64 j) {
// return evaluator->Run(i, j); });
//}
//SearchMonitor* MakeSearchLog(
// int branch_count,
// OptimizeVar* const objective,
// swig_util::VoidToString* display_callback) {
// return $self->MakeSearchLog(branch_count, objective, [display_callback]() {
// return display_callback->Run();
// });
//}
//SearchMonitor* MakeSearchLog(
// int branch_count,
// IntVar* const obj_var,
// swig_util::VoidToString* display_callback) {
// return $self->MakeSearchLog(branch_count, obj_var, [display_callback]() {
// return display_callback->Run();
// });
//}
//SearchMonitor* MakeSearchLog(
// int branch_count,
// swig_util::VoidToString* display_callback) {
// return $self->MakeSearchLog(branch_count, [display_callback]() {
// return display_callback->Run();
// });
//}
//SearchLimit* MakeCustomLimit(swig_util::VoidToBoolean* limiter) {
// return $self->MakeCustomLimit([limiter]() { return limiter->Run(); });
//}
//Demon* MakeClosureDemon(swig_util::VoidToVoid* closure) {
// return $self->MakeClosureDemon([closure]() { return closure->Run(); });
//}
} // extend Solver
%ignore DisjunctiveConstraint::SetTransitionTime(Solver::IndexEvaluator2 transit_evaluator);
%extend DisjunctiveConstraint {
void SetTransitionTime(swig_util::LongLongToLong* transit_evaluator) {
$self->SetTransitionTime([transit_evaluator](int64 i, int64 j) { return transit_evaluator->Run(i, j); });
}
} // extend DisjunctiveConstraint
%ignore Pack::AddWeightedSumLessOrEqualConstantDimension(
Solver::IndexEvaluator1 weights, const std::vector<int64>& bounds);
%ignore Pack::AddWeightedSumLessOrEqualConstantDimension(
Solver::IndexEvaluator2 weights, const std::vector<int64>& bounds);
%ignore Pack::AddWeightedSumEqualVarDimension(Solver::IndexEvaluator2 weights,
const std::vector<IntVar*>& loads);
%extend Pack {
void AddWeightedSumLessOrEqualConstantDimension(
swig_util::LongToLong* weights, const std::vector<int64>& bounds) {
operations_research::Solver::IndexEvaluator1 eval = [weights](int64 i) {
return weights->Run(i);
};
return $self->AddWeightedSumLessOrEqualConstantDimension(eval, bounds);
}
void AddWeightedSumLessOrEqualConstantDimension(
swig_util::LongLongToLong* weights, const std::vector<int64>& bounds) {
operations_research::Solver::IndexEvaluator2 eval =
[weights](int64 i, int64 j) { return weights->Run(i, j); };
return $self->AddWeightedSumLessOrEqualConstantDimension(eval, bounds);
}
void AddWeightedSumEqualVarDimension(
swig_util::LongLongToLong* weights, const std::vector<IntVar*>& loads) {
return $self->AddWeightedSumEqualVarDimension([weights](int64 i, int64 j) { return weights->Run(i, j); }, loads);
}
} // extend Pack
// No custom wrapping for this method, we simply ignore it.
%ignore SearchLog::SearchLog(
Solver* const s, OptimizeVar* const obj, IntVar* const var,
@@ -844,19 +685,32 @@ void AddWeightedSumEqualVarDimension(
}
}
%extend IntVarLocalSearchFilter {
int Index(IntVar* const var) {
int64 index = -1;
$self->FindIndex(var, &index);
return index;
}
}
class LocalSearchPhaseParameters {
public:
LocalSearchPhaseParameters();
~LocalSearchPhaseParameters();
};
// Pack
// Keep reference to delegate to avoid GC to collect them early
%typemap(cscode) Pack %{
// Store list of delegates to avoid the GC to reclaim them.
private List<IndexEvaluator1> indexEvaluator1Callbacks;
private List<IndexEvaluator2> indexEvaluator2Callbacks;
// Ensure that the GC does not collect any IndexEvaluator1Callback set from C#
// as the underlying C++ class will only store a pointer to it (i.e. no ownership).
private IndexEvaluator1 StoreIndexEvaluator1(IndexEvaluator1 c) {
if (indexEvaluator1Callbacks == null) indexEvaluator1Callbacks = new List<IndexEvaluator1>();
indexEvaluator1Callbacks.Add(c);
return c;
}
private IndexEvaluator2 StoreIndexEvaluator2(IndexEvaluator2 c) {
if (indexEvaluator2Callbacks == null) indexEvaluator2Callbacks = new List<IndexEvaluator2>();
indexEvaluator2Callbacks.Add(c);
return c;
}
%}
} // namespace operations_research
// Protobuf support

View File

@@ -15,7 +15,6 @@
%include "ortools/constraint_solver/csharp/constraint_solver.i"
%include "ortools/constraint_solver/csharp/routing_types.i"
%include "ortools/constraint_solver/csharp/routing_index_manager.i"
%include "ortools/util/csharp/functions.i"
// We need to forward-declare the proto here, so that PROTO_INPUT involving it
// works correctly. The order matters very much: this declaration needs to be
@@ -51,22 +50,7 @@ class RoutingSearchParameters;
%ignore operations_research::RoutingModel::MakeStateDependentTransit;
%ignore operations_research::RoutingModel::AddDimensionDependentDimensionWithVehicleCapacity;
%ignore operations_research::RoutingModel::RegisterTransitCallback(
operations_research::TransitCallback2);
%ignore operations_research::RoutingModel::RegisterUnaryTransitCallback(
operations_research::TransitCallback1);
%extend operations_research::RoutingModel {
int RegisterTransitCallback(swig_util::LongLongToLong* callback) {
return $self->RegisterTransitCallback([callback](int64 i, int64 j) {
return callback->Run(i, j);
});
}
int RegisterUnaryTransitCallback(swig_util::LongToLong* callback) {
return $self->RegisterUnaryTransitCallback([callback](int64 i) {
return callback->Run(i);
});
}
void AddVectorDimension(const std::vector<int64>& values,
int64 capacity,
bool fix_start_cumul_to_zero,
@@ -75,19 +59,72 @@ class RoutingSearchParameters;
self->AddVectorDimension(values.data(), capacity,
fix_start_cumul_to_zero, name);
}
int RegisterTransitCallback(operations_research::TransitCallback c) {
return $self->RegisterTransitCallback([c](int64 i, int64 j) {
return (*c)(i, j);
});
}
int RegisterUnaryTransitCallback(operations_research::UnaryTransitCallback c) {
return $self->RegisterUnaryTransitCallback([c](int64 i) {
return (*c)(i);
});
}
}
// RoutingModel
namespace operations_research {
// Define the delegate for Transit callback types.
// This replace the RoutingTransitCallback[1-2] in the C# proxy class
%typemap(csimports) RoutingModel %{
using System.Collections.Generic; // List<>
public delegate long UnaryTransitCallback(long fromIndex);
public delegate long TransitCallback(long fromIndex, long toIndex);
%}
// Keep reference to delegate to avoid GC to collect them early
%typemap(cscode) RoutingModel %{
// Store list of delegate to avoid the GC to reclaim them.
private List<UnaryTransitCallback> unaryTransitCallbacks;
private List<TransitCallback> transitCallbacks;
private IndexEvaluator2 indexEvaluator2Callback;
// Ensure that the GC does not collect any TransitCallback set from C#
// as the underlying C++ class stores a shallow copy
private UnaryTransitCallback StoreUnaryTransitCallback(UnaryTransitCallback c) {
if (unaryTransitCallbacks == null) unaryTransitCallbacks = new List<UnaryTransitCallback>();
unaryTransitCallbacks.Add(c);
return c;
}
private TransitCallback StoreTransitCallback(TransitCallback c) {
if (transitCallbacks == null) transitCallbacks = new List<TransitCallback>();
transitCallbacks.Add(c);
return c;
}
// only use in RoutingModel::SetFirstSolutionEvaluator()
private IndexEvaluator2 StoreIndexEvaluator2(IndexEvaluator2 c) {
indexEvaluator2Callback = c;
return c;
}
%}
// Types in Proxy class (foo.cs) e.g.:
// Foo::f(cstype $csinput, ...) {Foo_f_SWIG(csin, ...);}
%typemap(cstype, out="IntPtr") RoutingTransitCallback1 "UnaryTransitCallback"
%typemap(csin) RoutingTransitCallback1 "StoreUnaryTransitCallback($csinput)"
%typemap(cstype, out="IntPtr") RoutingTransitCallback2 "TransitCallback"
%typemap(csin) RoutingTransitCallback2 "StoreTransitCallback($csinput)"
// Type in the prototype of PINVOKE function.
%typemap(imtype, out="IntPtr") RoutingTransitCallback1 "UnaryTransitCallback"
%typemap(imtype, out="IntPtr") RoutingTransitCallback2 "TransitCallback"
// Type use in module_csharp_wrap.h function declaration.
// since SWIG generate code as: `ctype argX` we can't use a C function pointer type.
%typemap(ctype) RoutingTransitCallback1 "void*" // "int64 (*)(int64)"
%typemap(ctype) RoutingTransitCallback2 "void*" // "int64 (*)(int64, int64)"
// Convert in module_csharp_wrap.cc input argument (delegate marshaled in C function pointer) to original std::function<...>
%typemap(in) RoutingTransitCallback1 %{
$1 = [$input](int64 fromIndex) -> int64 {
return (*(int64 (*)(int64))$input)(fromIndex);
};
%}
%typemap(in) RoutingTransitCallback2 %{
$1 = [$input](int64 fromIndex, int64 toIndex) -> int64 {
return (*(int64 (*)(int64, int64))$input)(fromIndex, toIndex);};
%}
} // namespace operations_research
// Add PickupAndDeliveryPolicy enum value to RoutingModel (like RoutingModel::Status)
// For C++11 strongly typed enum SWIG support see https://github.com/swig/swig/issues/316
%extend operations_research::RoutingModel {

View File

@@ -77,21 +77,3 @@ DEFINE_INDEX_TYPE(operations_research::RoutingDisjunctionIndex);
DEFINE_INDEX_TYPE(operations_research::RoutingVehicleClassIndex);
%include "ortools/constraint_solver/routing_types.h"
%{
namespace operations_research {
typedef int64 (*TransitCallback)(int64, int64);
typedef int64 (*UnaryTransitCallback)(int64);
} // namespace operations_research
%}
%define %DEFINE_CALLBACK(TYPE, CSTYPE)
%typemap(ctype) TYPE, TYPE& "void*"
%typemap(in) TYPE %{ $1 = (TYPE)$input; %}
%typemap(in) TYPE& %{ $1 = (TYPE*)&$input; %}
%typemap(imtype, out="IntPtr") TYPE, TYPE& "CSTYPE"
%typemap(cstype, out="IntPtr") TYPE, TYPE& "CSTYPE"
%typemap(csin) TYPE, TYPE& "$csinput"
%enddef
%DEFINE_CALLBACK(operations_research::TransitCallback, TransitCallback)
%DEFINE_CALLBACK(operations_research::UnaryTransitCallback, UnaryTransitCallback)

View File

@@ -42,15 +42,19 @@ public class SimpleRoutingProgram {
RoutingModel routing = new RoutingModel(manager);
// [END routing_model]
// Define cost of each arc.
// [START arc_cost]
// Create a distance callback.
// [START distance_callback]
int transitCallbackIndex = routing.RegisterTransitCallback(
(long fromIndex, long toIndex) => {
// Convert from routing variable Index to distance matrix NodeIndex.
var fromNode = manager.IndexToNode(fromIndex);
var toNode = manager.IndexToNode(toIndex);
return Math.Abs(toNode - fromNode); }
);
// Convert from routing variable Index to distance matrix NodeIndex.
var fromNode = manager.IndexToNode(fromIndex);
var toNode = manager.IndexToNode(toIndex);
return Math.Abs(toNode - fromNode);
});
// [END distance_callback]
// Define cost of each arc.
// [START arc_cost]
routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
// [END arc_cost]

View File

@@ -59,7 +59,7 @@ public class Tsp {
/// positions and computes the Manhattan distance between the two
/// positions of two different indices.
/// </summary>
class ManhattanDistance : LongLongToLong {
class ManhattanDistance {
public ManhattanDistance(
in DataModel data,
in RoutingIndexManager manager) {
@@ -82,7 +82,7 @@ public class Tsp {
/// <summary>
/// Returns the manhattan distance between the two nodes
/// </summary>
public override long Run(long FromIndex, long ToIndex) {
public long call(long FromIndex, long ToIndex) {
// Convert from routing variable Index to distance matrix NodeIndex.
int FromNode = indexManager_.IndexToNode(FromIndex);
int ToNode = indexManager_.IndexToNode(ToIndex);
@@ -136,12 +136,14 @@ public class Tsp {
RoutingModel routing = new RoutingModel(manager);
// [END routing_model]
// Create a distance callback.
// [START distance_callback]
var distanceCallback = new ManhattanDistance(data, manager);
int transitCallbackIndex = routing.RegisterTransitCallback(distanceCallback.call);
// [END distance_callback]
// Define cost of each arc.
// [START arc_cost]
LongLongToLong distanceEvaluator = new ManhattanDistance(data, manager);
//protect callbacks from the GC
GC.KeepAlive(distanceEvaluator);
int transitCallbackIndex = routing.RegisterTransitCallback(distanceEvaluator);
routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
// [END arc_cost]

View File

@@ -107,6 +107,7 @@ public class TspDistanceMatrix {
return data.GetDistanceMatrix()[fromNode, toNode]; }
);
routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
GC.Collect();
// [END arc_cost]
// Setting first solution heuristic.

View File

@@ -1,51 +0,0 @@
// Copyright 2010-2018 Google LLC
// 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.
// This file provides swig wrapping for some specialization of std::function
// parameters. Currently, swig does not support much of C++11 features, and
// especially not the std::function.
// C# callers will need to use a specific "type" of callbacks: they must
// specialize one of the existing generic callback classes defined in
// ../functions_swig_helpers.h (which are SWIG-wrapped to C# in a
// straightforward way). See the examples.
%include "ortools/base/base.i"
%include "std_common.i"
%include "std_string.i"
%{
#include <functional>
#include "ortools/base/integral_types.h"
#include "ortools/util/functions_swig_helpers.h"
%}
%module(directors="1") operations_research_swig_util
// --------- Include the swig helpers file to create the director classes ------
// We cannot use %ignoreall/%unignoreall as this is not compatible with nested
// swig files.
%feature("director") operations_research::swig_util::LongToLong;
%feature("director") operations_research::swig_util::LongLongToLong;
%feature("director") operations_research::swig_util::IntIntToLong;
%feature("director") operations_research::swig_util::IntToLong;
%feature("director") operations_research::swig_util::LongLongLongToLong;
%feature("director") operations_research::swig_util::LongToBoolean;
%feature("director") operations_research::swig_util::VoidToString;
%feature("director") operations_research::swig_util::VoidToBoolean;
%feature("director") operations_research::swig_util::LongLongLongToBoolean;
%feature("director") operations_research::swig_util::LongToVoid;
%include "ortools/util/functions_swig_helpers.h"

View File

@@ -15,9 +15,7 @@
#define OR_TOOLS_UTIL_FUNCTIONS_SWIG_HELPERS_H_
// This file contains class definitions for the wrapping of C++ std::functions
// in Java and C#. It is #included by java/functions.i and
// csharp/functions.i.
// in Java. It is #included by java/functions.i
#include <functional>
#include <string>