From a70ed70563ea2c2bf747de3c617528b155ed43e0 Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Mon, 6 May 2019 12:55:30 +0200 Subject: [PATCH] remove the need for IntArrayHelper.cs; support conversion from type[][] and type[,] to std::vector> in C# --- makefiles/Makefile.dotnet.mk | 2 - ortools/algorithms/csharp/IntArrayHelper.cs | 76 ----------------- ortools/algorithms/csharp/knapsack_solver.i | 6 +- .../csharp/constraint_solver.i | 4 +- .../constraint_solver/csharp/routing_types.i | 2 +- .../dotnet/Google.OrTools.FSharp/OrTools.fs | 14 +-- ...Google.OrTools.runtime.linux-x64.csproj.in | 3 - .../Google.OrTools.runtime.osx-x64.csproj.in | 3 - .../Google.OrTools.runtime.win-x64.csproj.in | 3 - ortools/sat/csharp/IntArrayHelper.cs | 32 ------- ortools/sat/csharp/sat.i | 5 +- ortools/util/csharp/NestedArrayHelper.cs | 17 ++++ ortools/util/csharp/vector.i | 85 +++++++++++++++++-- 13 files changed, 105 insertions(+), 147 deletions(-) delete mode 100644 ortools/algorithms/csharp/IntArrayHelper.cs delete mode 100644 ortools/sat/csharp/IntArrayHelper.cs diff --git a/makefiles/Makefile.dotnet.mk b/makefiles/Makefile.dotnet.mk index ac3d85b7a3..decc882f1a 100644 --- a/makefiles/Makefile.dotnet.mk +++ b/makefiles/Makefile.dotnet.mk @@ -310,7 +310,6 @@ $(SRC_DIR)/ortools/dotnet/$(OR_TOOLS_NATIVE_ASSEMBLY_NAME)/$(OR_TOOLS_NATIVE_ASS $(DOTNET_ORTOOLS_NATIVE_NUPKG): \ $(LIB_DIR)/$(OR_TOOLS_NATIVE_ASSEMBLY_NAME).$(SWIG_DOTNET_LIB_SUFFIX) \ $(SRC_DIR)/ortools/dotnet/$(OR_TOOLS_NATIVE_ASSEMBLY_NAME)/$(OR_TOOLS_NATIVE_ASSEMBLY_NAME).csproj \ - $(SRC_DIR)/ortools/algorithms/csharp/IntArrayHelper.cs \ $(SRC_DIR)/ortools/constraint_solver/csharp/IntVarArrayHelper.cs \ $(SRC_DIR)/ortools/constraint_solver/csharp/IntervalVarArrayHelper.cs \ $(SRC_DIR)/ortools/constraint_solver/csharp/IntArrayHelper.cs \ @@ -325,7 +324,6 @@ $(DOTNET_ORTOOLS_NATIVE_NUPKG): \ $(SRC_DIR)/ortools/sat/csharp/Constraints.cs \ $(SRC_DIR)/ortools/sat/csharp/CpModel.cs \ $(SRC_DIR)/ortools/sat/csharp/CpSolver.cs \ - $(SRC_DIR)/ortools/sat/csharp/IntArrayHelper.cs \ $(SRC_DIR)/ortools/sat/csharp/IntegerExpressions.cs \ $(SRC_DIR)/ortools/sat/csharp/IntervalVariables.cs \ $(SRC_DIR)/ortools/sat/csharp/SearchHelpers.cs \ diff --git a/ortools/algorithms/csharp/IntArrayHelper.cs b/ortools/algorithms/csharp/IntArrayHelper.cs deleted file mode 100644 index ca514e5106..0000000000 --- a/ortools/algorithms/csharp/IntArrayHelper.cs +++ /dev/null @@ -1,76 +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. - -namespace Google.OrTools.Algorithms { -using System; -using System.Collections.Generic; - -public partial class KInt64Vector: IDisposable, System.Collections.IEnumerable -#if !SWIG_DOTNET_1 - , System.Collections.Generic.IList -#endif -{ - // cast from C# long array - public static implicit operator KInt64Vector(long[] inVal) { - var outVal= new KInt64Vector(); - foreach (long element in inVal) { - outVal.Add(element); - } - return outVal; - } - - // cast to C# long array - public static implicit operator long[](KInt64Vector inVal) { - var outVal= new long[inVal.Count]; - inVal.CopyTo(outVal); - return outVal; - } -} - -public partial class KInt64VectorVector : IDisposable, System.Collections.IEnumerable -#if !SWIG_DOTNET_1 - , System.Collections.Generic.IEnumerable -#endif - { - // cast from C# long matrix - public static implicit operator KInt64VectorVector(long[,] inVal) { - int x_size = inVal.GetLength(0); - int y_size = inVal.GetLength(1); - KInt64VectorVector outVal = new KInt64VectorVector(); - for (int i = 0; i < x_size; ++i) - { - outVal.Add(new KInt64Vector()); - for (int j = 0; j < y_size; ++j) - { - outVal[i].Add(inVal[i, j]); - } - } - return outVal; - } - - // cast to C# long matrix - public static implicit operator long[,](KInt64VectorVector inVal) { - int x_size = inVal.Count; - int y_size = inVal.Count == 0 ? 0 : inVal[0].Count; - var outVal= new long[x_size, y_size]; - for (int i = 0; i < x_size; ++i) - { - for (int j = 0; j < y_size; ++j) - { - outVal[i, j] = inVal[i][j]; - } - } - return outVal; - } -} -} // namespace Google.OrTools.Algorithms diff --git a/ortools/algorithms/csharp/knapsack_solver.i b/ortools/algorithms/csharp/knapsack_solver.i index 4e6aed6750..b52c97bd34 100644 --- a/ortools/algorithms/csharp/knapsack_solver.i +++ b/ortools/algorithms/csharp/knapsack_solver.i @@ -18,9 +18,7 @@ %include "std_vector.i" %include "ortools/base/base.i" - -/* allow partial c# classes */ -%typemap(csclassmodifiers) SWIGTYPE "public partial class" +%include "ortools/util/csharp/vector.i" // Include the file we want to wrap a first time. %{ @@ -35,6 +33,8 @@ typedef uint64_t uint64; // the template instantiation of std::vector<> differently. %template(KInt64Vector) std::vector; %template(KInt64VectorVector) std::vector >; +VECTOR_AS_CSHARP_ARRAY(int64, int64, long, KInt64Vector); +REGULAR_MATRIX_AS_CSHARP_ARRAY(int64, int64, long, KInt64VectorVector); %rename (UseReduction) operations_research::KnapsackSolver::use_reduction; %rename (SetUseReduction) operations_research::KnapsackSolver::set_use_reduction; diff --git a/ortools/constraint_solver/csharp/constraint_solver.i b/ortools/constraint_solver/csharp/constraint_solver.i index 75b42abdff..53d9c1295b 100644 --- a/ortools/constraint_solver/csharp/constraint_solver.i +++ b/ortools/constraint_solver/csharp/constraint_solver.i @@ -139,14 +139,14 @@ PROTECT_FROM_FAILURE(Solver::Fail(), arg1); // we redefine typemap of vec in VECTOR_AS_CSHARP_ARRAY %template(CpIntVectorVector) std::vector >; VECTOR_AS_CSHARP_ARRAY(int, int, int, CpIntVector); -MATRIX_AS_CSHARP_ARRAY(int, int, int, CpIntVectorVector); +JAGGED_MATRIX_AS_CSHARP_ARRAY(int, int, int, CpIntVectorVector); %template(CpInt64Vector) std::vector; // IMPORTANT(corentinl) this template for vec> must be call BEFORE // we redefine typemap of vec in VECTOR_AS_CSHARP_ARRAY %template(CpInt64VectorVector) std::vector >; VECTOR_AS_CSHARP_ARRAY(int64, int64, long, CpInt64Vector); -MATRIX_AS_CSHARP_ARRAY(int64, int64, long, CpInt64VectorVector); +JAGGED_MATRIX_AS_CSHARP_ARRAY(int64, int64, long, CpInt64VectorVector); // Types in Proxy class: // Solver.cs: diff --git a/ortools/constraint_solver/csharp/routing_types.i b/ortools/constraint_solver/csharp/routing_types.i index 4d30880485..d54bdd11be 100644 --- a/ortools/constraint_solver/csharp/routing_types.i +++ b/ortools/constraint_solver/csharp/routing_types.i @@ -56,7 +56,7 @@ // Convert std::vector to/from int arrays. VECTOR_AS_CSHARP_ARRAY(IndexT, int, int, CpIntVector); // Convert std::vector> to/from two-dimensional int arrays. -MATRIX_AS_CSHARP_ARRAY(IndexT, int, int, CpIntVectorVector); +JAGGED_MATRIX_AS_CSHARP_ARRAY(IndexT, int, int, CpIntVectorVector); %enddef // DEFINE_INDEX_TYPE diff --git a/ortools/dotnet/Google.OrTools.FSharp/OrTools.fs b/ortools/dotnet/Google.OrTools.FSharp/OrTools.fs index d8f7e34739..174d251e4a 100644 --- a/ortools/dotnet/Google.OrTools.FSharp/OrTools.fs +++ b/ortools/dotnet/Google.OrTools.FSharp/OrTools.fs @@ -132,7 +132,7 @@ module FSharp = | MultidimensionBranchAndBound -> 5 | MultidimensionSCIP -> 6 - let knapsackSolve (name: string) (solverAlgorithm:KnapsackSolverAlgorithm) (profits:int64 list) (weights:int64 list) (capacities:int64 list) = + let knapsackSolve (name: string) (solverAlgorithm:KnapsackSolverAlgorithm) (profits:int64 list) (weights:int64 [,]) (capacities:int64 list) = // extract the specific algorithm so its Id can be used to create solver let algorithm = match solverAlgorithm with @@ -154,17 +154,11 @@ module FSharp = let solver = new KnapsackSolver(enum(algorithm), name) // transform lists to compatible structures for C++ Solver - let profits = new KInt64Vector( List.toArray profits ) + let profit_array = List.toArray profits - let weights = - let tempVector = new KInt64VectorVector(1) - let tempWeights = new KInt64Vector(List.toArray weights) - tempVector.Add(tempWeights) - tempVector + let capacity_array = List.toArray capacities - let capacities = new KInt64Vector (List.toArray capacities) - - solver.Init(profits, weights, capacities) + solver.Init(profit_array, weights, capacity_array) solver type SolverOpts = { diff --git a/ortools/dotnet/Google.OrTools.runtime.linux-x64/Google.OrTools.runtime.linux-x64.csproj.in b/ortools/dotnet/Google.OrTools.runtime.linux-x64/Google.OrTools.runtime.linux-x64.csproj.in index 5e3b33e70c..48bfceb18b 100644 --- a/ortools/dotnet/Google.OrTools.runtime.linux-x64/Google.OrTools.runtime.linux-x64.csproj.in +++ b/ortools/dotnet/Google.OrTools.runtime.linux-x64/Google.OrTools.runtime.linux-x64.csproj.in @@ -41,9 +41,6 @@ algorithms/%(Filename)%(Extension) - - algorithms/%(Filename)%(Extension) - graph/%(Filename)%(Extension) diff --git a/ortools/dotnet/Google.OrTools.runtime.osx-x64/Google.OrTools.runtime.osx-x64.csproj.in b/ortools/dotnet/Google.OrTools.runtime.osx-x64/Google.OrTools.runtime.osx-x64.csproj.in index e43cca8c73..ed3141465e 100644 --- a/ortools/dotnet/Google.OrTools.runtime.osx-x64/Google.OrTools.runtime.osx-x64.csproj.in +++ b/ortools/dotnet/Google.OrTools.runtime.osx-x64/Google.OrTools.runtime.osx-x64.csproj.in @@ -41,9 +41,6 @@ algorithms/%(Filename)%(Extension) - - algorithms/%(Filename)%(Extension) - graph/%(Filename)%(Extension) diff --git a/ortools/dotnet/Google.OrTools.runtime.win-x64/Google.OrTools.runtime.win-x64.csproj.in b/ortools/dotnet/Google.OrTools.runtime.win-x64/Google.OrTools.runtime.win-x64.csproj.in index c42d7f2826..d9afaf8f35 100644 --- a/ortools/dotnet/Google.OrTools.runtime.win-x64/Google.OrTools.runtime.win-x64.csproj.in +++ b/ortools/dotnet/Google.OrTools.runtime.win-x64/Google.OrTools.runtime.win-x64.csproj.in @@ -41,9 +41,6 @@ algorithms/%(Filename)%(Extension) - - algorithms/%(Filename)%(Extension) - graph/%(Filename)%(Extension) diff --git a/ortools/sat/csharp/IntArrayHelper.cs b/ortools/sat/csharp/IntArrayHelper.cs deleted file mode 100644 index 5f4b7ec65a..0000000000 --- a/ortools/sat/csharp/IntArrayHelper.cs +++ /dev/null @@ -1,32 +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. - -namespace Google.OrTools.Sat { -using System; -using System.Collections.Generic; - -// int[] and long[] helper class. -public partial class SatInt64Vector: IDisposable, System.Collections.IEnumerable -#if !SWIG_DOTNET_1 - , System.Collections.Generic.IList -#endif -{ - // cast to C# long array - public static implicit operator long[](SatInt64Vector inVal) { - var outVal= new long[inVal.Count]; - inVal.CopyTo(outVal); - return outVal; - } -} - -} // namespace Google.OrTools.Sat diff --git a/ortools/sat/csharp/sat.i b/ortools/sat/csharp/sat.i index 87d57b5ccc..b2c481825d 100644 --- a/ortools/sat/csharp/sat.i +++ b/ortools/sat/csharp/sat.i @@ -36,9 +36,6 @@ typedef uint64_t uint64; %module(directors="1") operations_research_sat -/* allow partial c# classes */ -%typemap(csclassmodifiers) SWIGTYPE "public partial class" - PROTO_INPUT(operations_research::sat::CpModelProto, Google.OrTools.Sat.CpModelProto, model_proto); @@ -57,7 +54,7 @@ PROTO2_RETURN(operations_research::sat::CpSolverResponse, %template(SatInt64Vector) std::vector; %template(SatInt64VectorVector) std::vector >; VECTOR_AS_CSHARP_ARRAY(int64, int64, long, SatInt64Vector); -MATRIX_AS_CSHARP_ARRAY(int64, int64, long, SatInt64VectorVector); +JAGGED_MATRIX_AS_CSHARP_ARRAY(int64, int64, long, SatInt64VectorVector); %ignoreall diff --git a/ortools/util/csharp/NestedArrayHelper.cs b/ortools/util/csharp/NestedArrayHelper.cs index 69b30f4d6c..c7c874d360 100644 --- a/ortools/util/csharp/NestedArrayHelper.cs +++ b/ortools/util/csharp/NestedArrayHelper.cs @@ -35,6 +35,23 @@ public static class NestedArrayHelper return flat; } + + public static T[] GetFlatArrayFromMatrix(T[,] arr) + { + int flatLength = arr.GetLength(0) * arr.GetLength(1); + + int idx = 0; + T[] flat = new T[flatLength]; + + for (int i = 0; i < arr.GetLength(0); i++) + { + for (int j = 0; j < arr.GetLength(1); j++) + flat[idx++] = arr[i, j]; + } + + return flat; + } + public static int[] GetArraySecondSize(T[][]arr) { var result = new int[arr.GetLength(0)]; diff --git a/ortools/util/csharp/vector.i b/ortools/util/csharp/vector.i index 09a211b7a5..6a57d97047 100644 --- a/ortools/util/csharp/vector.i +++ b/ortools/util/csharp/vector.i @@ -50,11 +50,14 @@ %} %typemap(csout, excode=SWIGEXCODE) const std::vector& { global::System.IntPtr cPtr = $imcall;$excode - ARRAYTYPE ret = null; + ARRAYTYPE tmpVector = null; if (cPtr != global::System.IntPtr.Zero) { - ret = new ARRAYTYPE(cPtr, true); + tmpVector = new ARRAYTYPE(cPtr, true); + CSHARPTYPE[] outArray = new CSHARPTYPE[tmpVector.Count]; + tmpVector.CopyTo(outArray); + return outArray; } - return ret; + return null; } // Now, we do it for std::vector<>. %typemap(cstype) std::vector %{ CSHARPTYPE[] %} @@ -74,18 +77,21 @@ %} %typemap(csout, excode=SWIGEXCODE) std::vector { global::System.IntPtr cPtr = $imcall;$excode - ARRAYTYPE ret = null; + ARRAYTYPE tmpVector = null; if (cPtr != global::System.IntPtr.Zero) { - ret = new ARRAYTYPE(cPtr, true); + tmpVector = new ARRAYTYPE(cPtr, true); + CSHARPTYPE[] outArray = new CSHARPTYPE[tmpVector.Count]; + tmpVector.CopyTo(outArray); + return outArray; } - return ret; + return null; } %enddef // VECTOR_AS_CSHARP_ARRAY // Typemaps to represent arguments of types "const std::vector>&" or // "std::vector>*" as CSHARPTYPE[][]. // note: TYPE must be a primitive data type (PDT). -%define MATRIX_AS_CSHARP_ARRAY(TYPE, CTYPE, CSHARPTYPE, ARRAYTYPE) +%define JAGGED_MATRIX_AS_CSHARP_ARRAY(TYPE, CTYPE, CSHARPTYPE, ARRAYTYPE) // This part is for const std::vector>&. %typemap(cstype) const std::vector >& %{ CSHARPTYPE[][] %} %typemap(csin) const std::vector >& %{ @@ -145,5 +151,68 @@ } $1 = &result; %} -%enddef // MATRIX_AS_CSHARP_ARRAY +%enddef // JAGGED_MATRIX_AS_CSHARP_ARRAY +// "std::vector>*" as CSHARPTYPE[,]. +// note: TYPE must be a primitive data type (PDT). +%define REGULAR_MATRIX_AS_CSHARP_ARRAY(TYPE, CTYPE, CSHARPTYPE, ARRAYTYPE) +// This part is for const std::vector>&. +%typemap(cstype) const std::vector >& %{ CSHARPTYPE[,] %} +%typemap(csin) const std::vector >& %{ + $csinput.GetLength(0), + $csinput.GetLength(1), + NestedArrayHelper.GetFlatArrayFromMatrix($csinput) +%} +%typemap(imtype, out="global::System.IntPtr") const std::vector >& %{ + int len$argnum##_1, int len$argnum##_2, CSHARPTYPE[] +%} +%typemap(ctype, out="void*") const std::vector >& %{ + int len$argnum##_1, int len$argnum##_2, CTYPE* +%} +%typemap(in) const std::vector >& (std::vector > result) %{ + result.clear(); + result.resize(len$argnum##_1); + + TYPE* inner_array = reinterpret_cast($input); + int actualIndex = 0; + for (int index1 = 0; index1 < len$argnum##_1; ++index1) { + result[index1].reserve(len$argnum##_2); + for (int index2 = 0; index2 < len$argnum##_2; ++index2) { + const TYPE value = inner_array[actualIndex]; + result[index1].emplace_back(value); + actualIndex++; + } + } + + $1 = &result; +%} +// Now, we do it for std::vector>*. +%typemap(cstype) std::vector >* %{ CSHARPTYPE[,] %} +%typemap(csin) std::vector >* %{ + $csinput.GetLength(0), + $csinput.GetLength(1), + NestedArrayHelper.GetFlatArrayFromMatrix($csinput) +%} +%typemap(imtype, out="global::System.IntPtr") std::vector >* %{ + int len$argnum##_1, int len$argnum##_2, CSHARPTYPE[] +%} +%typemap(ctype, out="void*") std::vector >* %{ + int len$argnum##_1, int len$argnum##_2, CTYPE* +%} +%typemap(in) std::vector >* (std::vector > result) %{ + result.clear(); + result.resize(len$argnum##_1); + + TYPE* flat_array = reinterpret_cast($input); + int actualIndex = 0; + for (int index1 = 0; index1 < len$argnum##_1; ++index1) { + result[index1].reserve(len$argnum##_2); + for (int index2 = 0; index2 < len$argnum##_2; ++index2) { + const TYPE value = flat_array[actualIndex]; + result[index1].emplace_back(value); + actualIndex++; + } + } + $1 = &result; +%} +%enddef // REGULAR_MATRIX_AS_CSHARP_ARRAY