diff --git a/makefiles/Makefile.dotnet.mk b/makefiles/Makefile.dotnet.mk index 1b57d1c1db..070b4a3ed6 100644 --- a/makefiles/Makefile.dotnet.mk +++ b/makefiles/Makefile.dotnet.mk @@ -13,6 +13,8 @@ endif ORTOOLS_DLL_NAME=OrTools ORTOOLS_NUSPEC_FILE=$(ORTOOLS_DLL_NAME).nuspec +ORTOOLS_DLL_TEST=$(ORTOOLS_DLL_NAME).Tests + CLR_PROTOBUF_DLL_NAME?=Google.Protobuf CLR_ORTOOLS_DLL_NAME?=Google.$(ORTOOLS_DLL_NAME) BASE_CLR_ORTOOLS_DLL_NAME:= $(CLR_ORTOOLS_DLL_NAME) @@ -29,6 +31,15 @@ DOTNET_EXECUTABLE := $(shell which dotnet) endif endif +DOTNET_LIB_DIR := +ifeq ($(PLATFORM),MACOSX) +DOTNET_LIB_DIR = env DYLD_FALLBACK_LIBRARY_PATH=$(LIB_DIR) +endif +ifeq ($(PLATFORM),LINUX) +DOTNET_LIB_DIR = env LD_LIBRARY_PATH=$(LIB_DIR) +endif + +CLEAN_FILES=$(CLR_PROTOBUF_DLL_NAME).* $(CLR_ORTOOLS_DLL_NAME).* .PHONY: csharp_dotnet # Build C# OR-Tools. csharp_dotnet: \ @@ -164,15 +175,23 @@ $(BIN_DIR)/$(CLR_ORTOOLS_DLL_NAME)$(DLL): \ $(GEN_DIR)/com/google/ortools/sat/CpModel.g.cs \ $(OR_TOOLS_LIBS) $(DYNAMIC_LD) $(LDOUT)$(LIB_DIR)$S$(LIB_PREFIX)$(CLR_ORTOOLS_DLL_NAME).$(SWIG_LIB_SUFFIX) $(OBJ_DIR)/swig/linear_solver_csharp_wrap.$O $(OBJ_DIR)/swig/sat_csharp_wrap.$O $(OBJ_DIR)/swig/constraint_solver_csharp_wrap.$O $(OBJ_DIR)/swig/knapsack_solver_csharp_wrap.$O $(OBJ_DIR)/swig/graph_csharp_wrap.$O $(OR_TOOLS_LNK) $(OR_TOOLS_LD_FLAGS) - $(SED) -i -e "s/0.0.0.0/$(OR_TOOLS_VERSION)/" ortools$Sdotnet$S$(ORTOOLS_DLL_NAME)$S$(ORTOOLS_DLL_NAME).csproj + # $(SED) -i -e "s/0.0.0.0/$(OR_TOOLS_VERSION)/" ortools$Sdotnet$S$(ORTOOLS_DLL_NAME)$S$(ORTOOLS_DLL_NAME).csproj "$(DOTNET_EXECUTABLE)" restore ortools$Sdotnet$S$(ORTOOLS_DLL_NAME)$S$(ORTOOLS_DLL_NAME).csproj "$(DOTNET_EXECUTABLE)" build -c Debug ortools$Sdotnet$S$(ORTOOLS_DLL_NAME)$S$(ORTOOLS_DLL_NAME).csproj "$(DOTNET_EXECUTABLE)" build -c Release ortools$Sdotnet$S$(ORTOOLS_DLL_NAME)$S$(ORTOOLS_DLL_NAME).csproj + $(COPY) ortools$Sdotnet$S$(ORTOOLS_DLL_NAME)$Sbin$SDebug$Snetstandard2.0$S*.* $(BIN_DIR) - -.PHONY: clean_dotnet # Build Nuget Package for distribution. +.PHONY: clean_dotnet # Clean files clean_dotnet: - $(warning Not Implemented) + $(foreach var,$(CLEAN_FILES), $(DEL) bin$S$(var);) + +.PHONY: test_dotnet # Test dotnet version of OR-Tools +test_dotnet: + "$(DOTNET_EXECUTABLE)" restore --packages "ortools$Sdotnet$Spackages" "ortools$Sdotnet$S$(ORTOOLS_DLL_TEST)$S$(ORTOOLS_DLL_TEST).csproj" + "$(DOTNET_EXECUTABLE)" clean "ortools$Sdotnet$S$(ORTOOLS_DLL_TEST)$S$(ORTOOLS_DLL_TEST).csproj" + "$(DOTNET_EXECUTABLE)" build "ortools$Sdotnet$S$(ORTOOLS_DLL_TEST)$S$(ORTOOLS_DLL_TEST).csproj" + $(DOTNET_LIB_DIR) "$(DOTNET_EXECUTABLE)" "ortools$Sdotnet$Spackages$Sxunit.runner.console$S2.3.1$Stools$Snetcoreapp2.0$Sxunit.console.dll" "ortools$Sdotnet$S$(ORTOOLS_DLL_TEST)$Sbin$SDebug$Snetcoreapp2.0$SGoogle.$(ORTOOLS_DLL_TEST).dll" -verbose + .PHONY: pkg_dotnet # Build Nuget Package for distribution. pkg_dotnet: diff --git a/ortools/dotnet/Google.sln b/ortools/dotnet/Google.sln index f57ebc8f57..72d3963ba0 100644 --- a/ortools/dotnet/Google.sln +++ b/ortools/dotnet/Google.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 15.0.26124.0 MinimumVisualStudioVersion = 15.0.26124.0 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrTools", "OrTools\OrTools.csproj", "{AFA3F878-FB56-4314-B31E-3DA5583B548B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrTools.Tests", "OrTools.Tests\OrTools.Tests.csproj", "{CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -30,5 +32,17 @@ Global {AFA3F878-FB56-4314-B31E-3DA5583B548B}.Release|x64.Build.0 = Release|x64 {AFA3F878-FB56-4314-B31E-3DA5583B548B}.Release|x86.ActiveCfg = Release|x86 {AFA3F878-FB56-4314-B31E-3DA5583B548B}.Release|x86.Build.0 = Release|x86 + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Debug|x64.ActiveCfg = Debug|x64 + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Debug|x64.Build.0 = Debug|x64 + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Debug|x86.ActiveCfg = Debug|x86 + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Debug|x86.Build.0 = Debug|x86 + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Release|Any CPU.Build.0 = Release|Any CPU + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Release|x64.ActiveCfg = Release|x64 + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Release|x64.Build.0 = Release|x64 + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Release|x86.ActiveCfg = Release|x86 + {CB6482EF-BFD1-4512-A24C-3AF3C8C70D3D}.Release|x86.Build.0 = Release|x86 EndGlobalSection EndGlobal diff --git a/ortools/dotnet/OrTools.Tests/LinearProgramming.cs b/ortools/dotnet/OrTools.Tests/LinearProgramming.cs new file mode 100644 index 0000000000..716c49fe95 --- /dev/null +++ b/ortools/dotnet/OrTools.Tests/LinearProgramming.cs @@ -0,0 +1,199 @@ +using System; +using Xunit; + +using Google.OrTools.LinearSolver; + +namespace Google.OrTools.Tests +{ + public class LinearProgramming + { + [Fact] + public void TestVarOperator() + { + Solver solver = new Solver("TestVarOperator", Solver.CLP_LINEAR_PROGRAMMING); + Variable x = solver.MakeNumVar(0.0, 100.0, "x"); + Constraint ct1 = solver.Add(x >= 1); + Constraint ct2 = solver.Add(x <= 1); + Constraint ct3 = solver.Add(x == 1); + Constraint ct4 = solver.Add(1 >= x); + Constraint ct5 = solver.Add(1 <= x); + Constraint ct6 = solver.Add(1 == x); + + Assert.Equal(1.0, ct1.GetCoefficient(x)); + Assert.Equal(1.0, ct2.GetCoefficient(x)); + Assert.Equal(1.0, ct3.GetCoefficient(x)); + Assert.Equal(1.0, ct4.GetCoefficient(x)); + Assert.Equal(1.0, ct5.GetCoefficient(x)); + Assert.Equal(1.0, ct6.GetCoefficient(x)); + Assert.Equal(1.0, ct1.Lb()); + Assert.Equal(ct1.Ub(), double.PositiveInfinity); + Assert.Equal(ct2.Lb(), double.NegativeInfinity); + Assert.Equal(1.0, ct2.Ub()); + Assert.Equal(1.0, ct3.Lb()); + Assert.Equal(1.0, ct3.Ub()); + Assert.Equal(ct4.Lb(), double.NegativeInfinity); + Assert.Equal(1.0, ct4.Ub()); + Assert.Equal(1.0, ct5.Lb()); + Assert.Equal(ct5.Ub(), double.PositiveInfinity); + Assert.Equal(1.0, ct6.Lb()); + Assert.Equal(1.0, ct6.Ub()); + } + + [Fact] + public void TestVarAddition() + { + Solver solver = new Solver("TestVarAddition", Solver.CLP_LINEAR_PROGRAMMING); + Variable x = solver.MakeNumVar(0.0, 100.0, "x"); + Variable y = solver.MakeNumVar(0.0, 100.0, "y"); + + Constraint ct1 = solver.Add(x + y == 1); + Assert.Equal(1.0, ct1.GetCoefficient(x)); + Assert.Equal(1.0, ct1.GetCoefficient(y)); + + Constraint ct2 = solver.Add(x + x == 1); + Assert.Equal(2.0, ct2.GetCoefficient(x)); + + Constraint ct3 = solver.Add(x + (y + x) == 1); + Assert.Equal(2.0, ct3.GetCoefficient(x)); + Assert.Equal(1.0, ct3.GetCoefficient(y)); + + Constraint ct4 = solver.Add(x + (y + x + 3) == 1); + Assert.Equal(2.0, ct4.GetCoefficient(x)); + Assert.Equal(1.0, ct4.GetCoefficient(y)); + Assert.Equal(-2.0, ct4.Lb()); + Assert.Equal(-2.0, ct4.Ub()); + } + + [Fact] + public void TestVarMultiplication() + { + + Solver solver = new Solver("TestVarMultiplication", Solver.CLP_LINEAR_PROGRAMMING); + Variable x = solver.MakeNumVar(0.0, 100.0, "x"); + Variable y = solver.MakeNumVar(0.0, 100.0, "y"); + + Constraint ct1 = solver.Add(3 * x == 1); + Assert.Equal(3.0, ct1.GetCoefficient(x)); + + Constraint ct2 = solver.Add(x * 3 == 1); + Assert.Equal(3.0, ct2.GetCoefficient(x)); + + Constraint ct3 = solver.Add(x + (2 * y + 3 * x) == 1); + Assert.Equal(4.0, ct3.GetCoefficient(x)); + Assert.Equal(2.0, ct3.GetCoefficient(y)); + + Constraint ct4 = solver.Add(x + 5 * (y + x + 3) == 1); + Assert.Equal(6.0, ct4.GetCoefficient(x)); + Assert.Equal(5.0, ct4.GetCoefficient(y)); + Assert.Equal(-14.0, ct4.Lb()); + Assert.Equal(-14.0, ct4.Ub()); + + Constraint ct5 = solver.Add(x + (2 * y + x + 3) * 3 == 1); + Assert.Equal(4.0, ct5.GetCoefficient(x)); + Assert.Equal(6.0, ct5.GetCoefficient(y)); + Assert.Equal(-8.0, ct5.Lb()); + Assert.Equal(-8.0, ct5.Ub()); + } + + [Fact] + public void TestBinaryOperations() + { + Solver solver = new Solver("TestBinaryOperations", Solver.CLP_LINEAR_PROGRAMMING); + Variable x = solver.MakeNumVar(0.0, 100.0, "x"); + Variable y = solver.MakeNumVar(0.0, 100.0, "y"); + + Constraint ct1 = solver.Add(x == y); + Assert.Equal(1.0, ct1.GetCoefficient(x)); + Assert.Equal(-1.0, ct1.GetCoefficient(y)); + + Constraint ct2 = solver.Add(x == 3 * y + 5); + Assert.Equal(1.0, ct2.GetCoefficient(x)); + Assert.Equal(-3.0, ct2.GetCoefficient(y)); + Assert.Equal(5.0, ct2.Lb()); + Assert.Equal(5.0, ct2.Ub()); + + Constraint ct3 = solver.Add(2 * x - 9 == y); + Assert.Equal(2.0, ct3.GetCoefficient(x)); + Assert.Equal(-1.0, ct3.GetCoefficient(y)); + Assert.Equal(9.0, ct3.Lb()); + Assert.Equal(9.0, ct3.Ub()); + + Assert.True(x == x, "test11"); + Assert.True(!(x == y), "test12"); + Assert.True(!(x != x), "test13"); + Assert.True((x != y), "test14"); + } + + [Fact] + public void TestInequalities() + { + Solver solver = new Solver("TestInequalities", Solver.CLP_LINEAR_PROGRAMMING); + Variable x = solver.MakeNumVar(0.0, 100.0, "x"); + Variable y = solver.MakeNumVar(0.0, 100.0, "y"); + + Constraint ct1 = solver.Add(2 * (x + 3) + 5 * (y + x - 1) >= 3); + Assert.Equal(7.0, ct1.GetCoefficient(x)); + Assert.Equal(5.0, ct1.GetCoefficient(y)); + Assert.Equal(2.0, ct1.Lb()); + Assert.Equal(double.PositiveInfinity, ct1.Ub()); + + Constraint ct2 = solver.Add(2 * (x + 3) + 5 * (y + x - 1) <= 3); + Assert.Equal(7.0, ct2.GetCoefficient(x)); + Assert.Equal(5.0, ct2.GetCoefficient(y)); + Assert.Equal(double.NegativeInfinity, ct2.Lb()); + Assert.Equal(2.0, ct2.Ub()); + + Constraint ct3 = solver.Add(2 * (x + 3) + 5 * (y + x - 1) >= 3 - x - y); + Assert.Equal(8.0, ct3.GetCoefficient(x)); + Assert.Equal(6.0, ct3.GetCoefficient(y)); + Assert.Equal(2.0, ct3.Lb()); + Assert.Equal(double.PositiveInfinity, ct3.Ub()); + + Constraint ct4 = solver.Add(2 * (x + 3) + 5 * (y + x - 1) <= -x - y + 3); + Assert.Equal(8.0, ct4.GetCoefficient(x)); + Assert.Equal(6.0, ct4.GetCoefficient(y)); + Assert.Equal(double.NegativeInfinity, ct4.Lb()); + Assert.Equal(2.0, ct4.Ub()); + } + + [Fact] + public void TestSumArray() + { + Solver solver = new Solver("TestSumArray", Solver.CLP_LINEAR_PROGRAMMING); + + Variable[] x = solver.MakeBoolVarArray(10, "x"); + Constraint ct1 = solver.Add(x.Sum() == 3); + Assert.Equal(1.0, ct1.GetCoefficient(x[0])); + + Constraint ct2 = solver.Add(-2 * x.Sum() == 3); + Assert.Equal(-2.0, ct2.GetCoefficient(x[0])); + + LinearExpr[] array = new LinearExpr[] { x[0] + 2.0, x[0] + 3, x[0] + 4 }; + Constraint ct3 = solver.Add(array.Sum() == 1); + Assert.Equal(3.0, ct3.GetCoefficient(x[0])); + Assert.Equal(-8.0, ct3.Lb()); + Assert.Equal(-8.0, ct3.Ub()); + } + + [Fact] + public void TestObjective() + { + + Solver solver = new Solver("TestObjective", Solver.CLP_LINEAR_PROGRAMMING); + + Variable x = solver.MakeNumVar(0.0, 100.0, "x"); + Variable y = solver.MakeNumVar(0.0, 100.0, "y"); + + solver.Maximize(x); + Assert.Equal(0.0, solver.Objective().Offset()); + Assert.Equal(1.0, solver.Objective().GetCoefficient(x)); + Assert.True(solver.Objective().Maximization()); + + solver.Minimize(-x - 2 * y + 3); + Assert.Equal(3.0, solver.Objective().Offset()); + Assert.Equal(-1.0, solver.Objective().GetCoefficient(x)); + Assert.Equal(-2.0, solver.Objective().GetCoefficient(y)); + Assert.True(solver.Objective().Minimization()); + } + } +} diff --git a/ortools/dotnet/OrTools.Tests/OrTools.Tests.csproj b/ortools/dotnet/OrTools.Tests/OrTools.Tests.csproj new file mode 100644 index 0000000000..bca4a10c00 --- /dev/null +++ b/ortools/dotnet/OrTools.Tests/OrTools.Tests.csproj @@ -0,0 +1,20 @@ + + + Exe + netcoreapp2.0 + Google.OrTools.Tests + Google.OrTools.Tests + + + full + + + + + + + + ..\..\..\bin\Google.OrTools.dll + + + diff --git a/ortools/dotnet/OrTools.Tests/Program.cs b/ortools/dotnet/OrTools.Tests/Program.cs new file mode 100644 index 0000000000..d51cfe834f --- /dev/null +++ b/ortools/dotnet/OrTools.Tests/Program.cs @@ -0,0 +1,14 @@ +using System; + + +namespace Google.OrTools.Tests +{ + class Program + { + [STAThread] + public static void Main(string[] args) + { + Console.WriteLine("OrTools .NET Tests"); + } + } +} \ No newline at end of file