From b51e77c27d951d8f7524ed0e3bacc0839430959b Mon Sep 17 00:00:00 2001
From: Matthew Moore <mtthw.j.mr@gmail.com>
Date: Tue, 24 Apr 2018 02:40:11 -0700
Subject: [PATCH] Initial commit to unify all dotnet under one project

---
 .gitignore                                    |   5 +
 Makefile                                      |   5 +-
 makefiles/Makefile.dotnet.mk                  | 169 ++++
 ortools/dotnet/Google.sln                     |  34 +
 ortools/dotnet/OrTools/AssemblyInfo.cs        |  11 +
 ortools/dotnet/OrTools/OrTools.csproj         | 536 +++++++++++
 ortools/dotnet/OrTools/OrTools.nuspec         |  22 +
 .../OrTools/algorithms/IntArrayHelper.cs      |  76 ++
 .../constraintsolver/IntArrayHelper.cs        | 145 +++
 .../constraintsolver/IntVarArrayHelper.cs     | 370 ++++++++
 .../IntervalVarArrayHelper.cs                 |  53 ++
 .../constraintsolver/NetDecisionBuilder.cs    | 205 ++++
 .../OrTools/constraintsolver/SolverHelper.cs  | 517 ++++++++++
 .../OrTools/constraintsolver/ValCstPair.cs    | 300 ++++++
 .../OrTools/linearsolver/DoubleArrayHelper.cs |  40 +
 .../OrTools/linearsolver/LinearConstraint.cs  | 140 +++
 .../dotnet/OrTools/linearsolver/LinearExpr.cs | 344 +++++++
 .../OrTools/linearsolver/SolverHelper.cs      | 250 +++++
 .../OrTools/linearsolver/VariableHelper.cs    | 191 ++++
 ortools/dotnet/OrTools/sat/Constraints.cs     |  47 +
 ortools/dotnet/OrTools/sat/CpModel.cs         | 880 ++++++++++++++++++
 ortools/dotnet/OrTools/sat/CpSolver.cs        | 257 +++++
 .../dotnet/OrTools/sat/IntegerExpressions.cs  | 635 +++++++++++++
 .../dotnet/OrTools/sat/IntervalVariables.cs   |  69 ++
 .../dotnet/OrTools/util/NestedArrayHelper.cs  |  49 +
 ortools/dotnet/OrTools/util/ProtoHelper.cs    |  30 +
 ortools/dotnet/README.md                      |   5 +
 27 files changed, 5383 insertions(+), 2 deletions(-)
 create mode 100644 makefiles/Makefile.dotnet.mk
 create mode 100644 ortools/dotnet/Google.sln
 create mode 100644 ortools/dotnet/OrTools/AssemblyInfo.cs
 create mode 100644 ortools/dotnet/OrTools/OrTools.csproj
 create mode 100644 ortools/dotnet/OrTools/OrTools.nuspec
 create mode 100644 ortools/dotnet/OrTools/algorithms/IntArrayHelper.cs
 create mode 100644 ortools/dotnet/OrTools/constraintsolver/IntArrayHelper.cs
 create mode 100644 ortools/dotnet/OrTools/constraintsolver/IntVarArrayHelper.cs
 create mode 100644 ortools/dotnet/OrTools/constraintsolver/IntervalVarArrayHelper.cs
 create mode 100644 ortools/dotnet/OrTools/constraintsolver/NetDecisionBuilder.cs
 create mode 100644 ortools/dotnet/OrTools/constraintsolver/SolverHelper.cs
 create mode 100644 ortools/dotnet/OrTools/constraintsolver/ValCstPair.cs
 create mode 100644 ortools/dotnet/OrTools/linearsolver/DoubleArrayHelper.cs
 create mode 100644 ortools/dotnet/OrTools/linearsolver/LinearConstraint.cs
 create mode 100644 ortools/dotnet/OrTools/linearsolver/LinearExpr.cs
 create mode 100644 ortools/dotnet/OrTools/linearsolver/SolverHelper.cs
 create mode 100644 ortools/dotnet/OrTools/linearsolver/VariableHelper.cs
 create mode 100644 ortools/dotnet/OrTools/sat/Constraints.cs
 create mode 100644 ortools/dotnet/OrTools/sat/CpModel.cs
 create mode 100644 ortools/dotnet/OrTools/sat/CpSolver.cs
 create mode 100644 ortools/dotnet/OrTools/sat/IntegerExpressions.cs
 create mode 100644 ortools/dotnet/OrTools/sat/IntervalVariables.cs
 create mode 100644 ortools/dotnet/OrTools/util/NestedArrayHelper.cs
 create mode 100644 ortools/dotnet/OrTools/util/ProtoHelper.cs
 create mode 100644 ortools/dotnet/README.md

diff --git a/.gitignore b/.gitignore
index 440a39b759d..f9510a17ce3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -82,3 +82,8 @@ tools/netstandard/CreateSigningKey/obj
 ortools/fsharp/**/bin
 ortools/fsharp/**/obj
 ortools/fsharp/**/packages
+
+ortools/dotnet/**/bin
+ortools/dotnet/**/obj
+ortools/dotnet/**/packages
+*.userprefs
diff --git a/Makefile b/Makefile
index 32f2b5527d2..9b8d85c936e 100755
--- a/Makefile
+++ b/Makefile
@@ -55,8 +55,9 @@ include $(OR_ROOT)makefiles/Makefile.third_party.$(SYSTEM).mk
 include $(OR_ROOT)makefiles/Makefile.cpp.mk
 include $(OR_ROOT)makefiles/Makefile.python.mk
 include $(OR_ROOT)makefiles/Makefile.java.mk
-include $(OR_ROOT)makefiles/Makefile.csharp.mk
-include $(OR_ROOT)makefiles/Makefile.fsharp.mk
+include $(OR_ROOT)makefiles/Makefile.dotnet.mk
+# include $(OR_ROOT)makefiles/Makefile.csharp.mk
+# include $(OR_ROOT)makefiles/Makefile.fsharp.mk
 include $(OR_ROOT)makefiles/Makefile.archive.mk
 include $(OR_ROOT)makefiles/Makefile.install.mk
 
diff --git a/makefiles/Makefile.dotnet.mk b/makefiles/Makefile.dotnet.mk
new file mode 100644
index 00000000000..388e0f17264
--- /dev/null
+++ b/makefiles/Makefile.dotnet.mk
@@ -0,0 +1,169 @@
+# ---------- CSharp support using SWIG ----------
+.PHONY: help_dotnet # Generate list of dotnet targets with descriptions.
+help_dotnet:
+	@echo Use one of the following dotnet targets:
+ifeq ($(SYSTEM),win)
+	@tools\grep.exe "^.PHONY: .* #" $(CURDIR)/makefiles/Makefile.dotnet.mk | tools\sed.exe "s/\.PHONY: \(.*\) # \(.*\)/\1\t\2/"
+	@echo off & echo(
+else
+	@grep "^.PHONY: .* #" $(CURDIR)/makefiles/Makefile.dotnet.mk | sed "s/\.PHONY: \(.*\) # \(.*\)/\1\t\2/" | expand -t20
+	@echo
+endif
+
+ORTOOLS_DLL_NAME=OrTools
+ORTOOLS_NUSPEC_FILE=$(ORTOOLS_DLL_NAME).nuspec
+
+
+# Check for required build tools
+ifeq ($(SYSTEM), win)
+DOTNET_EXECUTABLE := $(shell $(WHICH) dotnet.exe 2>nul)
+else # UNIX
+ifeq ($(PLATFORM),MACOSX)
+DOTNET_EXECUTABLE := $(shell dirname ${DOTNET_INSTALL_PATH})$Sdotnet
+else # LINUX
+DOTNET_EXECUTABLE := $(shell which dotnet)
+endif
+endif
+
+.PHONY: csharp_dotnet # Build OrTools
+csharp_dotnet: ortoolslib \
+	$(GEN_DIR)/com/google/ortools/properties/CommonAssemblyInfo.cs \
+	$(OBJ_DIR)/swig/linear_solver_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 \
+	$(OBJ_DIR)/swig/sat_csharp_wrap.$O \
+	$(GEN_DIR)/com/google/ortools/constraintsolver/SearchLimit.g.cs \
+	$(GEN_DIR)/com/google/ortools/constraintsolver/SolverParameters.g.cs \
+	$(GEN_DIR)/com/google/ortools/constraintsolver/Model.g.cs \
+	$(GEN_DIR)/com/google/ortools/constraintsolver/RoutingParameters.g.cs \
+	$(GEN_DIR)/com/google/ortools/constraintsolver/RoutingEnums.g.cs \
+	$(GEN_DIR)/com/google/ortools/sat/CpModel.g.cs \
+	$(GEN_DIR)/com/google/ortools/sat/SatParameters.g.cs
+
+	$(SED) -i -e "s/0.0.0.0/$(OR_TOOLS_VERSION)/" ortools$Sdotnet$S$(ORTOOLS_DLL_NAME)$S$(ORTOOLS_DLL_NAME).csproj
+	"$(DOTNET_EXECUTABLE)" build ortools$Sdotnet$S$(ORTOOLS_DLL_NAME)$S$(ORTOOLS_DLL_NAME).csproj
+
+
+$(GEN_DIR)/com/google/ortools/properties/GitVersion$(OR_TOOLS_VERSION).txt: \
+	| $(GEN_DIR)/com/google/ortools/properties
+	@echo $(OR_TOOLS_VERSION) > $(GEN_DIR)$Scom$Sgoogle$Sortools$Sproperties$SGitVersion$(OR_TOOLS_VERSION).txt
+
+# See for background on Windows Explorer File Info Details:
+#  https://social.msdn.microsoft.com/Forums/vstudio/en-US/27894a09-1eed-48d9-8a0f-2198388d492c/csc-modulelink-or-just-csc-dll-plus-some-external-dllobj-references
+#  also, https://blogs.msdn.microsoft.com/texblog/2007/04/05/linking-native-c-into-c-applications/
+$(GEN_DIR)/com/google/ortools/properties/CommonAssemblyInfo.cs: \
+	$(GEN_DIR)/com/google/ortools/properties/GitVersion$(OR_TOOLS_VERSION).txt
+	$(COPY) tools$Scsharp$SCommonAssemblyInfo.cs $(GEN_DIR)$Scom$Sgoogle$Sortools$Sproperties
+	$(SED) -i -e "s/XXXX/$(OR_TOOLS_VERSION)/" $(GEN_DIR)$Scom$Sgoogle$Sortools$Sproperties$SCommonAssemblyInfo.cs
+
+
+$(GEN_DIR)/ortools/linear_solver/linear_solver_csharp_wrap.cc: \
+	$(SRC_DIR)/ortools/linear_solver/csharp/linear_solver.i \
+	$(SRC_DIR)/ortools/base/base.i \
+	$(SRC_DIR)/ortools/util/csharp/proto.i \
+	$(LP_DEPS)
+	$(SWIG_BINARY) $(SWIG_INC) -I$(INC_DIR) -c++ -csharp -o $(GEN_DIR)$Sortools$Slinear_solver$Slinear_solver_csharp_wrap.cc -module operations_research_linear_solver -namespace $(BASE_CLR_ORTOOLS_DLL_NAME).LinearSolver -dllimport "$(CLR_ORTOOLS_IMPORT_DLL_NAME).$(SWIG_LIB_SUFFIX)" -outdir $(GEN_DIR)$Scom$Sgoogle$Sortools$Slinearsolver $(SRC_DIR)$Sortools$Slinear_solver$Scsharp$Slinear_solver.i
+
+$(OBJ_DIR)/swig/linear_solver_csharp_wrap.$O: $(GEN_DIR)/ortools/linear_solver/linear_solver_csharp_wrap.cc
+	$(CCC) $(CFLAGS) -c $(GEN_DIR)/ortools/linear_solver/linear_solver_csharp_wrap.cc $(OBJ_OUT)$(OBJ_DIR)$Sswig$Slinear_solver_csharp_wrap.$O
+
+$(GEN_DIR)/ortools/constraint_solver/constraint_solver_csharp_wrap.cc: \
+	$(SRC_DIR)/ortools/constraint_solver/csharp/routing.i \
+	$(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)
+	$(SWIG_BINARY) $(SWIG_INC) -I$(INC_DIR) -c++ -csharp -o $(GEN_DIR)$Sortools$Sconstraint_solver$Sconstraint_solver_csharp_wrap.cc -module operations_research_constraint_solver -namespace $(BASE_CLR_ORTOOLS_DLL_NAME).ConstraintSolver -dllimport "$(CLR_ORTOOLS_IMPORT_DLL_NAME).$(SWIG_LIB_SUFFIX)" -outdir $(GEN_DIR)$Scom$Sgoogle$Sortools$Sconstraintsolver $(SRC_DIR)$Sortools$Sconstraint_solver$Scsharp$Srouting.i
+	$(SED) -i -e 's/CSharp_new_Solver/CSharp_new_CpSolver/g' $(GEN_DIR)/com/google/ortools/constraintsolver/*cs $(GEN_DIR)/ortools/constraint_solver/constraint_solver_csharp_wrap.*
+	$(SED) -i -e 's/CSharp_delete_Solver/CSharp_delete_CpSolver/g' $(GEN_DIR)/com/google/ortools/constraintsolver/*cs $(GEN_DIR)/ortools/constraint_solver/constraint_solver_csharp_wrap.*
+	$(SED) -i -e 's/CSharp_Solver/CSharp_CpSolver/g' $(GEN_DIR)/com/google/ortools/constraintsolver/*cs $(GEN_DIR)/ortools/constraint_solver/constraint_solver_csharp_wrap.*
+	$(SED) -i -e 's/CSharp_new_Constraint/CSharp_new_CpConstraint/g' $(GEN_DIR)/com/google/ortools/constraintsolver/*cs $(GEN_DIR)/ortools/constraint_solver/constraint_solver_csharp_wrap.*
+	$(SED) -i -e 's/CSharp_delete_Constraint/CSharp_delete_CpConstraint/g' $(GEN_DIR)/com/google/ortools/constraintsolver/*cs $(GEN_DIR)/ortools/constraint_solver/constraint_solver_csharp_wrap.*
+	$(SED) -i -e 's/CSharp_Constraint/CSharp_CpConstraint/g' $(GEN_DIR)/com/google/ortools/constraintsolver/*cs $(GEN_DIR)/ortools/constraint_solver/constraint_solver_csharp_wrap.*
+
+$(OBJ_DIR)/swig/constraint_solver_csharp_wrap.$O: \
+	$(GEN_DIR)/ortools/constraint_solver/constraint_solver_csharp_wrap.cc
+	$(CCC) $(CFLAGS) -c $(GEN_DIR)$Sortools$Sconstraint_solver$Sconstraint_solver_csharp_wrap.cc $(OBJ_OUT)$(OBJ_DIR)$Sswig$Sconstraint_solver_csharp_wrap.$O
+
+$(GEN_DIR)/ortools/algorithms/knapsack_solver_csharp_wrap.cc: \
+	$(SRC_DIR)/ortools/algorithms/csharp/knapsack_solver.i \
+	$(SRC_DIR)/ortools/base/base.i \
+	$(SRC_DIR)/ortools/util/csharp/proto.i \
+	$(SRC_DIR)/ortools/algorithms/knapsack_solver.h
+	$(SWIG_BINARY) $(SWIG_INC) -I$(INC_DIR) -c++ -csharp -o $(GEN_DIR)$Sortools$Salgorithms$Sknapsack_solver_csharp_wrap.cc -module operations_research_algorithms -namespace $(BASE_CLR_ORTOOLS_DLL_NAME).Algorithms -dllimport "$(CLR_ORTOOLS_IMPORT_DLL_NAME).$(SWIG_LIB_SUFFIX)" -outdir $(GEN_DIR)$Scom$Sgoogle$Sortools$Salgorithms $(SRC_DIR)$Sortools$Salgorithms$Scsharp$Sknapsack_solver.i
+
+$(OBJ_DIR)/swig/knapsack_solver_csharp_wrap.$O: $(GEN_DIR)/ortools/algorithms/knapsack_solver_csharp_wrap.cc
+	$(CCC) $(CFLAGS) -c $(GEN_DIR)/ortools/algorithms/knapsack_solver_csharp_wrap.cc $(OBJ_OUT)$(OBJ_DIR)$Sswig$Sknapsack_solver_csharp_wrap.$O
+
+$(GEN_DIR)/ortools/graph/graph_csharp_wrap.cc: \
+	$(SRC_DIR)/ortools/graph/csharp/graph.i \
+	$(SRC_DIR)/ortools/base/base.i \
+	$(SRC_DIR)/ortools/util/csharp/proto.i \
+	$(GRAPH_DEPS)
+	$(SWIG_BINARY) $(SWIG_INC) -I$(INC_DIR) -c++ -csharp -o $(GEN_DIR)$Sortools$Sgraph$Sgraph_csharp_wrap.cc -module operations_research_graph -namespace $(BASE_CLR_ORTOOLS_DLL_NAME).Graph -dllimport "$(CLR_ORTOOLS_IMPORT_DLL_NAME).$(SWIG_LIB_SUFFIX)" -outdir $(GEN_DIR)$Scom$Sgoogle$Sortools$Sgraph $(SRC_DIR)$Sortools$Sgraph$Scsharp$Sgraph.i
+
+$(OBJ_DIR)/swig/graph_csharp_wrap.$O: $(GEN_DIR)/ortools/graph/graph_csharp_wrap.cc
+	$(CCC) $(CFLAGS) -c $(GEN_DIR)$Sortools$Sgraph$Sgraph_csharp_wrap.cc $(OBJ_OUT)$(OBJ_DIR)$Sswig$Sgraph_csharp_wrap.$O
+
+$(GEN_DIR)/ortools/sat/sat_csharp_wrap.cc: \
+	$(SRC_DIR)/ortools/base/base.i \
+	$(SRC_DIR)/ortools/sat/csharp/sat.i \
+	$(SRC_DIR)/ortools/sat/swig_helper.h \
+	$(SRC_DIR)/ortools/util/csharp/proto.i \
+	$(SAT_DEPS)
+	$(SWIG_BINARY) $(SWIG_INC) -I$(INC_DIR) -c++ -csharp -o $(GEN_DIR)$Sortools$Ssat$Ssat_csharp_wrap.cc -module operations_research_sat -namespace $(BASE_CLR_ORTOOLS_DLL_NAME).Sat -dllimport "$(CLR_ORTOOLS_IMPORT_DLL_NAME).$(SWIG_LIB_SUFFIX)" -outdir $(GEN_DIR)$Scom$Sgoogle$Sortools$Ssat $(SRC_DIR)$Sortools$Ssat$Scsharp$Ssat.i
+
+$(OBJ_DIR)/swig/sat_csharp_wrap.$O: $(GEN_DIR)/ortools/sat/sat_csharp_wrap.cc
+	$(CCC) $(CFLAGS) -c $(GEN_DIR)/ortools/sat/sat_csharp_wrap.cc $(OBJ_OUT)$(OBJ_DIR)$Sswig$Ssat_csharp_wrap.$O
+
+
+# Protobufs
+
+$(GEN_DIR)/com/google/ortools/constraintsolver/SearchLimit.g.cs: $(SRC_DIR)/ortools/constraint_solver/search_limit.proto
+	$(PROTOBUF_DIR)/bin/protoc --proto_path=$(SRC_DIR) --csharp_out=$(GEN_DIR)$Scom$Sgoogle$Sortools$Sconstraintsolver --csharp_opt=file_extension=.g.cs $(SRC_DIR)$Sortools$Sconstraint_solver$Ssearch_limit.proto
+
+$(GEN_DIR)/com/google/ortools/constraintsolver/SolverParameters.g.cs: $(SRC_DIR)/ortools/constraint_solver/solver_parameters.proto
+	$(PROTOBUF_DIR)/bin/protoc --proto_path=$(SRC_DIR) --csharp_out=$(GEN_DIR)$Scom$Sgoogle$Sortools$Sconstraintsolver --csharp_opt=file_extension=.g.cs $(SRC_DIR)$Sortools$Sconstraint_solver$Ssolver_parameters.proto
+
+$(GEN_DIR)/com/google/ortools/constraintsolver/Model.g.cs: $(SRC_DIR)/ortools/constraint_solver/solver_parameters.proto
+	$(PROTOBUF_DIR)/bin/protoc --proto_path=$(SRC_DIR) --csharp_out=$(GEN_DIR)$Scom$Sgoogle$Sortools$Sconstraintsolver --csharp_opt=file_extension=.g.cs $(SRC_DIR)$Sortools$Sconstraint_solver$Smodel.proto
+
+$(GEN_DIR)/com/google/ortools/constraintsolver/RoutingParameters.g.cs: $(SRC_DIR)/ortools/constraint_solver/routing_parameters.proto
+	$(PROTOBUF_DIR)/bin/protoc --proto_path=$(SRC_DIR) --csharp_out=$(GEN_DIR)$Scom$Sgoogle$Sortools$Sconstraintsolver --csharp_opt=file_extension=.g.cs $(SRC_DIR)$Sortools$Sconstraint_solver$Srouting_parameters.proto
+
+$(GEN_DIR)/com/google/ortools/constraintsolver/RoutingEnums.g.cs: $(SRC_DIR)/ortools/constraint_solver/routing_enums.proto
+	$(PROTOBUF_DIR)/bin/protoc --proto_path=$(SRC_DIR) --csharp_out=$(GEN_DIR)$Scom$Sgoogle$Sortools$Sconstraintsolver --csharp_opt=file_extension=.g.cs $(SRC_DIR)$Sortools$Sconstraint_solver$Srouting_enums.proto
+
+$(GEN_DIR)/com/google/ortools/sat/CpModel.g.cs: $(SRC_DIR)/ortools/sat/cp_model.proto
+	$(PROTOBUF_DIR)/bin/protoc --proto_path=$(SRC_DIR) --csharp_out=$(GEN_DIR)$Scom$Sgoogle$Sortools$Ssat --csharp_opt=file_extension=.g.cs $(SRC_DIR)$Sortools$Ssat$Scp_model.proto
+
+$(GEN_DIR)/com/google/ortools/sat/SatParameters.g.cs: $(SRC_DIR)/ortools/sat/sat_parameters.proto
+	$(PROTOBUF_DIR)/bin/protoc --proto_path=$(SRC_DIR) --csharp_out=$(GEN_DIR)$Scom$Sgoogle$Sortools$Ssat --csharp_opt=file_extension=.g.cs $(SRC_DIR)$Sortools$Ssat$Ssat_parameters.proto
+
+
+
+.PHONY: pkg_dotnet # Build Nuget Package for distribution.
+pkg_dotnet:
+	$(warning Not Implemented)
+
+.PHONY: pkg_dotnet-upload # Upload Nuget Package
+nuget-pkg_dotnet-upload: nuget_archive
+	$(warning Not Implemented)
+
+
+.PHONY: detect_dotnet # Show variables used to build dotnet OR-Tools.
+detect_dotnet:
+ifeq ($(SYSTEM),win)
+	@echo Relevant info for the dotnet build:
+else
+	@echo Relevant info for the dotnet build:
+endif
+	@echo DOTNET_EXECUTABLE = "$(DOTNET_EXECUTABLE)"
+	@echo MONO_EXECUTABLE = "$(MONO_EXECUTABLE)"
+ifeq ($(SYSTEM),win)
+	@echo off & echo(
+else
+	@echo
+endif
diff --git a/ortools/dotnet/Google.sln b/ortools/dotnet/Google.sln
new file mode 100644
index 00000000000..f57ebc8f573
--- /dev/null
+++ b/ortools/dotnet/Google.sln
@@ -0,0 +1,34 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+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
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{AFA3F878-FB56-4314-B31E-3DA5583B548B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AFA3F878-FB56-4314-B31E-3DA5583B548B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AFA3F878-FB56-4314-B31E-3DA5583B548B}.Debug|x64.ActiveCfg = Debug|x64
+		{AFA3F878-FB56-4314-B31E-3DA5583B548B}.Debug|x64.Build.0 = Debug|x64
+		{AFA3F878-FB56-4314-B31E-3DA5583B548B}.Debug|x86.ActiveCfg = Debug|x86
+		{AFA3F878-FB56-4314-B31E-3DA5583B548B}.Debug|x86.Build.0 = Debug|x86
+		{AFA3F878-FB56-4314-B31E-3DA5583B548B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AFA3F878-FB56-4314-B31E-3DA5583B548B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AFA3F878-FB56-4314-B31E-3DA5583B548B}.Release|x64.ActiveCfg = Release|x64
+		{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
+	EndGlobalSection
+EndGlobal
diff --git a/ortools/dotnet/OrTools/AssemblyInfo.cs b/ortools/dotnet/OrTools/AssemblyInfo.cs
new file mode 100644
index 00000000000..6f5825f7d36
--- /dev/null
+++ b/ortools/dotnet/OrTools/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Google.OrTools")]
+[assembly: AssemblyDescription(".NET Assembly for the Operations Research Tools project")]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("0a227c4c-8bb3-4db0-808f-55dae227d8c5")]
diff --git a/ortools/dotnet/OrTools/OrTools.csproj b/ortools/dotnet/OrTools/OrTools.csproj
new file mode 100644
index 00000000000..44cb4b21e16
--- /dev/null
+++ b/ortools/dotnet/OrTools/OrTools.csproj
@@ -0,0 +1,536 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+
+    <OutputType>Library</OutputType>
+    <AssemblyTitle>Google.OrTools</AssemblyTitle>
+    <TargetFrameworks>netcoreapp2.0</TargetFrameworks>
+    <AssemblyName>Google.OrTools</AssemblyName>
+    <UseSharedCompilation>False</UseSharedCompilation>
+    <NuspecFile>OrTools.nuspec</NuspecFile>
+
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+
+    <Version>0.0.0.0</Version>
+    <AssemblyVersion>0.0.0.0</AssemblyVersion>
+    <FileVersion>0.0.0.0</FileVersion>
+
+    <RootNamespace>Google.OrTools</RootNamespace>
+
+    <AssemblyOriginatorKeyFile>..\..\..\bin\or-tools.snk</AssemblyOriginatorKeyFile>
+    <SignAssembly>true</SignAssembly>
+    <PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Compile Include="..\..\..\ortools\gen\com\google\ortools\properties\CommonAssemblyInfo.cs" Link="CommonAssemblyInfo.cs" />
+
+    <Compile Include="..\..\..\ortools\gen\com\google\ortools\linearsolver\*.cs">
+      <Link>linearsolver\%(Filename)%(Extension)</Link>
+    </Compile>
+
+    <Compile Include="..\..\..\ortools\gen\com\google\ortools\constraintsolver\*.cs">
+      <Link>constraintsolver\%(Filename)%(Extension)</Link>
+    </Compile>
+
+    <Compile Include="..\..\..\ortools\gen\com\google\ortools\algorithms\*.cs">
+      <Link>algorithms\%(Filename)%(Extension)</Link>
+    </Compile>
+
+    <Compile Include="..\..\..\ortools\gen\com\google\ortools\graph\*.cs">
+      <Link>graph\%(Filename)%(Extension)</Link>
+    </Compile>
+
+    <Compile Include="..\..\..\ortools\gen\com\google\ortools\sat\*.cs">
+      <Link>sat\%(Filename)%(Extension)</Link>
+    </Compile>
+
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Google.Protobuf" Version="3.5.1" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Update="..\..\gen\com\google\ortools\linearsolver\Constraint.cs">
+      <Link>linearsolver\Constraint.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\linearsolver\MPSolverParameters.cs">
+      <Link>linearsolver\MPSolverParameters.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\linearsolver\MpDoubleVector.cs">
+      <Link>linearsolver\MpDoubleVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\linearsolver\Objective.cs">
+      <Link>linearsolver\Objective.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\linearsolver\Solver.cs">
+      <Link>linearsolver\Solver.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\linearsolver\Variable.cs">
+      <Link>linearsolver\Variable.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\linearsolver\operations_research_linear_solver.cs">
+      <Link>linearsolver\operations_research_linear_solver.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\linearsolver\operations_research_linear_solverPINVOKE.cs">
+      <Link>linearsolver\operations_research_linear_solverPINVOKE.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\Assignment.cs">
+      <Link>constraintsolver\Assignment.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\AssignmentElement.cs">
+      <Link>constraintsolver\AssignmentElement.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\AssignmentIntContainer.cs">
+      <Link>constraintsolver\AssignmentIntContainer.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\BaseIntExpr.cs">
+      <Link>constraintsolver\BaseIntExpr.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\BaseLns.cs">
+      <Link>constraintsolver\BaseLns.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\BaseObject.cs">
+      <Link>constraintsolver\BaseObject.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\BasePathFilter.cs">
+      <Link>constraintsolver\BasePathFilter.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\BooleanVar.cs">
+      <Link>constraintsolver\BooleanVar.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\CastConstraint.cs">
+      <Link>constraintsolver\CastConstraint.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\ChangeValue.cs">
+      <Link>constraintsolver\ChangeValue.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\CheapestAdditionFilteredDecisionBuilder.cs">
+      <Link>constraintsolver\CheapestAdditionFilteredDecisionBuilder.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\CheapestInsertionFilteredDecisionBuilder.cs">
+      <Link>constraintsolver\CheapestInsertionFilteredDecisionBuilder.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\ChristofidesFilteredDecisionBuilder.cs">
+      <Link>constraintsolver\ChristofidesFilteredDecisionBuilder.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\ComparatorCheapestAdditionFilteredDecisionBuilder.cs">
+      <Link>constraintsolver\ComparatorCheapestAdditionFilteredDecisionBuilder.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\Constraint.cs">
+      <Link>constraintsolver\Constraint.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\CpInt64Vector.cs">
+      <Link>constraintsolver\CpInt64Vector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\CpInt64VectorVector.cs">
+      <Link>constraintsolver\CpInt64VectorVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\CpIntVector.cs">
+      <Link>constraintsolver\CpIntVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\CpIntVectorVector.cs">
+      <Link>constraintsolver\CpIntVectorVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\CpModelLoader.cs">
+      <Link>constraintsolver\CpModelLoader.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\Decision.cs">
+      <Link>constraintsolver\Decision.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\DecisionBuilder.cs">
+      <Link>constraintsolver\DecisionBuilder.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\DecisionBuilderVector.cs">
+      <Link>constraintsolver\DecisionBuilderVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\DecisionVisitor.cs">
+      <Link>constraintsolver\DecisionVisitor.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\DefaultPhaseParameters.cs">
+      <Link>constraintsolver\DefaultPhaseParameters.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\Demon.cs">
+      <Link>constraintsolver\Demon.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\DisjunctiveConstraint.cs">
+      <Link>constraintsolver\DisjunctiveConstraint.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\EvaluatorCheapestAdditionFilteredDecisionBuilder.cs">
+      <Link>constraintsolver\EvaluatorCheapestAdditionFilteredDecisionBuilder.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\GlobalCheapestInsertionFilteredDecisionBuilder.cs">
+      <Link>constraintsolver\GlobalCheapestInsertionFilteredDecisionBuilder.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntExpr.cs">
+      <Link>constraintsolver\IntExpr.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntIntToLong.cs">
+      <Link>constraintsolver\IntIntToLong.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntTupleSet.cs">
+      <Link>constraintsolver\IntTupleSet.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntVar.cs">
+      <Link>constraintsolver\IntVar.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntVarElement.cs">
+      <Link>constraintsolver\IntVarElement.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntVarFilteredDecisionBuilder.cs">
+      <Link>constraintsolver\IntVarFilteredDecisionBuilder.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntVarIterator.cs">
+      <Link>constraintsolver\IntVarIterator.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntVarLocalSearchFilter.cs">
+      <Link>constraintsolver\IntVarLocalSearchFilter.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntVarLocalSearchHandler.cs">
+      <Link>constraintsolver\IntVarLocalSearchHandler.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntVarLocalSearchOperator.cs">
+      <Link>constraintsolver\IntVarLocalSearchOperator.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntVarLocalSearchOperatorTemplate.cs">
+      <Link>constraintsolver\IntVarLocalSearchOperatorTemplate.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntVarVector.cs">
+      <Link>constraintsolver\IntVarVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntervalVar.cs">
+      <Link>constraintsolver\IntervalVar.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntervalVarElement.cs">
+      <Link>constraintsolver\IntervalVarElement.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\IntervalVarVector.cs">
+      <Link>constraintsolver\IntervalVarVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LocalCheapestInsertionFilteredDecisionBuilder.cs">
+      <Link>constraintsolver\LocalCheapestInsertionFilteredDecisionBuilder.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LocalSearchFilter.cs">
+      <Link>constraintsolver\LocalSearchFilter.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LocalSearchFilterVector.cs">
+      <Link>constraintsolver\LocalSearchFilterVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LocalSearchMonitor.cs">
+      <Link>constraintsolver\LocalSearchMonitor.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LocalSearchOperator.cs">
+      <Link>constraintsolver\LocalSearchOperator.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LocalSearchOperatorVector.cs">
+      <Link>constraintsolver\LocalSearchOperatorVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LocalSearchPhaseParameters.cs">
+      <Link>constraintsolver\LocalSearchPhaseParameters.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LongLongLongToBoolean.cs">
+      <Link>constraintsolver\LongLongLongToBoolean.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LongLongLongToLong.cs">
+      <Link>constraintsolver\LongLongLongToLong.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LongLongToLong.cs">
+      <Link>constraintsolver\LongLongToLong.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LongToBoolean.cs">
+      <Link>constraintsolver\LongToBoolean.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LongToLong.cs">
+      <Link>constraintsolver\LongToLong.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\LongToVoid.cs">
+      <Link>constraintsolver\LongToVoid.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\Model.g.cs">
+      <Link>constraintsolver\Model.g.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\ModelCache.cs">
+      <Link>constraintsolver\ModelCache.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\ModelVisitor.cs">
+      <Link>constraintsolver\ModelVisitor.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\NoGood.cs">
+      <Link>constraintsolver\NoGood.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\NoGoodManager.cs">
+      <Link>constraintsolver\NoGoodManager.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\NodeEvaluator2.cs">
+      <Link>constraintsolver\NodeEvaluator2.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\NodeEvaluator2Vector.cs">
+      <Link>constraintsolver\NodeEvaluator2Vector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\OptimizeVar.cs">
+      <Link>constraintsolver\OptimizeVar.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\Pack.cs">
+      <Link>constraintsolver\Pack.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\PathOperator.cs">
+      <Link>constraintsolver\PathOperator.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\PathWithPreviousNodesOperator.cs">
+      <Link>constraintsolver\PathWithPreviousNodesOperator.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\PropagationBaseObject.cs">
+      <Link>constraintsolver\PropagationBaseObject.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\PropagationMonitor.cs">
+      <Link>constraintsolver\PropagationMonitor.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\RevBool.cs">
+      <Link>constraintsolver\RevBool.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\RevInteger.cs">
+      <Link>constraintsolver\RevInteger.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\RevPartialSequence.cs">
+      <Link>constraintsolver\RevPartialSequence.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\RoutingDimension.cs">
+      <Link>constraintsolver\RoutingDimension.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\RoutingEnums.g.cs">
+      <Link>constraintsolver\RoutingEnums.g.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\RoutingFilteredDecisionBuilder.cs">
+      <Link>constraintsolver\RoutingFilteredDecisionBuilder.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\RoutingLocalSearchFilter.cs">
+      <Link>constraintsolver\RoutingLocalSearchFilter.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\RoutingModel.cs">
+      <Link>constraintsolver\RoutingModel.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\RoutingModelVisitor.cs">
+      <Link>constraintsolver\RoutingModelVisitor.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\RoutingParameters.g.cs">
+      <Link>constraintsolver\RoutingParameters.g.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_ResultCallback2T_long_long_RoutingNodeIndex_RoutingNodeIndex_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_ResultCallback2T_long_long_RoutingNodeIndex_RoutingNodeIndex_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_RoutingCostClassIndex.cs">
+      <Link>constraintsolver\SWIGTYPE_p_RoutingCostClassIndex.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_RoutingDimensionIndex.cs">
+      <Link>constraintsolver\SWIGTYPE_p_RoutingDimensionIndex.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_RoutingDisjunctionIndex.cs">
+      <Link>constraintsolver\SWIGTYPE_p_RoutingDisjunctionIndex.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_RoutingVehicleClassIndex.cs">
+      <Link>constraintsolver\SWIGTYPE_p_RoutingVehicleClassIndex.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_int.cs">
+      <Link>constraintsolver\SWIGTYPE_p_int.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_long_long.cs">
+      <Link>constraintsolver\SWIGTYPE_p_long_long.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_operations_research__AssignmentContainerT_operations_research__IntervalVar_operations_research__IntervalVarElement_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_operations_research__AssignmentContainerT_operations_research__IntervalVar_operations_research__IntervalVarElement_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_operations_research__AssignmentContainerT_operations_research__SequenceVar_operations_research__SequenceVarElement_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_operations_research__AssignmentContainerT_operations_research__SequenceVar_operations_research__SequenceVarElement_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_operations_research__AssignmentProto.cs">
+      <Link>constraintsolver\SWIGTYPE_p_operations_research__AssignmentProto.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_operations_research__CpModel.cs">
+      <Link>constraintsolver\SWIGTYPE_p_operations_research__CpModel.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_operations_research__DemonProfiler.cs">
+      <Link>constraintsolver\SWIGTYPE_p_operations_research__DemonProfiler.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_operations_research__IntVarAssignment.cs">
+      <Link>constraintsolver\SWIGTYPE_p_operations_research__IntVarAssignment.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_operations_research__IntervalVarAssignment.cs">
+      <Link>constraintsolver\SWIGTYPE_p_operations_research__IntervalVarAssignment.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_operations_research__RevIntSetT_int_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_operations_research__RevIntSetT_int_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_operations_research__Search.cs">
+      <Link>constraintsolver\SWIGTYPE_p_operations_research__Search.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_operations_research__SequenceVarAssignment.cs">
+      <Link>constraintsolver\SWIGTYPE_p_operations_research__SequenceVarAssignment.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_operations_research__SimpleRevFIFOT_operations_research__Demon_p_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_operations_research__SimpleRevFIFOT_operations_research__Demon_p_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__functionT_int_flong_longF_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__functionT_int_flong_longF_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__functionT_long_long_flong_longF_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__functionT_long_long_flong_longF_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__functionT_long_long_flong_long_long_longF_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__functionT_long_long_flong_long_long_longF_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__functionT_operations_research__Solver__DecisionModification_fF_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__functionT_operations_research__Solver__DecisionModification_fF_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__functionT_void_fF_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__functionT_void_fF_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__functionT_void_flong_longF_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__functionT_void_flong_longF_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__vectorT_RoutingDisjunctionIndex_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__vectorT_RoutingDisjunctionIndex_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__vectorT_operations_research__IntVarElement_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__vectorT_operations_research__IntVarElement_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__vectorT_std__pairT_RoutingNodeIndex_RoutingNodeIndex_t_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__vectorT_std__pairT_RoutingNodeIndex_RoutingNodeIndex_t_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__vectorT_std__pairT_int_int_t_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__vectorT_std__pairT_int_int_t_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__vectorT_std__string_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__vectorT_std__string_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__vectorT_std__vectorT_RoutingNodeIndex_t_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__vectorT_std__vectorT_RoutingNodeIndex_t_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SWIGTYPE_p_std__vectorT_unsigned_long_long_t.cs">
+      <Link>constraintsolver\SWIGTYPE_p_std__vectorT_unsigned_long_long_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SavingsFilteredDecisionBuilder.cs">
+      <Link>constraintsolver\SavingsFilteredDecisionBuilder.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SearchLimit.cs">
+      <Link>constraintsolver\SearchLimit.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SearchLimit.g.cs">
+      <Link>constraintsolver\SearchLimit.g.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SearchLog.cs">
+      <Link>constraintsolver\SearchLog.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SearchMonitor.cs">
+      <Link>constraintsolver\SearchMonitor.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SearchMonitorVector.cs">
+      <Link>constraintsolver\SearchMonitorVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SequenceVar.cs">
+      <Link>constraintsolver\SequenceVar.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SequenceVarElement.cs">
+      <Link>constraintsolver\SequenceVarElement.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SequenceVarLocalSearchHandler.cs">
+      <Link>constraintsolver\SequenceVarLocalSearchHandler.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SequenceVarLocalSearchOperator.cs">
+      <Link>constraintsolver\SequenceVarLocalSearchOperator.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SequenceVarLocalSearchOperatorTemplate.cs">
+      <Link>constraintsolver\SequenceVarLocalSearchOperatorTemplate.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SequenceVarVector.cs">
+      <Link>constraintsolver\SequenceVarVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SolutionCollector.cs">
+      <Link>constraintsolver\SolutionCollector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SolutionPool.cs">
+      <Link>constraintsolver\SolutionPool.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\Solver.cs">
+      <Link>constraintsolver\Solver.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SolverParameters.g.cs">
+      <Link>constraintsolver\SolverParameters.g.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SymmetryBreaker.cs">
+      <Link>constraintsolver\SymmetryBreaker.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\SymmetryBreakerVector.cs">
+      <Link>constraintsolver\SymmetryBreakerVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\UnsortedNullableRevBitset.cs">
+      <Link>constraintsolver\UnsortedNullableRevBitset.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\VoidToBoolean.cs">
+      <Link>constraintsolver\VoidToBoolean.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\VoidToString.cs">
+      <Link>constraintsolver\VoidToString.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\VoidToVoid.cs">
+      <Link>constraintsolver\VoidToVoid.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\operations_research_constraint_solver.cs">
+      <Link>constraintsolver\operations_research_constraint_solver.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\constraintsolver\operations_research_constraint_solverPINVOKE.cs">
+      <Link>constraintsolver\operations_research_constraint_solverPINVOKE.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\algorithms\KInt64Vector.cs">
+      <Link>algorithms\KInt64Vector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\algorithms\KInt64VectorVector.cs">
+      <Link>algorithms\KInt64VectorVector.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\algorithms\KnapsackSolver.cs">
+      <Link>algorithms\KnapsackSolver.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\algorithms\operations_research_algorithms.cs">
+      <Link>algorithms\operations_research_algorithms.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\algorithms\operations_research_algorithmsPINVOKE.cs">
+      <Link>algorithms\operations_research_algorithmsPINVOKE.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\graph\LinearSumAssignment.cs">
+      <Link>graph\LinearSumAssignment.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\graph\MaxFlow.cs">
+      <Link>graph\MaxFlow.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\graph\MinCostFlow.cs">
+      <Link>graph\MinCostFlow.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\graph\MinCostFlowBase.cs">
+      <Link>graph\MinCostFlowBase.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\graph\SWIGTYPE_p_std__vectorT_int_t.cs">
+      <Link>graph\SWIGTYPE_p_std__vectorT_int_t.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\graph\operations_research_graph.cs">
+      <Link>graph\operations_research_graph.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\graph\operations_research_graphPINVOKE.cs">
+      <Link>graph\operations_research_graphPINVOKE.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\sat\CpModel.g.cs">
+      <Link>sat\CpModel.g.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\sat\SatHelper.cs">
+      <Link>sat\SatHelper.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\sat\SolutionCallback.cs">
+      <Link>sat\SolutionCallback.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\sat\operations_research_sat.cs">
+      <Link>sat\operations_research_sat.cs</Link>
+    </Compile>
+    <Compile Update="..\..\gen\com\google\ortools\sat\operations_research_satPINVOKE.cs">
+      <Link>sat\operations_research_satPINVOKE.cs</Link>
+    </Compile>
+  </ItemGroup>
+</Project>
diff --git a/ortools/dotnet/OrTools/OrTools.nuspec b/ortools/dotnet/OrTools/OrTools.nuspec
new file mode 100644
index 00000000000..2832225a92f
--- /dev/null
+++ b/ortools/dotnet/OrTools/OrTools.nuspec
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<package >
+    <metadata>
+        <id>NNNN</id>
+        <version>VVVV</version>
+        <authors>Google</authors>
+        <licenseUrl>https://github.com/google/or-tools/blob/master/LICENSE-2.0.txt</licenseUrl>
+        <projectUrl>https://developers.google.com/optimization</projectUrl>
+        <description>.NET Assembly for the Operations Research Tools project</description>
+        <copyright>Copyright 2018 Google, Inc</copyright>
+        <tags>Operations Research Math Linear Constraint Programming C# .NET SWIG C++</tags>
+        <dependencies>
+            <dependency id="MMMM" version="PROTOBUF_TAG" />
+        </dependencies>
+    </metadata>
+    <files>
+        <file src="bin\NNNN.dll" target="lib\net40"/>
+        <file src="examples\**\*.*" target="examples"/>
+        <file src="examples\data\**\*.*" target="data"/>
+        <file src="LICENSE-2.0.txt"/>
+    </files>
+</package>
diff --git a/ortools/dotnet/OrTools/algorithms/IntArrayHelper.cs b/ortools/dotnet/OrTools/algorithms/IntArrayHelper.cs
new file mode 100644
index 00000000000..ebfcb6e8f4c
--- /dev/null
+++ b/ortools/dotnet/OrTools/algorithms/IntArrayHelper.cs
@@ -0,0 +1,76 @@
+// Copyright 2010-2017 Google
+// 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<long>
+#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<KInt64Vector>
+#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/dotnet/OrTools/constraintsolver/IntArrayHelper.cs b/ortools/dotnet/OrTools/constraintsolver/IntArrayHelper.cs
new file mode 100644
index 00000000000..bc16cc4ef8f
--- /dev/null
+++ b/ortools/dotnet/OrTools/constraintsolver/IntArrayHelper.cs
@@ -0,0 +1,145 @@
+// Copyright 2010-2017 Google
+// 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.ConstraintSolver {
+using System;
+using System.Collections.Generic;
+
+// int[] and long[] helper class.
+public static class IntArrayHelper  {
+  public static IntExpr Element(this int[] array, IntExpr index) {
+    return index.solver().MakeElement(array, index.Var());
+  }
+  public static IntExpr Element(this long[] array, IntExpr index) {
+    return index.solver().MakeElement(array, index.Var());
+  }
+}
+
+public partial class CpInt64Vector: IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IList<long>
+#endif
+{
+  // cast from C# long array
+  public static implicit operator CpInt64Vector(long[] inVal) {
+    var outVal= new CpInt64Vector();
+    foreach (long element in inVal) {
+      outVal.Add(element);
+    }
+    return outVal;
+  }
+
+  // cast to C# long array
+  public static implicit operator long[](CpInt64Vector inVal) {
+    var outVal= new long[inVal.Count];
+    inVal.CopyTo(outVal);
+    return outVal;
+  }
+}
+
+public partial class CpIntVector: IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IList<int>
+#endif
+{
+  // cast from C# int array
+  public static implicit operator CpIntVector(int[] inVal) {
+    var outVal= new CpIntVector();
+    foreach (int element in inVal) {
+      outVal.Add(element);
+    }
+    return outVal;
+  }
+
+  // cast to C# int array
+  public static implicit operator int[](CpIntVector inVal) {
+    var outVal= new int[inVal.Count];
+    inVal.CopyTo(outVal);
+    return outVal;
+  }
+}
+
+public partial class CpIntVectorVector : IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IEnumerable<CpIntVector>
+#endif
+ {
+  // cast from C# int matrix
+  public static implicit operator CpIntVectorVector(int[,] inVal) {
+    int x_size = inVal.GetLength(0);
+    int y_size = inVal.GetLength(1);
+    CpIntVectorVector outVal = new CpIntVectorVector();
+    for (int i = 0; i < x_size; ++i)
+    {
+      outVal.Add(new CpIntVector());
+      for (int j = 0; j < y_size; ++j)
+      {
+        outVal[i].Add(inVal[i, j]);
+      }
+    }
+    return outVal;
+  }
+
+  // cast to C# int matrix
+  public static implicit operator int[,](CpIntVectorVector inVal) {
+    int x_size = inVal.Count;
+    int y_size = inVal.Count == 0  ? 0 : inVal[0].Count;
+    var outVal= new int[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;
+  }
+}
+
+public partial class CpInt64VectorVector : IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IEnumerable<CpInt64Vector>
+#endif
+ {
+  // cast from C# long matrix
+  public static implicit operator CpInt64VectorVector(long[,] inVal) {
+    int x_size = inVal.GetLength(0);
+    int y_size = inVal.GetLength(1);
+    CpInt64VectorVector outVal = new CpInt64VectorVector();
+    for (int i = 0; i < x_size; ++i)
+    {
+      outVal.Add(new CpInt64Vector());
+      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[,](CpInt64VectorVector 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.ConstraintSolver
diff --git a/ortools/dotnet/OrTools/constraintsolver/IntVarArrayHelper.cs b/ortools/dotnet/OrTools/constraintsolver/IntVarArrayHelper.cs
new file mode 100644
index 00000000000..186eac7c541
--- /dev/null
+++ b/ortools/dotnet/OrTools/constraintsolver/IntVarArrayHelper.cs
@@ -0,0 +1,370 @@
+// Copyright 2010-2017 Google
+// 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.ConstraintSolver
+{
+using System;
+using System.Collections.Generic;
+
+// IntVar[] helper class.
+public static class IntVarArrayHelper
+{
+  // All Different
+  public static Constraint AllDifferent(this IntVar[] vars)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeAllDifferent(vars);
+  }
+  // Allowed assignment
+  public static Constraint AllowedAssignments(this IntVar[] vars,
+                                              IntTupleSet tuples)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeAllowedAssignments(vars, tuples);
+  }
+  // sum of all vars.
+  public static IntExpr Sum(this IntVar[] vars)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeSum(vars);
+  }
+  // sum of all constraints.
+  public static IntExpr Sum(this IConstraintWithStatus[] cts)
+  {
+    Solver solver = GetSolver(cts);
+    IntVar[] vars = new IntVar[cts.Length];
+    for (int i = 0; i < cts.Length; ++i)
+    {
+      vars[i] = cts[i].Var();
+    }
+    return solver.MakeSum(vars);
+  }
+  public static IntExpr Sum(this IntExpr[] exprs)
+  {
+    Solver solver = GetSolver(exprs);
+    IntVar[] vars = new IntVar[exprs.Length];
+    for (int i = 0; i < exprs.Length; ++i)
+    {
+      vars[i] = exprs[i].Var();
+    }
+    return solver.MakeSum(vars);
+  }
+
+  // scalar product
+  public static IntExpr ScalProd(this IntVar[] vars, long[] coefs)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeScalProd(vars, coefs);
+  }
+
+  // scalar product
+  public static IntExpr ScalProd(this IntVar[] vars, int[] coefs)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeScalProd(vars, coefs);
+  }
+
+  // get solver from array of integer variables
+  private static Solver GetSolver(IntVar[] vars)
+  {
+    if (vars == null || vars.Length <= 0)
+      throw new ArgumentException("Array <vars> cannot be null or empty");
+
+    return vars[0].solver();
+  }
+  // get solver from array of integer expressions
+  private static Solver GetSolver(IntExpr[] expressions)
+  {
+    if (expressions == null || expressions.Length <= 0)
+      throw new ArgumentException("Array <expr> cannot be null or empty");
+
+    return expressions[0].solver();
+  }
+  private static Solver GetSolver(IConstraintWithStatus[] cts)
+  {
+    if (cts == null || cts.Length <= 0)
+      throw new ArgumentException("Array <cts> cannot be null or empty");
+
+    return cts[0].solver();
+  }
+  public static IntExpr Element(this IntVar[] array, IntExpr index) {
+    return index.solver().MakeElement(array, index.Var());
+  }
+  // min of all vars.
+  public static IntExpr Min(this IntVar[] vars)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeMin(vars);
+  }
+  // min of all vars.
+  public static IntExpr Max(this IntVar[] vars)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeMax(vars);
+  }
+  // count of all vars.
+  public static Constraint Count(this IntVar[] vars, long value, long count)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeCount(vars, value, count);
+  }
+  // count of all vars.
+  public static Constraint Count(this IntVar[] vars,
+                                 long value,
+                                 IntExpr count)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeCount(vars, value, count.Var());
+  }
+  public static Constraint Distribute(this IntVar[] vars,
+                                      long[] values,
+                                      IntVar[] cards)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeDistribute(vars, values, cards);
+  }
+  public static Constraint Distribute(this IntVar[] vars,
+                                      int[] values,
+                                      IntVar[] cards)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeDistribute(vars, values, cards);
+  }
+  public static Constraint Distribute(this IntVar[] vars,
+                                      IntVar[] cards)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeDistribute(vars, cards);
+  }
+  public static Constraint Distribute(this IntVar[] vars,
+                                      long card_min,
+                                      long card_max,
+                                      long card_size)
+  {
+    Solver solver = GetSolver(vars);
+    return solver.MakeDistribute(vars, card_min, card_max, card_size);
+  }
+  public static Constraint Transition(this IntVar[] vars,
+                                      IntTupleSet transitions,
+                                      long initial_state,
+                                      long[] final_states) {
+    Solver solver = GetSolver(vars);
+    return solver.MakeTransitionConstraint(vars,
+                                           transitions,
+                                           initial_state,
+                                           final_states);
+  }
+  public static Constraint Transition(this IntVar[] vars,
+                                      IntTupleSet transitions,
+                                      long initial_state,
+                                      int[] final_states) {
+    Solver solver = GetSolver(vars);
+    return solver.MakeTransitionConstraint(vars,
+                                           transitions,
+                                           initial_state,
+                                           final_states);
+  }
+
+  // Matrix API
+  public static IntVar[] Flatten(this IntVar[,] vars)
+  {
+    int rows = vars.GetLength(0);
+    int cols = vars.GetLength(1);
+    IntVar[] flat = new IntVar[cols * rows];
+    for(int i = 0; i < rows; i++) {
+      for(int j = 0; j < cols; j++) {
+        flat[i * cols + j] = vars[i, j];
+      }
+    }
+    return flat;
+  }
+}
+
+
+// TODO(user): Try to move this code back to the .swig with @define macros.
+public partial class IntVarVector: IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IList<IntVar>
+#endif
+{
+  // cast from C# IntVar array
+  public static implicit operator IntVarVector(IntVar[] inVal) {
+    var outVal= new IntVarVector();
+    foreach (IntVar element in inVal) {
+      outVal.Add(element);
+    }
+    return outVal;
+  }
+
+  // cast to C# IntVar array
+  public static implicit operator IntVar[](IntVarVector inVal) {
+    var outVal= new IntVar[inVal.Count];
+    inVal.CopyTo(outVal);
+    return outVal;
+  }
+}
+
+public partial class SearchMonitorVector: IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IList<SearchMonitor>
+#endif
+{
+  // cast from C# SearchMonitor array
+  public static implicit operator SearchMonitorVector(SearchMonitor[] inVal) {
+    var outVal= new SearchMonitorVector();
+    foreach (SearchMonitor element in inVal) {
+      outVal.Add(element);
+    }
+    return outVal;
+  }
+
+  // cast to C# SearchMonitor array
+  public static implicit operator SearchMonitor[](SearchMonitorVector inVal) {
+    var outVal= new SearchMonitor[inVal.Count];
+    inVal.CopyTo(outVal);
+    return outVal;
+  }
+}
+
+public partial class DecisionBuilderVector: IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IList<DecisionBuilder>
+#endif
+{
+  // cast from C# DecisionBuilder array
+  public static implicit operator DecisionBuilderVector(DecisionBuilder[] inVal) {
+    var outVal= new DecisionBuilderVector();
+    foreach (DecisionBuilder element in inVal) {
+      outVal.Add(element);
+    }
+    return outVal;
+  }
+
+  // cast to C# DecisionBuilder array
+  public static implicit operator DecisionBuilder[](DecisionBuilderVector inVal) {
+    var outVal= new DecisionBuilder[inVal.Count];
+    inVal.CopyTo(outVal);
+    return outVal;
+  }
+}
+
+public partial class IntervalVarVector: IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IList<IntervalVar>
+#endif
+{
+  // cast from C# IntervalVar array
+  public static implicit operator IntervalVarVector(IntervalVar[] inVal) {
+    var outVal= new IntervalVarVector();
+    foreach (IntervalVar element in inVal) {
+      outVal.Add(element);
+    }
+    return outVal;
+  }
+
+  // cast to C# IntervalVar array
+  public static implicit operator IntervalVar[](IntervalVarVector inVal) {
+    var outVal= new IntervalVar[inVal.Count];
+    inVal.CopyTo(outVal);
+    return outVal;
+  }
+}
+
+public partial class SequenceVarVector: IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IList<SequenceVar>
+#endif
+{
+  // cast from C# SequenceVar array
+  public static implicit operator SequenceVarVector(SequenceVar[] inVal) {
+    var outVal= new SequenceVarVector();
+    foreach (SequenceVar element in inVal) {
+      outVal.Add(element);
+    }
+    return outVal;
+  }
+
+  // cast to C# SequenceVar array
+  public static implicit operator SequenceVar[](SequenceVarVector inVal) {
+    var outVal= new SequenceVar[inVal.Count];
+    inVal.CopyTo(outVal);
+    return outVal;
+  }
+}
+
+public partial class LocalSearchOperatorVector: IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IList<LocalSearchOperator>
+#endif
+{
+  // cast from C# LocalSearchOperator array
+  public static implicit operator LocalSearchOperatorVector(LocalSearchOperator[] inVal) {
+    var outVal= new LocalSearchOperatorVector();
+    foreach (LocalSearchOperator element in inVal) {
+      outVal.Add(element);
+    }
+    return outVal;
+  }
+
+  // cast to C# LocalSearchOperator array
+  public static implicit operator LocalSearchOperator[](LocalSearchOperatorVector inVal) {
+    var outVal= new LocalSearchOperator[inVal.Count];
+    inVal.CopyTo(outVal);
+    return outVal;
+  }
+}
+
+public partial class LocalSearchFilterVector: IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IList<LocalSearchFilter>
+#endif
+{
+  // cast from C# LocalSearchFilter array
+  public static implicit operator LocalSearchFilterVector(LocalSearchFilter[] inVal) {
+    var outVal= new LocalSearchFilterVector();
+    foreach (LocalSearchFilter element in inVal) {
+      outVal.Add(element);
+    }
+    return outVal;
+  }
+
+  // cast to C# LocalSearchFilter array
+  public static implicit operator LocalSearchFilter[](LocalSearchFilterVector inVal) {
+    var outVal= new LocalSearchFilter[inVal.Count];
+    inVal.CopyTo(outVal);
+    return outVal;
+  }
+}
+
+public partial class SymmetryBreakerVector: IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IList<SymmetryBreaker>
+#endif
+{
+  // cast from C# SymmetryBreaker array
+  public static implicit operator SymmetryBreakerVector(SymmetryBreaker[] inVal) {
+    var outVal= new SymmetryBreakerVector();
+    foreach (SymmetryBreaker element in inVal) {
+      outVal.Add(element);
+    }
+    return outVal;
+  }
+
+  // cast to C# SymmetryBreaker array
+  public static implicit operator SymmetryBreaker[](SymmetryBreakerVector inVal) {
+    var outVal= new SymmetryBreaker[inVal.Count];
+    inVal.CopyTo(outVal);
+    return outVal;
+  }
+}
+}  // namespace Google.OrTools.ConstraintSolver
diff --git a/ortools/dotnet/OrTools/constraintsolver/IntervalVarArrayHelper.cs b/ortools/dotnet/OrTools/constraintsolver/IntervalVarArrayHelper.cs
new file mode 100644
index 00000000000..b78d1b46a62
--- /dev/null
+++ b/ortools/dotnet/OrTools/constraintsolver/IntervalVarArrayHelper.cs
@@ -0,0 +1,53 @@
+// Copyright 2010-2017 Google
+// 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.ConstraintSolver
+{
+  using System;
+  using System.Collections.Generic;
+
+  // IntervalVar[] helper class.
+  public static class IntervalVarArrayHelper
+  {
+    // get solver from array of interval variables
+    private static Solver GetSolver(IntervalVar[] vars)
+    {
+      if (vars == null || vars.Length <= 0)
+        throw new ArgumentException("Array <vars> cannot be null or empty");
+
+      return vars[0].solver();
+    }
+    public static DisjunctiveConstraint Disjunctive(this IntervalVar[] vars,
+                                                    String name)
+    {
+      Solver solver = GetSolver(vars);
+      return solver.MakeDisjunctiveConstraint(vars, name);
+    }
+    public static Constraint Cumulative(this IntervalVar[] vars,
+                                        long[] demands,
+                                        long capacity,
+                                        String name)
+    {
+      Solver solver = GetSolver(vars);
+      return solver.MakeCumulative(vars, demands, capacity, name);
+    }
+    public static Constraint Cumulative(this IntervalVar[] vars,
+                                        int[] demands,
+                                        long capacity,
+                                        String name)
+    {
+      Solver solver = GetSolver(vars);
+      return solver.MakeCumulative(vars, demands, capacity, name);
+    }
+  }
+}  // namespace Google.OrTools.ConstraintSolver
diff --git a/ortools/dotnet/OrTools/constraintsolver/NetDecisionBuilder.cs b/ortools/dotnet/OrTools/constraintsolver/NetDecisionBuilder.cs
new file mode 100644
index 00000000000..9c3ee0c9357
--- /dev/null
+++ b/ortools/dotnet/OrTools/constraintsolver/NetDecisionBuilder.cs
@@ -0,0 +1,205 @@
+// Copyright 2010-2017 Google
+// 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.
+
+using System;
+using System.Collections;
+
+namespace Google.OrTools.ConstraintSolver
+{
+/**
+ * This class acts as a intermediate step between a c++ decision builder and a
+ * .Net one. Its main purpose is to catch the .Net application exception
+ * launched when a failure occurs during the Next() call, and to return
+ * silently a System.ApplicationException that will propagate the failure back
+ * to the C++ code.
+ *
+ */
+public class NetDecisionBuilder : DecisionBuilder
+{
+  /**
+   * This methods wraps the calls to next() and catches fail exceptions.
+   * It currently catches all application exceptions.
+   */
+  public override Decision NextWrapper(Solver solver)
+  {
+    try
+    {
+      return Next(solver);
+    }
+    catch (ApplicationException e)
+    {
+      // TODO(user): Catch only fail exceptions.
+      return solver.MakeFailDecision();
+    }
+  }
+  /**
+   * This is the new method to subclass when defining a .Net decision builder.
+   */
+  public virtual Decision Next(Solver solver)
+  {
+    return null;
+  }
+}
+
+/**
+ * This class acts as a intermediate step between a c++ decision and a
+ * .Net one. Its main purpose is to catch the .Net application
+ * exception launched when a failure occurs during the
+ * Apply()/Refute() calls, and to set the ShouldFail() flag on the
+ * solver that will propagate the failure back to the C++ code.
+ *
+ */
+public class NetDecision : Decision
+{
+  /**
+   * This methods wraps the calls to Apply() and catches fail exceptions.
+   * It currently catches all application exceptions.
+   */
+  public override void ApplyWrapper(Solver solver)
+  {
+    try
+    {
+      Apply(solver);
+    }
+    catch (ApplicationException e)
+    {
+      // TODO(user): Catch only fail exceptions.
+      solver.ShouldFail();
+    }
+  }
+  /**
+   * This is a new method to subclass when defining a .Net decision.
+   */
+  public virtual void Apply(Solver solver)
+  {
+    // By default, do nothing
+  }
+
+  public override void RefuteWrapper(Solver solver)
+  {
+    try
+    {
+      Refute(solver);
+    }
+    catch (ApplicationException e)
+    {
+      // TODO(user): Catch only fail exceptions.
+      solver.ShouldFail();
+    }
+  }
+  /**
+   * This is a new method to subclass when defining a .Net decision.
+   */
+  public virtual void Refute(Solver solver)
+  {
+  }
+}
+
+public class NetDemon : Demon
+{
+  /**
+   * This methods wraps the calls to next() and catches fail exceptions.
+   */
+  public override void RunWrapper(Solver solver)
+  {
+    try
+    {
+      Run(solver);
+    }
+    catch (ApplicationException e)
+    {
+      // TODO(user): Check that this is indeed a fail. Try implementing
+      // custom exceptions (hard).
+      solver.ShouldFail();
+    }
+  }
+  /**
+   * This is the new method to subclass when defining a .Net decision builder.
+   */
+  public virtual void Run(Solver solver) {}
+  public override int Priority() {
+    return Solver.NORMAL_PRIORITY;
+  }
+  public override string ToString() {
+    return "NetDemon";
+  }
+}
+
+public class NetConstraint : Constraint {
+  public NetConstraint(Solver s) : base(s) {}
+
+  public override void InitialPropagateWrapper() {
+    try {
+      InitialPropagate();
+    } catch (ApplicationException e) {
+      solver().ShouldFail();
+    }
+  }
+  public virtual void InitialPropagate() {}
+  public override string ToString() {
+    return "NetConstraint";
+  }
+}
+
+public class IntVarEnumerator : IEnumerator {
+  private IntVarIterator iterator_;
+
+  // Enumerators are positioned before the first element
+  // until the first MoveNext() call.
+  private bool first_ = true;
+
+  public IntVarEnumerator(IntVarIterator iterator) {
+    iterator_ = iterator;
+  }
+
+  public bool MoveNext() {
+    if (first_) {
+      iterator_.Init();
+      first_ = false;
+    } else {
+      iterator_.Next();
+    }
+    return iterator_.Ok();
+  }
+
+  public void Reset() {
+    first_ = true;
+  }
+
+  object IEnumerator.Current {
+    get {
+      return Current;
+    }
+  }
+
+  public long Current {
+    get {
+      if (!first_ && iterator_.Ok()) {
+        return iterator_.Value();
+      } else {
+        throw new InvalidOperationException();
+      }
+    }
+  }
+}
+
+public partial class IntVarIterator : BaseObject, IEnumerable {
+  IEnumerator IEnumerable.GetEnumerator() {
+    return (IEnumerator) GetEnumerator();
+  }
+
+  public IntVarEnumerator GetEnumerator() {
+    return new IntVarEnumerator(this);
+  }
+}
+}  // namespace Google.OrTools.ConstraintSolver
diff --git a/ortools/dotnet/OrTools/constraintsolver/SolverHelper.cs b/ortools/dotnet/OrTools/constraintsolver/SolverHelper.cs
new file mode 100644
index 00000000000..bf11a4b2520
--- /dev/null
+++ b/ortools/dotnet/OrTools/constraintsolver/SolverHelper.cs
@@ -0,0 +1,517 @@
+// Copyright 2010-2017 Google
+// 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.ConstraintSolver {
+using System;
+using System.Collections.Generic;
+
+public partial class Solver : IDisposable {
+  public IntVar[] MakeIntVarArray(int count, long min, long max) {
+    IntVar[] array = new IntVar[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeIntVar(min, max);
+    }
+    return array;
+  }
+
+  public IntVar[] MakeIntVarArray(int count, long min, long max, string name) {
+    IntVar[] array = new IntVar[count];
+    for (int i = 0; i < count; ++i) {
+      string var_name = name + i;
+      array[i] = MakeIntVar(min, max, var_name);
+    }
+    return array;
+  }
+
+  public IntVar[] MakeIntVarArray(int count, long[] values) {
+    IntVar[] array = new IntVar[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeIntVar(values);
+    }
+    return array;
+  }
+
+  public IntVar[] MakeIntVarArray(int count, long[] values, string name) {
+    IntVar[] array = new IntVar[count];
+    for (int i = 0; i < count; ++i) {
+      string var_name = name + i;
+      array[i] = MakeIntVar(values, var_name);
+    }
+    return array;
+  }
+
+  public IntVar[] MakeIntVarArray(int count, int[] values) {
+    IntVar[] array = new IntVar[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeIntVar(values);
+    }
+    return array;
+  }
+
+  public IntVar[] MakeIntVarArray(int count, int[] values, string name) {
+    IntVar[] array = new IntVar[count];
+    for (int i = 0; i < count; ++i) {
+      string var_name = name + i;
+      array[i] = MakeIntVar(values, var_name);
+    }
+    return array;
+  }
+
+  public IntVar[] MakeBoolVarArray(int count) {
+    IntVar[] array = new IntVar[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeBoolVar();
+    }
+    return array;
+  }
+
+  public IntVar[] MakeBoolVarArray(int count, string name) {
+    IntVar[] array = new IntVar[count];
+    for (int i = 0; i < count; ++i) {
+      string var_name = name + i;
+      array[i] = MakeBoolVar(var_name);
+    }
+    return array;
+  }
+
+  public IntVar[,] MakeIntVarMatrix(int rows, int cols, long min, long max) {
+    IntVar[,] array = new IntVar[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        array[i,j] = MakeIntVar(min, max);
+      }
+    }
+    return array;
+  }
+
+  public IntVar[,] MakeIntVarMatrix(int rows, int cols,
+                                    long min, long max, string name) {
+    IntVar[,] array = new IntVar[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        string var_name = name + "["+ i + ", " + j +"]";
+        array[i,j] = MakeIntVar(min, max, var_name);
+      }
+    }
+    return array;
+  }
+
+  public IntVar[,] MakeIntVarMatrix(int rows, int cols, long[] values) {
+    IntVar[,] array = new IntVar[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        array[i,j] = MakeIntVar(values);
+      }
+    }
+    return array;
+  }
+
+  public IntVar[,] MakeIntVarMatrix(int rows, int cols,
+                                    long[] values, string name) {
+    IntVar[,] array = new IntVar[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        string var_name = name + "["+ i + ", " + j +"]";
+        array[i,j] = MakeIntVar(values, var_name);
+      }
+    }
+    return array;
+  }
+
+  public IntVar[,] MakeIntVarMatrix(int rows, int cols, int[] values) {
+    IntVar[,] array = new IntVar[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        array[i,j] = MakeIntVar(values);
+      }
+    }
+    return array;
+  }
+
+  public IntVar[,] MakeIntVarMatrix(int rows, int cols,
+                                    int[] values, string name) {
+    IntVar[,] array = new IntVar[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        string var_name = name + "["+ i + ", " + j +"]";
+        array[i,j] = MakeIntVar(values, var_name);
+      }
+    }
+    return array;
+  }
+
+  public IntVar[,] MakeBoolVarMatrix(int rows, int cols) {
+    IntVar[,] array = new IntVar[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        array[i,j] = MakeBoolVar();
+      }
+    }
+    return array;
+  }
+
+  public IntVar[,] MakeBoolVarMatrix(int rows, int cols, string name) {
+    IntVar[,] array = new IntVar[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        string var_name = name + "["+ i + ", " + j +"]";
+        array[i,j] = MakeBoolVar(var_name);
+      }
+    }
+    return array;
+  }
+
+  public IntervalVar[] MakeFixedDurationIntervalVarArray(int count,
+                                                         long start_min,
+                                                         long start_max,
+                                                         long duration,
+                                                         bool optional) {
+    IntervalVar[] array = new IntervalVar[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeFixedDurationIntervalVar(start_min,
+                                              start_max,
+                                              duration,
+                                              optional,
+                                              "");
+    }
+    return array;
+  }
+
+  public IntervalVar[] MakeFixedDurationIntervalVarArray(int count,
+                                                         long start_min,
+                                                         long start_max,
+                                                         long duration,
+                                                         bool optional,
+                                                         string name) {
+    IntervalVar[] array = new IntervalVar[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeFixedDurationIntervalVar(start_min,
+                                              start_max,
+                                              duration,
+                                              optional,
+                                              name + i);
+    }
+    return array;
+  }
+
+  public IntervalVar[] MakeFixedDurationIntervalVarArray(int count,
+                                                         long[] start_min,
+                                                         long[] start_max,
+                                                         long[] duration,
+                                                         bool optional,
+                                                         string name) {
+    IntervalVar[] array = new IntervalVar[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeFixedDurationIntervalVar(start_min[i],
+                                              start_max[i],
+                                              duration[i],
+                                              optional,
+                                              name + i);
+    }
+    return array;
+  }
+
+  public IntervalVar[] MakeFixedDurationIntervalVarArray(int count,
+                                                         int[] start_min,
+                                                         int[] start_max,
+                                                         int[] duration,
+                                                         bool optional,
+                                                         string name) {
+    IntervalVar[] array = new IntervalVar[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeFixedDurationIntervalVar(start_min[i],
+                                              start_max[i],
+                                              duration[i],
+                                              optional,
+                                              name + i);
+    }
+    return array;
+  }
+  public IntervalVar[] MakeFixedDurationIntervalVarArray(IntVar[] starts,
+                                                         int[] durations,
+                                                         string name) {
+    int count = starts.Length;
+    IntervalVar[] array = new IntervalVar[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeFixedDurationIntervalVar(starts[i],
+                                              durations[i],
+                                              name + i);
+    }
+    return array;
+  }
+  public IntervalVar[] MakeFixedDurationIntervalVarArray(IntVar[] starts,
+                                                         long[] durations,
+                                                         string name) {
+    int count = starts.Length;
+    IntervalVar[] array = new IntervalVar[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeFixedDurationIntervalVar(starts[i],
+                                              durations[i],
+                                              name + i);
+    }
+    return array;
+  }
+  public void NewSearch(DecisionBuilder db) {
+    pinned_decision_builder_ = db;
+    pinned_search_monitors_.Clear();
+    NewSearchAux(db);
+  }
+
+  public void NewSearch(DecisionBuilder db, SearchMonitor sm1) {
+    pinned_decision_builder_ = db;
+    pinned_search_monitors_.Clear();
+    pinned_search_monitors_.Add(sm1);
+    NewSearchAux(db, sm1);
+  }
+
+
+  public void NewSearch(DecisionBuilder db,
+                        SearchMonitor sm1,
+                        SearchMonitor sm2) {
+    pinned_decision_builder_ = db;
+    pinned_search_monitors_.Clear();
+    pinned_search_monitors_.Add(sm1);
+    pinned_search_monitors_.Add(sm2);
+    NewSearchAux(db, sm1, sm2);
+  }
+
+  public void NewSearch(DecisionBuilder db,
+                        SearchMonitor sm1,
+                        SearchMonitor sm2,
+                        SearchMonitor sm3) {
+    pinned_decision_builder_ = db;
+    pinned_search_monitors_.Clear();
+    pinned_search_monitors_.Add(sm1);
+    pinned_search_monitors_.Add(sm2);
+    pinned_search_monitors_.Add(sm3);
+    NewSearchAux(db, sm1, sm2, sm3);
+  }
+
+  public void NewSearch(DecisionBuilder db,
+                        SearchMonitor sm1,
+                        SearchMonitor sm2,
+                        SearchMonitor sm3,
+                        SearchMonitor sm4) {
+    pinned_decision_builder_ = db;
+    pinned_search_monitors_.Clear();
+    pinned_search_monitors_.Add(sm1);
+    pinned_search_monitors_.Add(sm2);
+    pinned_search_monitors_.Add(sm3);
+    pinned_search_monitors_.Add(sm4);
+    NewSearchAux(db, sm1, sm2, sm3, sm4);
+  }
+
+  public void NewSearch(DecisionBuilder db, SearchMonitor[] monitors) {
+    pinned_decision_builder_ = db;
+    pinned_search_monitors_.Clear();
+    pinned_search_monitors_.AddRange(monitors);
+    NewSearchAux(db, monitors);
+  }
+
+  public void EndSearch() {
+    pinned_decision_builder_ = null;
+    pinned_search_monitors_.Clear();
+    EndSearchAux();
+  }
+
+  private System.Collections.Generic.List<SearchMonitor> pinned_search_monitors_
+      = new System.Collections.Generic.List<SearchMonitor>();
+  private DecisionBuilder pinned_decision_builder_;
+}
+
+public partial class IntExpr : PropagationBaseObject {
+  public static IntExpr operator+(IntExpr a, IntExpr b) {
+    return a.solver().MakeSum(a, b);
+  }
+  public static IntExpr operator+(IntExpr a, long v) {
+    return a.solver().MakeSum(a, v);
+  }
+  public static IntExpr operator+(long v, IntExpr a) {
+    return a.solver().MakeSum(a, v);
+  }
+  public static IntExpr operator-(IntExpr a, IntExpr b) {
+    return a.solver().MakeDifference(a, b);
+  }
+  public static IntExpr operator-(IntExpr a, long v) {
+    return a.solver().MakeSum(a, -v);
+  }
+  public static IntExpr operator-(long v, IntExpr a) {
+    return a.solver().MakeDifference(v, a);
+  }
+  public static IntExpr operator*(IntExpr a, IntExpr b) {
+    return a.solver().MakeProd(a, b);
+  }
+  public static IntExpr operator*(IntExpr a, long v) {
+    return a.solver().MakeProd(a, v);
+  }
+  public static IntExpr operator*(long v, IntExpr a) {
+    return a.solver().MakeProd(a, v);
+  }
+  public static IntExpr operator/(IntExpr a, long v) {
+    return a.solver().MakeDiv(a, v);
+  }
+  public static IntExpr operator%(IntExpr a, long v) {
+    return a.solver().MakeModulo(a, v);
+  }
+  public static IntExpr operator-(IntExpr a) {
+    return a.solver().MakeOpposite(a);
+  }
+  public IntExpr Abs() {
+    return this.solver().MakeAbs(this);
+  }
+  public IntExpr Square() {
+    return this.solver().MakeSquare(this);
+  }
+  public static IntExprEquality operator ==(IntExpr a, IntExpr b) {
+    return new IntExprEquality(a, b, true);
+  }
+  public static IntExprEquality operator !=(IntExpr a, IntExpr b) {
+    return new IntExprEquality(a, b, false);
+  }
+  public static WrappedConstraint operator ==(IntExpr a, long v) {
+    return new WrappedConstraint(a.solver().MakeEquality(a, v));
+  }
+  public static WrappedConstraint operator !=(IntExpr a, long v) {
+    return new WrappedConstraint(a.solver().MakeNonEquality(a.Var(), v));
+  }
+  public static WrappedConstraint operator >=(IntExpr a, long v) {
+    return new WrappedConstraint(a.solver().MakeGreaterOrEqual(a, v));
+  }
+  public static WrappedConstraint operator >(IntExpr a, long v) {
+    return new WrappedConstraint(a.solver().MakeGreater(a, v));
+  }
+  public static WrappedConstraint operator <=(IntExpr a, long v) {
+    return new WrappedConstraint(a.solver().MakeLessOrEqual(a, v));
+  }
+  public static WrappedConstraint operator <(IntExpr a, long v) {
+    return new WrappedConstraint(a.solver().MakeLess(a, v));
+  }
+  public static WrappedConstraint operator >=(IntExpr a, IntExpr b) {
+    return new WrappedConstraint(a.solver().MakeGreaterOrEqual(a.Var(), b.Var()));
+  }
+  public static WrappedConstraint operator >(IntExpr a, IntExpr b) {
+    return new WrappedConstraint(a.solver().MakeGreater(a.Var(), b.Var()));
+  }
+  public static WrappedConstraint operator <=(IntExpr a, IntExpr b) {
+    return new WrappedConstraint(a.solver().MakeLessOrEqual(a.Var(), b.Var()));
+  }
+  public static WrappedConstraint operator <(IntExpr a, IntExpr b) {
+    return new WrappedConstraint(a.solver().MakeLess(a.Var(), b.Var()));
+  }
+}
+
+public partial class Constraint : PropagationBaseObject, IConstraintWithStatus {
+  public static implicit operator IntVar(Constraint eq)
+  {
+    return eq.Var();
+  }
+
+  public static implicit operator IntExpr(Constraint eq)
+  {
+    return eq.Var();
+  }
+  public static IntExpr operator+(Constraint a, Constraint b) {
+    return a.solver().MakeSum(a.Var(), b.Var());
+  }
+  public static IntExpr operator+(Constraint a, long v) {
+    return a.solver().MakeSum(a.Var(), v);
+  }
+  public static IntExpr operator+(long v, Constraint a) {
+    return a.solver().MakeSum(a.Var(), v);
+  }
+  public static IntExpr operator-(Constraint a, Constraint b) {
+    return a.solver().MakeDifference(a.Var(), b.Var());
+  }
+  public static IntExpr operator-(Constraint a, long v) {
+    return a.solver().MakeSum(a.Var(), -v);
+  }
+  public static IntExpr operator-(long v, Constraint a) {
+    return a.solver().MakeDifference(v, a.Var());
+  }
+  public static IntExpr operator*(Constraint a, Constraint b) {
+    return a.solver().MakeProd(a.Var(), b.Var());
+  }
+  public static IntExpr operator*(Constraint a, long v) {
+    return a.solver().MakeProd(a.Var(), v);
+  }
+  public static IntExpr operator*(long v, Constraint a) {
+    return a.solver().MakeProd(a.Var(), v);
+  }
+  public static IntExpr operator/(Constraint a, long v) {
+    return a.solver().MakeDiv(a.Var(), v);
+  }
+  public static IntExpr operator-(Constraint a) {
+    return a.solver().MakeOpposite(a.Var());
+  }
+  public IntExpr Abs() {
+    return this.solver().MakeAbs(this.Var());
+  }
+  public IntExpr Square() {
+    return this.solver().MakeSquare(this.Var());
+  }
+  public static WrappedConstraint operator ==(Constraint a, long v) {
+    return new WrappedConstraint(a.solver().MakeEquality(a.Var(), v));
+  }
+  public static WrappedConstraint operator ==(long v, Constraint a) {
+    return new WrappedConstraint(a.solver().MakeEquality(a.Var(), v));
+  }
+  public static WrappedConstraint operator !=(Constraint a, long v) {
+    return new WrappedConstraint(a.solver().MakeNonEquality(a.Var(), v));
+  }
+  public static WrappedConstraint operator !=(long v, Constraint a) {
+    return new WrappedConstraint(a.solver().MakeNonEquality(a.Var(), v));
+  }
+  public static WrappedConstraint operator >=(Constraint a, long v) {
+    return new WrappedConstraint(a.solver().MakeGreaterOrEqual(a.Var(), v));
+  }
+  public static WrappedConstraint operator >=(long v, Constraint a) {
+    return new WrappedConstraint(a.solver().MakeLessOrEqual(a.Var(), v));
+  }
+  public static WrappedConstraint operator >(Constraint a, long v) {
+    return new WrappedConstraint(a.solver().MakeGreater(a.Var(), v));
+  }
+  public static WrappedConstraint operator >(long v, Constraint a) {
+    return new WrappedConstraint(a.solver().MakeLess(a.Var(), v));
+  }
+  public static WrappedConstraint operator <=(Constraint a, long v) {
+    return new WrappedConstraint(a.solver().MakeLessOrEqual(a.Var(), v));
+  }
+  public static WrappedConstraint operator <=(long v, Constraint a) {
+    return new WrappedConstraint(a.solver().MakeGreaterOrEqual(a.Var(), v));
+  }
+  public static WrappedConstraint operator <(Constraint a, long v) {
+    return new WrappedConstraint(a.solver().MakeLess(a.Var(), v));
+  }
+  public static WrappedConstraint operator <(long v, Constraint a) {
+    return new WrappedConstraint(a.solver().MakeGreater(a.Var(), v));
+  }
+  public static WrappedConstraint operator >=(Constraint a, Constraint b) {
+    return new WrappedConstraint(a.solver().MakeGreaterOrEqual(a.Var(), b.Var()));
+  }
+  public static WrappedConstraint operator >(Constraint a, Constraint b) {
+    return new WrappedConstraint(a.solver().MakeGreater(a.Var(), b.Var()));
+  }
+  public static WrappedConstraint operator <=(Constraint a, Constraint b) {
+    return new WrappedConstraint(a.solver().MakeLessOrEqual(a.Var(), b.Var()));
+  }
+  public static WrappedConstraint operator <(Constraint a, Constraint b) {
+    return new WrappedConstraint(a.solver().MakeLess(a.Var(), b.Var()));
+  }
+  public static ConstraintEquality operator ==(Constraint a, Constraint b) {
+    return new ConstraintEquality(a, b, true);
+  }
+  public static ConstraintEquality operator !=(Constraint a, Constraint b) {
+    return new ConstraintEquality(a, b, false);
+  }
+}
+}  // namespace Google.OrTools.ConstraintSolver
diff --git a/ortools/dotnet/OrTools/constraintsolver/ValCstPair.cs b/ortools/dotnet/OrTools/constraintsolver/ValCstPair.cs
new file mode 100644
index 00000000000..b964a05ae65
--- /dev/null
+++ b/ortools/dotnet/OrTools/constraintsolver/ValCstPair.cs
@@ -0,0 +1,300 @@
+// Copyright 2010-2017 Google
+// 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.ConstraintSolver
+{
+using System;
+using System.Collections.Generic;
+
+public interface IConstraintWithStatus
+{
+  Solver solver();
+  IntVar Var();
+}
+
+public abstract class BaseEquality : IConstraintWithStatus
+{
+  abstract public Solver solver();
+  abstract public IntVar Var();
+
+  public static IntExpr operator+(BaseEquality a, BaseEquality b) {
+    return a.solver().MakeSum(a.Var(), b.Var());
+  }
+  public static IntExpr operator+(BaseEquality a, long v) {
+    return a.solver().MakeSum(a.Var(), v);
+  }
+  public static IntExpr operator+(long v, BaseEquality a) {
+    return a.solver().MakeSum(a.Var(), v);
+  }
+  public static IntExpr operator-(BaseEquality a, BaseEquality b) {
+    return a.solver().MakeDifference(a.Var(), b.Var());
+  }
+  public static IntExpr operator-(BaseEquality a, long v) {
+    return a.solver().MakeSum(a.Var(), -v);
+  }
+  public static IntExpr operator-(long v, BaseEquality a) {
+    return a.solver().MakeDifference(v, a.Var());
+  }
+  public static IntExpr operator*(BaseEquality a, BaseEquality b) {
+    return a.solver().MakeProd(a.Var(), b.Var());
+  }
+  public static IntExpr operator*(BaseEquality a, long v) {
+    return a.solver().MakeProd(a.Var(), v);
+  }
+  public static IntExpr operator*(long v, BaseEquality a) {
+    return a.solver().MakeProd(a.Var(), v);
+  }
+  public static IntExpr operator/(BaseEquality a, long v) {
+    return a.solver().MakeDiv(a.Var(), v);
+  }
+  public static IntExpr operator-(BaseEquality a) {
+    return a.solver().MakeOpposite(a.Var());
+  }
+  public IntExpr Abs() {
+    return this.solver().MakeAbs(this.Var());
+  }
+  public IntExpr Square() {
+    return this.solver().MakeSquare(this.Var());
+  }
+  public static WrappedConstraint operator ==(BaseEquality a, long v) {
+    return new WrappedConstraint(a.solver().MakeEquality(a.Var(), v));
+  }
+  public static WrappedConstraint operator ==(long v, BaseEquality a) {
+    return new WrappedConstraint(a.solver().MakeEquality(a.Var(), v));
+  }
+  public static WrappedConstraint operator !=(BaseEquality a, long v) {
+    return new WrappedConstraint(a.solver().MakeNonEquality(a.Var(), v));
+  }
+  public static WrappedConstraint operator !=(long v, BaseEquality a) {
+    return new WrappedConstraint(a.solver().MakeNonEquality(a.Var(), v));
+  }
+  public static WrappedConstraint operator >=(BaseEquality a, long v) {
+    return new WrappedConstraint(a.solver().MakeGreaterOrEqual(a.Var(), v));
+  }
+  public static WrappedConstraint operator >=(long v, BaseEquality a) {
+    return new WrappedConstraint(a.solver().MakeLessOrEqual(a.Var(), v));
+  }
+  public static WrappedConstraint operator >(BaseEquality a, long v) {
+    return new WrappedConstraint(a.solver().MakeGreater(a.Var(), v));
+  }
+  public static WrappedConstraint operator >(long v, BaseEquality a) {
+    return new WrappedConstraint(a.solver().MakeLess(a.Var(), v));
+  }
+  public static WrappedConstraint operator <=(BaseEquality a, long v) {
+    return new WrappedConstraint(a.solver().MakeLessOrEqual(a.Var(), v));
+  }
+  public static WrappedConstraint operator <=(long v, BaseEquality a) {
+    return new WrappedConstraint(a.solver().MakeGreaterOrEqual(a.Var(), v));
+  }
+  public static WrappedConstraint operator <(BaseEquality a, long v) {
+    return new WrappedConstraint(a.solver().MakeLess(a.Var(), v));
+  }
+  public static WrappedConstraint operator <(long v, BaseEquality a) {
+    return new WrappedConstraint(a.solver().MakeGreater(a.Var(), v));
+  }
+  public static WrappedConstraint operator >=(BaseEquality a, BaseEquality b) {
+    return new WrappedConstraint(a.solver().MakeGreaterOrEqual(a.Var(),
+                                 b.Var()));
+  }
+  public static WrappedConstraint operator >(BaseEquality a, BaseEquality b) {
+    return new WrappedConstraint(a.solver().MakeGreater(a.Var(), b.Var()));
+  }
+  public static WrappedConstraint operator <=(BaseEquality a, BaseEquality b) {
+    return new WrappedConstraint(a.solver().MakeLessOrEqual(a.Var(), b.Var()));
+  }
+  public static WrappedConstraint operator <(BaseEquality a, BaseEquality b) {
+    return new WrappedConstraint(a.solver().MakeLess(a.Var(), b.Var()));
+  }
+  public static ConstraintEquality operator ==(BaseEquality a, BaseEquality b) {
+    return new ConstraintEquality(a, b, true);
+  }
+  public static ConstraintEquality operator !=(BaseEquality a, BaseEquality b) {
+    return new ConstraintEquality(a, b, false);
+  }
+}
+
+public class WrappedConstraint : BaseEquality
+{
+  public bool Val { get; set; }
+
+  public Constraint Cst { get; set; }
+
+  public WrappedConstraint(Constraint cst) : this(true, cst) {}
+
+  public WrappedConstraint(bool val) : this(val, null) {}
+
+  public WrappedConstraint(bool val, Constraint cst)
+  {
+    this.Val = val;
+    this.Cst = cst;
+  }
+
+  public static implicit operator bool(WrappedConstraint valCstPair)
+  {
+    return valCstPair.Val;
+  }
+
+  public static implicit operator Constraint(WrappedConstraint valCstPair)
+  {
+    return valCstPair.Cst;
+  }
+
+  public static implicit operator IntVar(WrappedConstraint eq)
+  {
+    return eq.Var();
+  }
+
+  public static implicit operator IntExpr(WrappedConstraint eq)
+  {
+    return eq.Var();
+  }
+
+  public override Solver solver()
+  {
+    return this.Cst.solver();
+  }
+
+  public override IntVar Var()
+  {
+    return Cst.Var();
+  }
+}
+
+public class IntExprEquality : BaseEquality
+{
+  public IntExprEquality(IntExpr a, IntExpr b, bool equality)
+  {
+    this.left_ = a;
+    this.right_ = b;
+    this.equality_ = equality;
+  }
+
+  bool IsTrue()
+  {
+    return (object)left_ == (object)right_ ? equality_ : !equality_;
+  }
+
+  Constraint ToConstraint()
+  {
+    return equality_ ?
+        left_.solver().MakeEquality(left_.Var(), right_.Var()) :
+        left_.solver().MakeNonEquality(left_.Var(), right_.Var());
+  }
+
+  public static bool operator true(IntExprEquality eq)
+  {
+    return eq.IsTrue();
+  }
+
+  public static bool operator false(IntExprEquality eq)
+  {
+    return !eq.IsTrue();
+  }
+
+  public static implicit operator Constraint(IntExprEquality eq)
+  {
+    return eq.ToConstraint();
+  }
+
+  public override IntVar Var()
+  {
+    return equality_ ?
+        left_.solver().MakeIsEqualVar(left_, right_) :
+        left_.solver().MakeIsDifferentVar(left_, right_);
+  }
+
+  public static implicit operator IntVar(IntExprEquality eq)
+  {
+    return eq.Var();
+  }
+
+  public static implicit operator IntExpr(IntExprEquality eq)
+  {
+    return eq.Var();
+  }
+
+  public override Solver solver()
+  {
+    return left_.solver();
+  }
+
+  private IntExpr left_;
+  private IntExpr right_;
+  private bool equality_;
+}
+
+public class ConstraintEquality : BaseEquality
+{
+  public ConstraintEquality(IConstraintWithStatus a,
+                            IConstraintWithStatus b,
+                            bool equality)
+  {
+    this.left_ = a;
+    this.right_ = b;
+    this.equality_ = equality;
+  }
+
+  bool IsTrue()
+  {
+    return (object)left_ == (object)right_ ? equality_ : !equality_;
+  }
+
+  Constraint ToConstraint()
+  {
+    return equality_ ?
+        left_.solver().MakeEquality(left_.Var(), right_.Var()) :
+        left_.solver().MakeNonEquality(left_.Var(), right_.Var());
+  }
+
+  public static bool operator true(ConstraintEquality eq)
+  {
+    return eq.IsTrue();
+  }
+
+  public static bool operator false(ConstraintEquality eq)
+  {
+    return !eq.IsTrue();
+  }
+
+  public static implicit operator Constraint(ConstraintEquality eq)
+  {
+    return eq.ToConstraint();
+  }
+
+  public override IntVar Var()
+  {
+    return equality_ ?
+        left_.solver().MakeIsEqualVar(left_.Var(), right_.Var()) :
+        left_.solver().MakeIsDifferentVar(left_.Var(), right_.Var());
+  }
+
+  public static implicit operator IntVar(ConstraintEquality eq)
+  {
+    return eq.Var();
+  }
+
+  public static implicit operator IntExpr(ConstraintEquality eq)
+  {
+    return eq.Var();
+  }
+
+  public override Solver solver()
+  {
+    return left_.solver();
+  }
+
+  private IConstraintWithStatus left_;
+  private IConstraintWithStatus right_;
+  private bool equality_;
+}
+}  // namespace Google.OrTools.ConstraintSolver
diff --git a/ortools/dotnet/OrTools/linearsolver/DoubleArrayHelper.cs b/ortools/dotnet/OrTools/linearsolver/DoubleArrayHelper.cs
new file mode 100644
index 00000000000..829ce269c06
--- /dev/null
+++ b/ortools/dotnet/OrTools/linearsolver/DoubleArrayHelper.cs
@@ -0,0 +1,40 @@
+// Copyright 2010-2017 Google
+// 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.LinearSolver {
+using System;
+using System.Collections.Generic;
+
+// double[] helper class.
+public partial class MpDoubleVector: IDisposable, System.Collections.IEnumerable
+#if !SWIG_DOTNET_1
+    , System.Collections.Generic.IList<double>
+#endif
+{
+  // cast from C# double array
+  public static implicit operator MpDoubleVector(double[] inVal) {
+    var outVal= new MpDoubleVector();
+    foreach (double element in inVal) {
+      outVal.Add(element);
+    }
+    return outVal;
+  }
+
+  // cast to C# double array
+  public static implicit operator double[](MpDoubleVector inVal) {
+    var outVal= new double[inVal.Count];
+    inVal.CopyTo(outVal);
+    return outVal;
+  }
+}
+}  // namespace Google.OrTools.LinearSolver
diff --git a/ortools/dotnet/OrTools/linearsolver/LinearConstraint.cs b/ortools/dotnet/OrTools/linearsolver/LinearConstraint.cs
new file mode 100644
index 00000000000..3442ad5a335
--- /dev/null
+++ b/ortools/dotnet/OrTools/linearsolver/LinearConstraint.cs
@@ -0,0 +1,140 @@
+// Copyright 2010-2017 Google
+// 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.LinearSolver
+{
+  using System;
+  using System.Collections.Generic;
+
+public class LinearConstraint
+{
+
+  public virtual String ToString()
+  {
+    return "LinearConstraint";
+  }
+
+  public virtual Constraint Extract(Solver solver)
+  {
+    return null;
+  }
+}
+
+public class RangeConstraint : LinearConstraint
+{
+
+  public RangeConstraint(LinearExpr expr, double lb, double ub)
+  {
+    this.expr_ = expr;
+    this.lb_ = lb;
+    this.ub_ = ub;
+  }
+
+  public override String ToString()
+  {
+    return "" + lb_ + " <= " + expr_.ToString() + " <= " + ub_;
+  }
+
+  public override Constraint Extract(Solver solver)
+  {
+    Dictionary<Variable, double> coefficients =
+        new Dictionary<Variable, double>();
+    double constant = expr_.Visit(coefficients);
+    Constraint ct = solver.MakeConstraint(lb_ - constant, ub_ - constant);
+    foreach (KeyValuePair<Variable, double> pair in coefficients)
+    {
+      ct.SetCoefficient(pair.Key, pair.Value);
+    }
+    return ct;
+  }
+
+  public static implicit operator bool(RangeConstraint ct)
+  {
+    return false;
+  }
+
+  private LinearExpr expr_;
+  private double lb_;
+  private double ub_;
+}
+
+public class Equality : LinearConstraint
+{
+  public Equality(LinearExpr left, LinearExpr right, bool equality)
+  {
+    this.left_ = left;
+    this.right_ = right;
+    this.equality_ = equality;
+  }
+
+  public override String ToString()
+  {
+    return "" + left_.ToString() + " == " + right_.ToString();
+  }
+
+  public override Constraint Extract(Solver solver)
+  {
+    Dictionary<Variable, double> coefficients =
+        new Dictionary<Variable, double>();
+    double constant = left_.Visit(coefficients);
+    constant += right_.DoVisit(coefficients, -1);
+    Constraint ct = solver.MakeConstraint(-constant, -constant);
+    foreach (KeyValuePair<Variable, double> pair in coefficients)
+    {
+      ct.SetCoefficient(pair.Key, pair.Value);
+    }
+    return ct;
+  }
+
+  public static implicit operator bool(Equality ct)
+  {
+    return (object)ct.left_ == (object)ct.right_ ? ct.equality_ : !ct.equality_;
+  }
+
+  private LinearExpr left_;
+  private LinearExpr right_;
+  private bool equality_;
+}
+
+public class VarEquality : LinearConstraint
+{
+  public VarEquality(Variable left, Variable right, bool equality)
+  {
+    this.left_ = left;
+    this.right_ = right;
+    this.equality_ = equality;
+  }
+
+  public override String ToString()
+  {
+    return "" + left_.Name() + " == " + right_.Name();
+  }
+
+  public override Constraint Extract(Solver solver)
+  {
+    Constraint ct = solver.MakeConstraint(0.0, 0.0);
+    ct.SetCoefficient(left_, 1.0);
+    ct.SetCoefficient(right_, -1.0);
+    return ct;
+  }
+
+  public static implicit operator bool(VarEquality ct)
+  {
+    return (object)ct.left_ == (object)ct.right_ ? ct.equality_ : !ct.equality_;
+  }
+
+  private Variable left_;
+  private Variable right_;
+  private bool equality_;
+}
+}  // namespace Google.OrTools.LinearSolver
diff --git a/ortools/dotnet/OrTools/linearsolver/LinearExpr.cs b/ortools/dotnet/OrTools/linearsolver/LinearExpr.cs
new file mode 100644
index 00000000000..7abded015ac
--- /dev/null
+++ b/ortools/dotnet/OrTools/linearsolver/LinearExpr.cs
@@ -0,0 +1,344 @@
+// Copyright 2010-2017 Google
+// 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.LinearSolver
+{
+  using System;
+  using System.Collections.Generic;
+
+public class LinearExpr
+{
+  public virtual double DoVisit(Dictionary<Variable, double> coefficients,
+                                double multiplier)
+  {
+    return 0;
+  }
+
+  public double Visit(Dictionary<Variable, double> coefficients)
+  {
+    return DoVisit(coefficients, 1.0);
+  }
+
+  public static LinearExpr operator+(LinearExpr a, double v)
+  {
+    return new SumCst(a, v);
+  }
+
+  public static LinearExpr operator+(double v, LinearExpr a)
+  {
+    return new SumCst(a, v);
+  }
+
+  public static LinearExpr operator+(LinearExpr a, LinearExpr b)
+  {
+    return new Sum(a, b);
+  }
+
+  public static LinearExpr operator-(LinearExpr a, double v)
+  {
+    return new SumCst(a, -v);
+  }
+
+  public static LinearExpr operator-(double v, LinearExpr a)
+  {
+    return new SumCst(new ProductCst(a, -1.0), v);
+  }
+
+  public static LinearExpr operator-(LinearExpr a, LinearExpr b)
+  {
+    return new Sum(a, new ProductCst(b, -1.0));
+  }
+
+  public static LinearExpr operator-(LinearExpr a)
+  {
+    return new ProductCst(a, -1.0);
+  }
+
+  public static LinearExpr operator*(LinearExpr a, double v)
+  {
+    return new ProductCst(a, v);
+  }
+
+  public static LinearExpr operator/(LinearExpr a, double v)
+  {
+    return new ProductCst(a, 1 / v);
+  }
+
+  public static LinearExpr operator*(double v, LinearExpr a)
+  {
+    return new ProductCst(a, v);
+  }
+
+  public static RangeConstraint operator==(LinearExpr a, double v)
+  {
+    return new RangeConstraint(a, v, v);
+  }
+
+  public static RangeConstraint operator==(double v, LinearExpr a)
+  {
+    return new RangeConstraint(a, v, v);
+  }
+
+  public static RangeConstraint operator!=(LinearExpr a, double v)
+  {
+    return new RangeConstraint(a, 1, -1);
+  }
+
+  public static RangeConstraint operator!=(double v, LinearExpr a)
+  {
+    return new RangeConstraint(a, 1, -1);
+  }
+
+  public static Equality operator==(LinearExpr a, LinearExpr b)
+  {
+    return new Equality(a, b, true);
+  }
+
+  public static Equality operator!=(LinearExpr a, LinearExpr b)
+  {
+    return new Equality(a, b, false);
+  }
+
+  public static RangeConstraint operator<=(LinearExpr a, double v)
+  {
+    return new RangeConstraint(a, double.NegativeInfinity, v);
+  }
+
+  public static RangeConstraint operator>=(LinearExpr a, double v)
+  {
+    return new RangeConstraint(a, v, double.PositiveInfinity);
+  }
+
+    public static RangeConstraint operator<=(LinearExpr a, LinearExpr b)
+  {
+    return a - b <= 0;
+  }
+
+  public static RangeConstraint operator>=(LinearExpr a, LinearExpr b)
+  {
+    return a - b >= 0;
+  }
+
+  public static implicit operator LinearExpr(Variable a)
+  {
+    return new VarWrapper(a);
+  }
+}
+
+public static class LinearExprArrayHelper
+{
+  public static LinearExpr Sum(this LinearExpr[] exprs)
+  {
+    return new SumArray(exprs);
+  }
+
+  public static LinearExpr Sum(this Variable[] vars)
+  {
+    return new SumVarArray(vars);
+  }
+}
+
+  // def __ge__(self, arg):
+  //   if isinstance(arg, (int, long, float)):
+  //     return LinearConstraint(self, arg, 1e308)
+  //   else:
+  //     return LinearConstraint(Sum(self, ProductCst(arg, -1)), 0.0, 1e308)
+
+  // def __le__(self, arg):
+  //   if isinstance(arg, (int, long, float)):
+  //     return LinearConstraint(self, -1e308, arg)
+  //   else:
+  //     return LinearConstraint(Sum(self, ProductCst(arg, -1)), -1e308, 0.0)
+
+
+class ProductCst : LinearExpr
+{
+  public ProductCst(LinearExpr expr, double coeff)
+  {
+    this.coeff_ = coeff;
+    this.expr_ = expr;
+  }
+
+  public override String ToString()
+  {
+    return "(" + expr_.ToString() + " * " + coeff_ + ")";
+  }
+
+  public override double DoVisit(Dictionary<Variable, double> coefficients,
+                                 double multiplier)
+  {
+    double current_multiplier = multiplier * coeff_;
+    if (current_multiplier != 0.0)
+    {
+      return expr_.DoVisit(coefficients, current_multiplier);
+    }
+    else
+    {
+      return 0.0;
+    }
+  }
+
+  private LinearExpr expr_;
+  private double coeff_;
+}
+
+class SumCst : LinearExpr
+{
+  public SumCst(LinearExpr expr, double coeff)
+  {
+    this.coeff_ = coeff;
+    this.expr_ = expr;
+  }
+
+  public override String ToString()
+  {
+    return "(" + expr_.ToString() + " + " + coeff_ + ")";
+  }
+
+  public override double DoVisit(Dictionary<Variable, double> coefficients,
+                                 double multiplier)
+  {
+    if (multiplier != 0.0)
+    {
+      return coeff_ * multiplier + expr_.DoVisit(coefficients, multiplier);
+    }
+    else
+    {
+      return 0.0;
+    }
+  }
+
+  private LinearExpr expr_;
+  private double coeff_;
+}
+
+class VarWrapper : LinearExpr
+{
+  public VarWrapper(Variable var)
+  {
+    this.var_ = var;
+  }
+
+  public override String ToString()
+  {
+    return var_.Name();
+  }
+
+  public override double DoVisit(Dictionary<Variable, double> coefficients,
+                                 double multiplier)
+  {
+    if (multiplier != 0.0)
+    {
+      if (coefficients.ContainsKey(var_))
+      {
+        coefficients[var_] += multiplier;
+      }
+      else
+      {
+        coefficients[var_] = multiplier;
+      }
+    }
+    return 0.0;
+  }
+
+  private Variable var_;
+}
+
+
+class Sum : LinearExpr
+{
+  public Sum(LinearExpr left, LinearExpr right)
+  {
+    this.left_ = left;
+    this.right_ = right;
+  }
+
+  public override String ToString()
+  {
+    return "(" + left_.ToString() + " + " + right_.ToString() + ")";
+  }
+
+  public override double DoVisit(Dictionary<Variable, double> coefficients,
+                                 double multiplier)
+  {
+    if (multiplier != 0.0)
+    {
+      return left_.DoVisit(coefficients, multiplier) +
+          right_.DoVisit(coefficients, multiplier);
+    }
+    else
+    {
+      return 0.0;
+    }
+  }
+
+  private LinearExpr left_;
+  private LinearExpr right_;
+}
+
+public class SumArray : LinearExpr
+{
+  public SumArray(LinearExpr[] array)
+  {
+    this.array_ = array;
+  }
+
+  public override double DoVisit(Dictionary<Variable, double> coefficients,
+                                 double multiplier) {
+    if (multiplier != 0.0)
+    {
+      double constant = 0.0;
+      foreach (LinearExpr expr in array_)
+      {
+        constant += expr.DoVisit(coefficients, multiplier);
+      }
+      return constant;
+    }
+    else
+    {
+      return 0.0;
+    }
+  }
+
+  private LinearExpr[] array_;
+}
+
+public class SumVarArray : LinearExpr
+{
+  public SumVarArray(Variable[] array)
+  {
+    this.array_ = array;
+  }
+
+  public override double DoVisit(Dictionary<Variable, double> coefficients,
+                                 double multiplier) {
+    if (multiplier != 0.0)
+    {
+      foreach (Variable var in array_)
+      {
+        if (coefficients.ContainsKey(var))
+        {
+          coefficients[var] += multiplier;
+        }
+        else
+        {
+          coefficients[var] = multiplier;
+        }
+      }
+    }
+    return 0.0;
+  }
+
+  private Variable[] array_;
+}
+}  // namespace Google.OrTools.LinearSolver
diff --git a/ortools/dotnet/OrTools/linearsolver/SolverHelper.cs b/ortools/dotnet/OrTools/linearsolver/SolverHelper.cs
new file mode 100644
index 00000000000..870a14b15ab
--- /dev/null
+++ b/ortools/dotnet/OrTools/linearsolver/SolverHelper.cs
@@ -0,0 +1,250 @@
+// Copyright 2010-2017 Google
+// 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.LinearSolver {
+using System;
+using System.Collections.Generic;
+
+// Patch the MPSolver class to:
+// - support custom versions of the array-based APIs (MakeVarArray, etc).
+// - customize the construction, and the OptimizationProblemType enum.
+// - support the natural language API.
+public partial class Solver {
+  public Variable[] MakeVarArray(int count,
+                                 double lb,
+                                 double ub,
+                                 bool integer) {
+    Variable[] array = new Variable[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeVar(lb, ub, integer, "");
+    }
+    return array;
+  }
+
+  public Variable[] MakeVarArray(int count,
+                                 double lb,
+                                 double ub,
+                                 bool integer,
+                                 string var_name) {
+    Variable[] array = new Variable[count];
+    for (int i = 0; i < count; ++i) {
+      array[i] = MakeVar(lb, ub, integer, var_name + i);
+    }
+    return array;
+  }
+
+  public Variable[,] MakeVarMatrix(int rows,
+                                   int cols,
+                                   double lb,
+                                   double ub,
+                                   bool integer) {
+    Variable[,] matrix = new Variable[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        matrix[i,j] = MakeVar(lb, ub, integer, "");
+      }
+    }
+    return matrix;
+  }
+
+  public Variable[,] MakeVarMatrix(int rows,
+                                   int cols,
+                                   double lb,
+                                   double ub,
+                                   bool integer,
+                                   string name) {
+    Variable[,] matrix = new Variable[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        string var_name = name + "[" + i + ", " + j +"]";
+        matrix[i,j] = MakeVar(lb, ub, integer, var_name);
+      }
+    }
+    return matrix;
+  }
+
+  public Variable[] MakeNumVarArray(int count, double lb, double ub) {
+    return MakeVarArray(count, lb, ub, false);
+  }
+
+  public Variable[] MakeNumVarArray(int count,
+                                    double lb,
+                                    double ub,
+                                    string var_name) {
+    return MakeVarArray(count, lb, ub, false, var_name);
+  }
+
+  public Variable[,] MakeNumVarMatrix(int rows,
+                                      int cols,
+                                      double lb,
+                                      double ub) {
+    Variable[,] matrix = new Variable[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        matrix[i,j] = MakeNumVar(lb, ub, "");
+      }
+    }
+    return matrix;
+  }
+
+  public Variable[,] MakeNumVarMatrix(int rows,
+                                      int cols,
+                                      double lb,
+                                      double ub,
+                                      string name) {
+    Variable[,] matrix = new Variable[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        string var_name = name + "[" + i + ", " + j +"]";
+        matrix[i,j] = MakeNumVar(lb, ub, var_name);
+      }
+    }
+    return matrix;
+  }
+
+  public Variable[] MakeIntVarArray(int count, double lb, double ub) {
+    return MakeVarArray(count, lb, ub, true);
+  }
+
+  public Variable[] MakeIntVarArray(int count,
+                                    double lb,
+                                    double ub,
+                                    string var_name) {
+    return MakeVarArray(count, lb, ub, true, var_name);
+  }
+
+  public Variable[,] MakeIntVarMatrix(int rows,
+                                      int cols,
+                                      double lb,
+                                      double ub) {
+    Variable[,] matrix = new Variable[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        matrix[i,j] = MakeIntVar(lb, ub, "");
+      }
+    }
+    return matrix;
+  }
+
+  public Variable[,] MakeIntVarMatrix(int rows,
+                                      int cols,
+                                      double lb,
+                                      double ub,
+                                      string name) {
+    Variable[,] matrix = new Variable[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        string var_name = name + "[" + i + ", " + j +"]";
+        matrix[i,j] = MakeIntVar(lb, ub, var_name);
+      }
+    }
+    return matrix;
+  }
+
+  public Variable[] MakeBoolVarArray(int count) {
+    return MakeVarArray(count, 0.0, 1.0, true);
+  }
+
+  public Variable[] MakeBoolVarArray(int count, string var_name) {
+    return MakeVarArray(count, 0.0, 1.0, true, var_name);
+  }
+
+  public Variable[,] MakeBoolVarMatrix(int rows, int cols) {
+    Variable[,] matrix = new Variable[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        matrix[i,j] = MakeBoolVar("");
+      }
+    }
+    return matrix;
+  }
+
+  public Variable[,] MakeBoolVarMatrix(int rows, int cols, string name) {
+    Variable[,] matrix = new Variable[rows, cols];
+    for (int i = 0; i < rows; ++i) {
+      for (int j = 0; j < cols; ++j) {
+        string var_name = name + "[" + i + ", " + j +"]";
+        matrix[i,j] = MakeBoolVar(var_name);
+      }
+    }
+    return matrix;
+  }
+
+  public static int GetSolverEnum(String solverType) {
+    System.Reflection.FieldInfo fieldInfo =
+      typeof(Solver).GetField(solverType);
+    if (fieldInfo != null) {
+      return (int)fieldInfo.GetValue(null);
+    } else {
+      throw new System.ApplicationException("Solver not supported");
+    }
+  }
+
+  public static Solver CreateSolver(String name, String type) {
+    System.Reflection.FieldInfo fieldInfo =
+        typeof(Solver).GetField(type);
+    if (fieldInfo != null) {
+      return new Solver(name, (int)fieldInfo.GetValue(null));
+    } else {
+      return null;
+    }
+  }
+
+  public Constraint Add(LinearConstraint constraint) {
+    return constraint.Extract(this);
+  }
+
+  public void Minimize(LinearExpr expr)
+  {
+    Objective().Clear();
+    Objective().SetMinimization();
+    Dictionary<Variable, double> coefficients =
+        new Dictionary<Variable, double>();
+    double constant = expr.Visit(coefficients);
+    foreach (KeyValuePair<Variable, double> pair in coefficients)
+    {
+      Objective().SetCoefficient(pair.Key, pair.Value);
+    }
+    Objective().SetOffset(constant);
+  }
+
+  public void Maximize(LinearExpr expr)
+  {
+    Objective().Clear();
+    Objective().SetMaximization();
+    Dictionary<Variable, double> coefficients =
+        new Dictionary<Variable, double>();
+    double constant = expr.Visit(coefficients);
+    foreach (KeyValuePair<Variable, double> pair in coefficients)
+    {
+      Objective().SetCoefficient(pair.Key, pair.Value);
+    }
+    Objective().SetOffset(constant);
+  }
+
+  public void Minimize(Variable var)
+  {
+    Objective().Clear();
+    Objective().SetMinimization();
+    Objective().SetCoefficient(var, 1.0);
+  }
+
+  public void Maximize(Variable var)
+  {
+    Objective().Clear();
+    Objective().SetMaximization();
+    Objective().SetCoefficient(var, 1.0);
+  }
+}
+
+}  // namespace Google.OrTools.LinearSolver
diff --git a/ortools/dotnet/OrTools/linearsolver/VariableHelper.cs b/ortools/dotnet/OrTools/linearsolver/VariableHelper.cs
new file mode 100644
index 00000000000..81b314a2c7d
--- /dev/null
+++ b/ortools/dotnet/OrTools/linearsolver/VariableHelper.cs
@@ -0,0 +1,191 @@
+// Copyright 2010-2017 Google
+// 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.LinearSolver {
+using System;
+using System.Collections.Generic;
+
+// Patch the MPVariable class to support the natural language API.
+public partial class Variable {
+  public static LinearExpr operator+(Variable a, double v)
+  {
+    return new VarWrapper(a) + v;
+  }
+
+  public static LinearExpr operator+(double v, Variable a)
+  {
+    return a + v;
+  }
+
+  public static LinearExpr operator+(Variable a, LinearExpr b)
+  {
+    return new VarWrapper(a) + b;
+  }
+
+  public static LinearExpr operator+(Variable a, Variable b)
+  {
+    return new VarWrapper(a) + new VarWrapper(b);
+  }
+
+  public static LinearExpr operator+(LinearExpr a, Variable b)
+  {
+    return a + new VarWrapper(b);
+  }
+
+  public static LinearExpr operator-(Variable a, double v)
+  {
+    return new VarWrapper(a) - v;
+  }
+
+  public static LinearExpr operator-(double v, Variable a)
+  {
+    return v - new VarWrapper(a);
+  }
+
+  public static LinearExpr operator-(Variable a, LinearExpr b)
+  {
+    return new VarWrapper(a) - b;
+  }
+
+  public static LinearExpr operator-(LinearExpr a, Variable b)
+  {
+    return a - new VarWrapper(b);
+  }
+
+  public static LinearExpr operator-(Variable a, Variable b)
+  {
+    return new VarWrapper(a) - new VarWrapper(b);
+  }
+
+  public static LinearExpr operator-(Variable a)
+  {
+    return - new VarWrapper(a);
+  }
+
+  public static LinearExpr operator*(Variable a, double v)
+  {
+    return new VarWrapper(a) * v;
+  }
+
+  public static LinearExpr operator/(Variable a, double v)
+  {
+    return new VarWrapper(a) / v;
+  }
+
+  public static LinearExpr operator*(double v, Variable a)
+  {
+    return v * new VarWrapper(a);
+  }
+
+  public static RangeConstraint operator==(Variable a, double v)
+  {
+    return new VarWrapper(a) == v;
+  }
+
+  public static RangeConstraint operator==(double v, Variable a)
+  {
+    return v == new VarWrapper(a);
+  }
+
+  public static RangeConstraint operator!=(Variable a, double v)
+  {
+    return new VarWrapper(a) != v;
+  }
+
+  public static RangeConstraint operator!=(double v, Variable a)
+  {
+    return new VarWrapper(a) != v;
+  }
+
+  public static Equality operator==(Variable a, LinearExpr b)
+  {
+    return new VarWrapper(a) == b;
+  }
+
+  public static Equality operator==(LinearExpr a, Variable b)
+  {
+    return a == new VarWrapper(b);
+  }
+
+  public static VarEquality operator==(Variable a, Variable b)
+  {
+    return new VarEquality(a, b, true);
+  }
+
+  public static Equality operator!=(Variable a, LinearExpr b)
+  {
+    return new VarWrapper(a) != b;
+  }
+
+  public static Equality operator!=(LinearExpr a, Variable b)
+  {
+    return a != new VarWrapper(b);
+  }
+
+  public static VarEquality operator!=(Variable a, Variable b)
+  {
+    return new VarEquality(a, b, false);
+  }
+
+  public static RangeConstraint operator<=(Variable a, double v)
+  {
+    return new VarWrapper(a) <= v;
+  }
+
+  public static RangeConstraint operator>=(Variable a, double v)
+  {
+    return new VarWrapper(a) >= v;
+  }
+
+  public static RangeConstraint operator<=(double v, Variable a)
+  {
+    return new VarWrapper(a) >= v;
+  }
+
+  public static RangeConstraint operator>=(double v, Variable a)
+  {
+    return new VarWrapper(a) <= v;
+  }
+
+  public static RangeConstraint operator<=(Variable a, LinearExpr b)
+  {
+    return new VarWrapper(a) <= b;
+  }
+
+  public static RangeConstraint operator>=(Variable a, LinearExpr b)
+  {
+    return new VarWrapper(a) >= b;
+  }
+
+  public static RangeConstraint operator<=(Variable a, Variable b)
+  {
+    return new VarWrapper(a) <= new VarWrapper(b);
+  }
+
+  public static RangeConstraint operator>=(Variable a, Variable b)
+  {
+    return new VarWrapper(a) >= new VarWrapper(b);
+  }
+
+  public static RangeConstraint operator<=(LinearExpr a, Variable b)
+  {
+    return a <= new VarWrapper(b);
+  }
+
+  public static RangeConstraint operator>=(LinearExpr a, Variable b)
+  {
+    return a >= new VarWrapper(b);
+  }
+}
+
+}  // namespace Google.OrTools.LinearSolver
diff --git a/ortools/dotnet/OrTools/sat/Constraints.cs b/ortools/dotnet/OrTools/sat/Constraints.cs
new file mode 100644
index 00000000000..51d95599ca6
--- /dev/null
+++ b/ortools/dotnet/OrTools/sat/Constraints.cs
@@ -0,0 +1,47 @@
+// Copyright 2010-2017 Google
+// 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;
+
+public class Constraint
+{
+  public Constraint(CpModelProto model)
+  {
+    index_ = model.Constraints.Count;
+    constraint_ = new ConstraintProto();
+    model.Constraints.Add(constraint_);
+  }
+
+  public void OnlyEnforceIf(ILiteral lit)
+  {
+    constraint_.EnforcementLiteral.Add(lit.GetIndex());
+  }
+
+  public int Index
+  {
+    get  { return index_; }
+  }
+
+  public ConstraintProto Proto
+  {
+    get { return constraint_; }
+  }
+
+  private int index_;
+  private ConstraintProto constraint_;
+}
+
+}  // namespace Google.OrTools.Sat
diff --git a/ortools/dotnet/OrTools/sat/CpModel.cs b/ortools/dotnet/OrTools/sat/CpModel.cs
new file mode 100644
index 00000000000..8e4438d2391
--- /dev/null
+++ b/ortools/dotnet/OrTools/sat/CpModel.cs
@@ -0,0 +1,880 @@
+// Copyright 2010-2017 Google
+// 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;
+
+public class CpModel
+{
+  public CpModel()
+  {
+    model_ = new CpModelProto();
+    constant_map_ = new Dictionary<long, int>();
+  }
+
+  // Getters.
+
+  public CpModelProto Model
+  {
+    get { return model_; }
+  }
+
+  int Negated(int index)
+  {
+    return -index - 1;
+  }
+
+  // Integer variables and constraints.
+
+  public IntVar NewIntVar(long lb, long ub, string name)
+  {
+    long[] bounds = { lb, ub };
+    return new IntVar(model_, bounds, name);
+  }
+
+  public IntVar NewEnumeratedIntVar(IEnumerable<long> bounds, string name)
+  {
+    return new IntVar(model_, bounds, name);
+  }
+
+  public IntVar NewOptionalIntVar(
+      long lb, long ub, ILiteral is_present, string name)
+  {
+    long[] bounds = { lb, ub };
+    return new IntVar(model_, bounds, is_present.GetIndex(), name);
+  }
+
+  public IntVar NewOptionalEnumeratedIntVar(
+      IEnumerable<long> bounds, ILiteral is_present, string name)
+  {
+    return new IntVar(model_, bounds, is_present.GetIndex(), name);
+  }
+
+  // Constants (named or not).
+
+  // TODO: Cache constant.
+  public IntVar NewConstant(long value)
+  {
+    long[] bounds = { value, value };
+    return new IntVar(model_, bounds, String.Format("{0}", value));
+  }
+
+  public IntVar NewConstant(long value, string name)
+  {
+    long[] bounds = { value, value };
+    return new IntVar(model_, bounds, name);
+  }
+
+  public IntVar NewOptionalConstant(
+      long value, ILiteral is_present, string name)
+  {
+    long[] bounds = { value, value };
+    return new IntVar(model_, bounds, is_present.GetIndex(), name);
+  }
+
+  public IntVar NewBoolVar(string name)
+  {
+    long[] bounds = { 0L, 1L };
+    return new IntVar(model_, bounds, name);
+  }
+
+  public Constraint AddLinearConstraint(IEnumerable<Tuple<IntVar, long>> terms,
+                                        long lb, long ub)
+  {
+    Constraint ct = new Constraint(model_);
+    LinearConstraintProto lin = new LinearConstraintProto();
+    foreach (Tuple<IntVar, long> term in terms)
+    {
+      lin.Vars.Add(term.Item1.Index);
+      lin.Coeffs.Add(term.Item2);
+    }
+    lin.Domain.Add(lb);
+    lin.Domain.Add(ub);
+    ct.Proto.Linear = lin;
+    return ct;
+  }
+
+  public Constraint AddLinearConstraint(IEnumerable<IntVar> vars,
+                                        IEnumerable<long> coeffs,
+                                        long lb, long ub)
+  {
+    Constraint ct = new Constraint(model_);
+    LinearConstraintProto lin = new LinearConstraintProto();
+    foreach (IntVar var in vars)
+    {
+      lin.Vars.Add(var.Index);
+    }
+    foreach (long coeff in coeffs)
+    {
+      lin.Coeffs.Add(coeff);
+    }
+    lin.Domain.Add(lb);
+    lin.Domain.Add(ub);
+    ct.Proto.Linear = lin;
+    return ct;
+  }
+
+  public Constraint AddLinearConstraint(IEnumerable<IntVar> vars,
+                                        IEnumerable<int> coeffs,
+                                        long lb, long ub)
+  {
+    Constraint ct = new Constraint(model_);
+    LinearConstraintProto lin = new LinearConstraintProto();
+    foreach (IntVar var in vars)
+    {
+      lin.Vars.Add(var.Index);
+    }
+    foreach (int coeff in coeffs)
+    {
+      lin.Coeffs.Add(coeff);
+    }
+    lin.Domain.Add(lb);
+    lin.Domain.Add(ub);
+    ct.Proto.Linear = lin;
+    return ct;
+  }
+
+  public Constraint AddLinearConstraintWithBounds(
+      IEnumerable<Tuple<IntVar, long>> terms, IEnumerable<long> bounds)
+  {
+    Constraint ct = new Constraint(model_);
+    LinearConstraintProto lin = new LinearConstraintProto();
+    foreach (Tuple<IntVar, long> term in terms)
+    {
+      lin.Vars.Add(term.Item1.Index);
+      lin.Coeffs.Add(term.Item2);
+    }
+    foreach (long b in bounds)
+    {
+      lin.Domain.Add(b);
+    }
+    ct.Proto.Linear = lin;
+    return ct;
+  }
+
+  public Constraint AddLinearConstraintWithBounds(IEnumerable<IntVar> vars,
+                                                  IEnumerable<long> coeffs,
+                                                  IEnumerable<long> bounds)
+  {
+    Constraint ct = new Constraint(model_);
+    LinearConstraintProto lin = new LinearConstraintProto();
+    foreach (IntVar var in vars)
+    {
+      lin.Vars.Add(var.Index);
+    }
+    foreach (long coeff in coeffs)
+    {
+      lin.Coeffs.Add(coeff);
+    }
+    foreach (long b in bounds)
+    {
+      lin.Domain.Add(b);
+    }
+    ct.Proto.Linear = lin;
+    return ct;
+  }
+
+  public Constraint AddLinearConstraintWithBounds(IEnumerable<IntVar> vars,
+                                                  IEnumerable<int> coeffs,
+                                                  IEnumerable<long> bounds)
+  {
+    Constraint ct = new Constraint(model_);
+    LinearConstraintProto lin = new LinearConstraintProto();
+    foreach (IntVar var in vars)
+    {
+      lin.Vars.Add(var.Index);
+    }
+    foreach (int coeff in coeffs)
+    {
+      lin.Coeffs.Add(coeff);
+    }
+    foreach (long b in bounds)
+    {
+      lin.Domain.Add(b);
+    }
+    ct.Proto.Linear = lin;
+    return ct;
+  }
+
+  public Constraint AddSumConstraint(IEnumerable<IntVar> vars, long lb,
+                                     long ub)
+  {
+    Constraint ct = new Constraint(model_);
+    LinearConstraintProto lin = new LinearConstraintProto();
+    foreach (IntVar var in vars)
+    {
+      lin.Vars.Add(var.Index);
+      lin.Coeffs.Add(1L);
+    }
+    lin.Domain.Add(lb);
+    lin.Domain.Add(ub);
+    ct.Proto.Linear = lin;
+    return ct;
+  }
+
+  public Constraint Add(BoundIntegerExpression lin)
+  {
+    switch (lin.CtType)
+    {
+      case BoundIntegerExpression.Type.BoundExpression:
+        {
+          Dictionary<IntVar, long> dict = new Dictionary<IntVar, long>();
+          long constant = IntegerExpression.GetVarValueMap(lin.Left, 1L, dict);
+          Constraint ct = new Constraint(model_);
+          LinearConstraintProto linear = new LinearConstraintProto();
+          foreach (KeyValuePair<IntVar, long> term in dict)
+          {
+            linear.Vars.Add(term.Key.Index);
+            linear.Coeffs.Add(term.Value);
+          }
+          linear.Domain.Add(lin.Lb == Int64.MinValue ? Int64.MinValue
+                            : lin.Lb - constant);
+          linear.Domain.Add(lin.Ub == Int64.MaxValue ? Int64.MaxValue
+                            : lin.Ub - constant);
+          ct.Proto.Linear = linear;
+          return ct;
+        }
+      case BoundIntegerExpression.Type.VarEqVar:
+        {
+          Dictionary<IntVar, long> dict = new Dictionary<IntVar, long>();
+          long constant = IntegerExpression.GetVarValueMap(lin.Left, 1L, dict);
+          constant +=  IntegerExpression.GetVarValueMap(lin.Right, -1L, dict);
+          Constraint ct = new Constraint(model_);
+          LinearConstraintProto linear = new LinearConstraintProto();
+          foreach (KeyValuePair<IntVar, long> term in dict)
+          {
+            linear.Vars.Add(term.Key.Index);
+            linear.Coeffs.Add(term.Value);
+          }
+          linear.Domain.Add(-constant);
+          linear.Domain.Add(-constant);
+          ct.Proto.Linear = linear;
+          return ct;
+        }
+      case BoundIntegerExpression.Type.VarDiffVar:
+        {
+          Dictionary<IntVar, long> dict = new Dictionary<IntVar, long>();
+          long constant = IntegerExpression.GetVarValueMap(lin.Left, 1L, dict);
+          constant +=  IntegerExpression.GetVarValueMap(lin.Right, -1L, dict);
+          Constraint ct = new Constraint(model_);
+          LinearConstraintProto linear = new LinearConstraintProto();
+          foreach (KeyValuePair<IntVar, long> term in dict)
+          {
+            linear.Vars.Add(term.Key.Index);
+            linear.Coeffs.Add(term.Value);
+          }
+          linear.Domain.Add(Int64.MinValue);
+          linear.Domain.Add(-constant - 1);
+          linear.Domain.Add(-constant + 1);
+          linear.Domain.Add(Int64.MaxValue);
+          ct.Proto.Linear = linear;
+          return ct;
+        }
+      case BoundIntegerExpression.Type.VarEqCst:
+        {
+          Dictionary<IntVar, long> dict = new Dictionary<IntVar, long>();
+          long constant = IntegerExpression.GetVarValueMap(lin.Left, 1L, dict);
+          Constraint ct = new Constraint(model_);
+          LinearConstraintProto linear = new LinearConstraintProto();
+          foreach (KeyValuePair<IntVar, long> term in dict)
+          {
+            linear.Vars.Add(term.Key.Index);
+            linear.Coeffs.Add(term.Value);
+          }
+          linear.Domain.Add(lin.Lb - constant);
+          linear.Domain.Add(lin.Lb - constant);
+          ct.Proto.Linear = linear;
+          return ct;
+        }
+      case BoundIntegerExpression.Type.VarDiffCst:
+        {
+          Dictionary<IntVar, long> dict = new Dictionary<IntVar, long>();
+          long constant = IntegerExpression.GetVarValueMap(lin.Left, 1L, dict);
+          Constraint ct = new Constraint(model_);
+          LinearConstraintProto linear = new LinearConstraintProto();
+          foreach (KeyValuePair<IntVar, long> term in dict)
+          {
+            linear.Vars.Add(term.Key.Index);
+            linear.Coeffs.Add(term.Value);
+          }
+          linear.Domain.Add(Int64.MinValue);
+          linear.Domain.Add(lin.Lb - constant - 1);
+          linear.Domain.Add(lin.Lb - constant + 1);
+          linear.Domain.Add(Int64.MaxValue);
+          ct.Proto.Linear = linear;
+          return ct;
+        }
+    }
+    return null;
+  }
+
+  public Constraint AddAllDifferent(IEnumerable<IntVar> vars)
+  {
+    Constraint ct = new Constraint(model_);
+    AllDifferentConstraintProto alldiff = new AllDifferentConstraintProto();
+    foreach (IntVar var in vars)
+    {
+      alldiff.Vars.Add(var.Index);
+    }
+    ct.Proto.AllDiff = alldiff;
+    return ct;
+  }
+
+  public Constraint AddElement(IntVar index, IEnumerable<IntVar> vars,
+                               IntVar target)
+  {
+    Constraint ct = new Constraint(model_);
+    ElementConstraintProto element = new ElementConstraintProto();
+    element.Index = index.Index;
+    foreach (IntVar var in vars)
+    {
+      element.Vars.Add(var.Index);
+    }
+    element.Target = target.Index;
+    ct.Proto.Element = element;
+    return ct;
+  }
+
+  public Constraint AddElement(IntVar index, IEnumerable<long> values,
+                               IntVar target)
+  {
+    Constraint ct = new Constraint(model_);
+    ElementConstraintProto element = new ElementConstraintProto();
+    element.Index = index.Index;
+    foreach (long value in values)
+    {
+      element.Vars.Add(ConvertConstant(value));
+    }
+    element.Target = target.Index;
+    ct.Proto.Element = element;
+    return ct;
+  }
+
+  public Constraint AddElement(IntVar index, IEnumerable<int> values,
+                               IntVar target)
+  {
+    Constraint ct = new Constraint(model_);
+    ElementConstraintProto element = new ElementConstraintProto();
+    element.Index = index.Index;
+    foreach (int value in values)
+    {
+      element.Vars.Add(ConvertConstant(value));
+    }
+    element.Target = target.Index;
+    ct.Proto.Element = element;
+    return ct;
+  }
+
+  public Constraint AddCircuit(IEnumerable<Tuple<int, int, ILiteral>> arcs)
+  {
+    Constraint ct = new Constraint(model_);
+    CircuitConstraintProto circuit = new CircuitConstraintProto();
+    foreach (var arc in arcs)
+    {
+      circuit.Tails.Add(arc.Item1);
+      circuit.Heads.Add(arc.Item2);
+      circuit.Literals.Add(arc.Item3.GetIndex());
+    }
+    ct.Proto.Circuit = circuit;
+    return ct;
+  }
+
+  public Constraint AddAllowedAssignments(IEnumerable<IntVar> vars,
+                                          long[,] tuples)
+  {
+    Constraint ct = new Constraint(model_);
+    TableConstraintProto table = new TableConstraintProto();
+    foreach (IntVar var in vars)
+    {
+      table.Vars.Add(var.Index);
+    }
+    for (int i = 0; i < tuples.GetLength(0); ++i)
+    {
+      for (int j = 0; j < tuples.GetLength(1);++j)
+      {
+        table.Values.Add(tuples[i, j]);
+      }
+    }
+    ct.Proto.Table = table;
+    return ct;
+  }
+
+  public Constraint AddForbiddenAssignments(IEnumerable<IntVar> vars,
+                                            long[,] tuples)
+  {
+    Constraint ct = AddAllowedAssignments(vars, tuples);
+    ct.Proto.Table.Negated = true;
+    return ct;
+  }
+
+  public Constraint AddAutomata(IEnumerable<IntVar> vars,
+                                long starting_state,
+                                long[,] transitions,
+                                IEnumerable<long> final_states) {
+    Constraint ct = new Constraint(model_);
+    AutomataConstraintProto aut = new AutomataConstraintProto();
+    foreach (IntVar var in vars)
+    {
+      aut.Vars.Add(var.Index);
+    }
+    aut.StartingState = starting_state;
+    foreach (long f in final_states)
+    {
+      aut.FinalStates.Add(f);
+    }
+    for (int i = 0; i < transitions.GetLength(0); ++i)
+    {
+      aut.TransitionTail.Add(transitions[i, 0]);
+      aut.TransitionLabel.Add(transitions[i, 1]);
+      aut.TransitionHead.Add(transitions[i, 2]);
+    }
+
+    ct.Proto.Automata = aut;
+    return ct;
+  }
+
+  public Constraint AddAutomata(
+      IEnumerable<IntVar> vars,
+      long starting_state,
+      IEnumerable<Tuple<long, long, long>> transitions,
+      IEnumerable<long> final_states) {
+    Constraint ct = new Constraint(model_);
+    AutomataConstraintProto aut = new AutomataConstraintProto();
+    foreach (IntVar var in vars)
+    {
+      aut.Vars.Add(var.Index);
+    }
+    aut.StartingState = starting_state;
+    foreach (long f in final_states)
+    {
+      aut.FinalStates.Add(f);
+    }
+    foreach (Tuple<long, long, long> transition in transitions)
+    {
+
+      aut.TransitionHead.Add(transition.Item1);
+      aut.TransitionLabel.Add(transition.Item2);
+      aut.TransitionTail.Add(transition.Item3);
+    }
+
+    ct.Proto.Automata = aut;
+    return ct;
+  }
+
+  public Constraint AddInverse(IEnumerable<IntVar> direct,
+                               IEnumerable<IntVar> reverse)
+  {
+    Constraint ct = new Constraint(model_);
+    InverseConstraintProto inverse = new InverseConstraintProto();
+    foreach (IntVar var in direct)
+    {
+      inverse.FDirect.Add(var.Index);
+    }
+    foreach (IntVar var in reverse)
+    {
+      inverse.FInverse.Add(var.Index);
+    }
+    ct.Proto.Inverse = inverse;
+    return ct;
+  }
+
+  public Constraint AddReservoirConstraint(IEnumerable<IntVar> times,
+                                           IEnumerable<long> demands,
+                                           long min_level, long max_level)
+  {
+    Constraint ct = new Constraint(model_);
+    ReservoirConstraintProto res = new ReservoirConstraintProto();
+    foreach (IntVar var in times)
+    {
+      res.Times.Add(var.Index);
+    }
+    foreach (long d in demands)
+    {
+      res.Demands.Add(d);
+    }
+
+    ct.Proto.Reservoir = res;
+    return ct;
+  }
+
+  public Constraint AddReservoirConstraint(IEnumerable<IntVar> times,
+                                           IEnumerable<int> demands,
+                                           long min_level, long max_level)
+  {
+    Constraint ct = new Constraint(model_);
+    ReservoirConstraintProto res = new ReservoirConstraintProto();
+    foreach (IntVar var in times)
+    {
+      res.Times.Add(var.Index);
+    }
+    foreach (int d in demands)
+    {
+      res.Demands.Add(d);
+    }
+
+    ct.Proto.Reservoir = res;
+    return ct;
+  }
+
+  public void AddMapDomain(
+      IntVar var, IEnumerable<IntVar> bool_vars, long offset = 0)
+  {
+    int i = 0;
+    foreach (IntVar bool_var in bool_vars)
+    {
+      int b_index = bool_var.Index;
+      int var_index = var.Index;
+
+      ConstraintProto ct1 = new ConstraintProto();
+      LinearConstraintProto lin1 = new LinearConstraintProto();
+      lin1.Vars.Add(var_index);
+      lin1.Coeffs.Add(1L);
+      lin1.Domain.Add(offset + i);
+      lin1.Domain.Add(offset + i);
+      ct1.Linear = lin1;
+      ct1.EnforcementLiteral.Add(b_index);
+      model_.Constraints.Add(ct1);
+
+      ConstraintProto ct2 = new ConstraintProto();
+      LinearConstraintProto lin2 = new LinearConstraintProto();
+      lin2.Vars.Add(var_index);
+      lin2.Coeffs.Add(1L);
+      lin2.Domain.Add(Int64.MinValue);
+      lin2.Domain.Add(offset + i - 1);
+      lin2.Domain.Add(offset + i + 1);
+      lin2.Domain.Add(Int64.MaxValue);
+      ct2.Linear = lin2;
+      ct2.EnforcementLiteral.Add(-b_index - 1);
+      model_.Constraints.Add(ct2);
+
+      i++;
+    }
+  }
+
+  public Constraint AddImplication(ILiteral a, ILiteral b)
+  {
+    Constraint ct = new Constraint(model_);
+    BoolArgumentProto or = new BoolArgumentProto();
+    or.Literals.Add(a.Not().GetIndex());
+    or.Literals.Add(b.GetIndex());
+    ct.Proto.BoolOr = or;
+    return ct;
+  }
+
+  public Constraint AddBoolOr(IEnumerable<ILiteral> literals)
+  {
+    Constraint ct = new Constraint(model_);
+    BoolArgumentProto bool_argument = new BoolArgumentProto();
+    foreach (ILiteral lit in literals)
+    {
+      bool_argument.Literals.Add(lit.GetIndex());
+    }
+    ct.Proto.BoolOr = bool_argument;
+    return ct;
+  }
+
+  public Constraint AddBoolAnd(IEnumerable<ILiteral> literals)
+  {
+    Constraint ct = new Constraint(model_);
+    BoolArgumentProto bool_argument = new BoolArgumentProto();
+    foreach (ILiteral lit in literals)
+    {
+      bool_argument.Literals.Add(lit.GetIndex());
+    }
+    ct.Proto.BoolAnd = bool_argument;
+    return ct;
+  }
+
+  public Constraint AddBoolXor(IEnumerable<ILiteral> literals)
+  {
+    Constraint ct = new Constraint(model_);
+    BoolArgumentProto bool_argument = new BoolArgumentProto();
+    foreach (ILiteral lit in literals)
+    {
+      bool_argument.Literals.Add(lit.GetIndex());
+    }
+    ct.Proto.BoolXor = bool_argument;
+    return ct;
+  }
+
+  public Constraint AddMinEquality(IntVar target, IEnumerable<IntVar> vars)
+  {
+    Constraint ct = new Constraint(model_);
+    IntegerArgumentProto args = new IntegerArgumentProto();
+    foreach (IntVar var in vars)
+    {
+      args.Vars.Add(var.Index);
+    }
+    args.Target = target.Index;
+    ct.Proto.IntMin = args;
+    return ct;
+  }
+
+  public Constraint AddMaxEquality(IntVar target, IEnumerable<IntVar> vars)
+  {
+    Constraint ct = new Constraint(model_);
+    IntegerArgumentProto args = new IntegerArgumentProto();
+    foreach (IntVar var in vars)
+    {
+      args.Vars.Add(var.Index);
+    }
+    args.Target = target.Index;
+    ct.Proto.IntMax = args;
+    return ct;
+  }
+
+  public Constraint AddDivisionEquality<T, N, D>(T target, N num, D denom)
+  {
+    Constraint ct = new Constraint(model_);
+    IntegerArgumentProto args = new IntegerArgumentProto();
+    args.Vars.Add(GetOrCreateIndex(num));
+    args.Vars.Add(GetOrCreateIndex(denom));
+    args.Target = GetOrCreateIndex(target);
+    ct.Proto.IntDiv = args;
+    return ct;
+  }
+
+  public Constraint AddModuloEquality<T, V, M>(T target, V v, M m)
+  {
+    Constraint ct = new Constraint(model_);
+    IntegerArgumentProto args = new IntegerArgumentProto();
+    args.Vars.Add(GetOrCreateIndex(v));
+    args.Vars.Add(GetOrCreateIndex(m));
+    args.Target = GetOrCreateIndex(target);
+    ct.Proto.IntMod = args;
+    return ct;
+  }
+
+  public Constraint AddProdEquality(IntVar target, IEnumerable<IntVar> vars)
+  {
+    Constraint ct = new Constraint(model_);
+    IntegerArgumentProto args = new IntegerArgumentProto();
+    args.Target = target.Index;
+    foreach (IntVar var in vars)
+    {
+      args.Vars.Add(var.Index);
+    }
+    ct.Proto.IntProd = args;
+    return ct;
+  }
+
+  // Scheduling support
+
+  public IntervalVar NewIntervalVar<S, D, E>(
+      S start, D duration, E end, string name) {
+    return new IntervalVar(model_,
+                           GetOrCreateIndex(start),
+                           GetOrCreateIndex(duration),
+                           GetOrCreateIndex(end),
+                           name);
+  }
+
+
+  public IntervalVar NewOptionalIntervalVar<S, D, E>(
+      S start, D duration, E end, ILiteral is_present, string name) {
+    int i = is_present.GetIndex();
+    return new IntervalVar(model_,
+                           GetOrCreateOptionalIndex(start, i),
+                           // Size is currently not optional.
+                           GetOrCreateIndex(duration),
+                           GetOrCreateOptionalIndex(end, i),
+                           i,
+                           name);
+  }
+
+  public Constraint AddNoOverlap(IEnumerable<IntervalVar> intervals)
+  {
+    Constraint ct = new Constraint(model_);
+    NoOverlapConstraintProto args = new NoOverlapConstraintProto();
+    foreach (IntervalVar var in intervals)
+    {
+      args.Intervals.Add(var.GetIndex());
+    }
+    ct.Proto.NoOverlap = args;
+    return ct;
+  }
+
+  public Constraint AddNoOverlap2D(IEnumerable<IntervalVar> x_intervals,
+                                   IEnumerable<IntervalVar> y_intervals)
+  {
+    Constraint ct = new Constraint(model_);
+    NoOverlap2DConstraintProto args = new NoOverlap2DConstraintProto();
+    foreach (IntervalVar var in x_intervals)
+    {
+      args.XIntervals.Add(var.GetIndex());
+    }
+    foreach (IntervalVar var in y_intervals)
+    {
+      args.YIntervals.Add(var.GetIndex());
+    }
+    ct.Proto.NoOverlap2D = args;
+    return ct;
+  }
+
+  public Constraint AddCumulative<D, C>(IEnumerable<IntervalVar> intervals,
+                                        IEnumerable<D> demands,
+                                        C capacity) {
+    Constraint ct = new Constraint(model_);
+    CumulativeConstraintProto cumul = new CumulativeConstraintProto();
+    foreach (IntervalVar var in intervals)
+    {
+      cumul.Intervals.Add(var.GetIndex());
+    }
+    foreach (D demand in demands)
+    {
+      cumul.Demands.Add(GetOrCreateIndex(demand));
+    }
+    cumul.Capacity = GetOrCreateIndex(capacity);
+    ct.Proto.Cumulative = cumul;
+    return ct;
+  }
+
+
+  // Objective.
+  public void Minimize(IntegerExpression obj)
+  {
+    SetObjective(obj, true);
+  }
+
+  public void Maximize(IntegerExpression obj)
+  {
+    SetObjective(obj, false);
+  }
+
+  bool HasObjective()
+  {
+    return model_.Objective == null;
+  }
+
+  // Internal methods.
+
+  void SetObjective(IntegerExpression obj, bool minimize)
+  {
+    CpObjectiveProto objective = new CpObjectiveProto();
+    if (obj is IntVar)
+    {
+      objective.Coeffs.Add(1L);
+      objective.Offset = 0L;
+      if (minimize)
+      {
+        objective.Vars.Add(obj.Index);
+        objective.ScalingFactor = 1L;
+      }
+      else
+      {
+        objective.Vars.Add(Negated(obj.Index));
+        objective.ScalingFactor = -1L;
+      }
+    }
+    else
+    {
+      Dictionary<IntVar, long> dict = new Dictionary<IntVar, long>();
+      long constant = IntegerExpression.GetVarValueMap(obj, 1L, dict);
+      if (minimize)
+      {
+        objective.ScalingFactor = 1L;
+        objective.Offset = constant;
+      }
+      else
+      {
+        objective.ScalingFactor = -1L;
+        objective.Offset = -constant;
+      }
+      foreach (KeyValuePair<IntVar, long> it in dict)
+      {
+        objective.Coeffs.Add(it.Value);
+        if (minimize)
+        {
+          objective.Vars.Add(it.Key.Index);
+        }
+        else
+        {
+          objective.Vars.Add(Negated(it.Key.Index));
+        }
+      }
+    }
+    model_.Objective = objective;
+  }
+
+  private int ConvertConstant(long value)
+  {
+    if (constant_map_.ContainsKey(value))
+    {
+      return constant_map_[value];
+    }
+    else
+    {
+      int index = model_.Variables.Count;
+      IntegerVariableProto var = new IntegerVariableProto();
+      var.Domain.Add(value);
+      var.Domain.Add(value);
+      constant_map_.Add(value, index);
+      model_.Variables.Add(var);
+      return index;
+    }
+  }
+
+  private int ConvertOptionalConstant(long value, int is_present_index)
+  {
+    if (constant_map_.ContainsKey(value))
+    {
+      return constant_map_[value];
+    }
+    else
+    {
+      int index = model_.Variables.Count;
+      IntegerVariableProto var = new IntegerVariableProto();
+      var.Domain.Add(value);
+      var.Domain.Add(value);
+      constant_map_.Add(value, index);
+      var.EnforcementLiteral.Add(is_present_index);
+      model_.Variables.Add(var);
+      return index;
+    }
+  }
+
+  private int GetOrCreateIndex<X>(X x)
+  {
+    if (typeof(X) == typeof(IntVar))
+    {
+      IntVar vx = (IntVar)(Object)x;
+      return vx.Index;
+    }
+    if (typeof(X) == typeof(long) || typeof(X) == typeof(int))
+    {
+      return ConvertConstant(Convert.ToInt64(x));
+    }
+    throw new ArgumentException("Cannot extract index from argument");
+  }
+
+  private int GetOrCreateOptionalIndex<X>(X x, int is_present_index)
+  {
+    if (typeof(X) == typeof(IntVar))
+    {
+      IntVar vx = (IntVar)(Object)x;
+      return vx.Index;
+    }
+    if (typeof(X) == typeof(long) || typeof(X) == typeof(int))
+    {
+      return ConvertOptionalConstant(Convert.ToInt64(x), is_present_index);
+    }
+    throw new ArgumentException("Cannot extract index from argument");
+  }
+
+  private CpModelProto model_;
+  private Dictionary<long, int> constant_map_;
+}
+
+}  // namespace Google.OrTools.Sat
\ No newline at end of file
diff --git a/ortools/dotnet/OrTools/sat/CpSolver.cs b/ortools/dotnet/OrTools/sat/CpSolver.cs
new file mode 100644
index 00000000000..62a94d93d4b
--- /dev/null
+++ b/ortools/dotnet/OrTools/sat/CpSolver.cs
@@ -0,0 +1,257 @@
+// Copyright 2010-2017 Google
+// 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;
+
+public class CpSolverSolutionCallback : SolutionCallback
+{
+  public long Value(IntegerExpression e)
+  {
+    List<IntegerExpression> exprs = new List<IntegerExpression>();
+    List<long> coeffs = new List<long>();
+    exprs.Add(e);
+    coeffs.Add(1L);
+    long constant = 0;
+
+    while (exprs.Count > 0)
+    {
+      IntegerExpression expr = exprs[0];
+      exprs.RemoveAt(0);
+      long coeff = coeffs[0];
+      coeffs.RemoveAt(0);
+      if (coeff == 0) continue;
+
+      if (expr is ProductCst)
+      {
+        ProductCst p = (ProductCst)expr;
+        if (p.Coeff != 0)
+        {
+          exprs.Add(p.Expr);
+          coeffs.Add(p.Coeff * coeff);
+        }
+      }
+      else if (expr is SumArray)
+      {
+        SumArray a = (SumArray)expr;
+        constant += coeff * a.Constant;
+        foreach (IntegerExpression sub in a.Expressions)
+        {
+          exprs.Add(sub);
+          coeffs.Add(coeff);
+        }
+      }
+      else if (expr is IntVar)
+      {
+        int index = expr.Index;
+        long value = SolutionIntegerValue(index);
+        constant += coeff * value;
+      }
+      else if (expr is NotBooleanVariable)
+      {
+        throw new ArgumentException(
+            "Cannot evaluate a literal in an integer expression.");
+      }
+      else
+      {
+        throw new ArgumentException("Cannot evaluate '" + expr.ToString() +
+                                    "' in an integer expression");
+      }
+    }
+    return constant;
+  }
+
+  public Boolean BooleanValue(ILiteral literal)
+  {
+    if (literal is IntVar || literal is NotBooleanVariable)
+    {
+      int index = literal.GetIndex();
+      return SolutionBooleanValue(index);
+    }
+    else
+    {
+      throw new ArgumentException("Cannot evaluate '" + literal.ToString() +
+                                  "' as a boolean literal");
+    }
+  }
+}
+
+public class CpSolver
+{
+
+  public CpSolverStatus Solve(CpModel model)
+  {
+    if (string_parameters_ != null)
+    {
+      response_ = SatHelper.SolveWithStringParameters(model.Model,
+                                                      string_parameters_);
+    }
+    else
+    {
+      response_ = SatHelper.Solve(model.Model);
+    }
+    return response_.Status;
+  }
+
+  public CpSolverStatus SolveWithSolutionCallback(CpModel model,
+                                                  SolutionCallback cb)
+  {
+    if (string_parameters_ != null)
+    {
+      response_ = SatHelper.SolveWithStringParametersAndSolutionCallback(
+          model.Model, string_parameters_, cb);
+    }
+    else
+    {
+      response_ = SatHelper.Solve(model.Model);
+    }
+    return response_.Status;
+  }
+
+  public CpSolverStatus SearchAllSolutions(CpModel model, SolutionCallback cb)
+  {
+    if (string_parameters_ != null)
+    {
+      string extra_parameters =
+          " enumerate_all_solutions:true, cp_model_presolve:false";
+      response_ =
+          SatHelper.SolveWithStringParametersAndSolutionCallback(
+              model.Model, string_parameters_ + extra_parameters, cb);
+    }
+    else
+    {
+      string parameters =
+          "enumerate_all_solutions:true, cp_model_presolve:false";
+      response_ = SatHelper.SolveWithStringParametersAndSolutionCallback(
+          model.Model, parameters, cb);
+    }
+    return response_.Status;
+  }
+
+  public double ObjectiveValue
+  {
+    get { return response_.ObjectiveValue; }
+  }
+
+  public string StringParameters
+  {
+    get { return string_parameters_; }
+    set { string_parameters_ = value; }
+  }
+
+  public CpSolverResponse Response
+  {
+    get { return response_; }
+  }
+
+  public long Value(IntegerExpression e)
+  {
+    List<IntegerExpression> exprs = new List<IntegerExpression>();
+    List<long> coeffs = new List<long>();
+    exprs.Add(e);
+    coeffs.Add(1L);
+    long constant = 0;
+
+    while (exprs.Count > 0)
+    {
+      IntegerExpression expr = exprs[0];
+      exprs.RemoveAt(0);
+      long coeff = coeffs[0];
+      coeffs.RemoveAt(0);
+      if (coeff == 0) continue;
+
+      if (expr is ProductCst)
+      {
+        ProductCst p = (ProductCst)expr;
+        if (p.Coeff != 0)
+        {
+          exprs.Add(p.Expr);
+          coeffs.Add(p.Coeff * coeff);
+        }
+      }
+      else if (expr is SumArray)
+      {
+        SumArray a = (SumArray)expr;
+        constant += coeff * a.Constant;
+        foreach (IntegerExpression sub in a.Expressions)
+        {
+          exprs.Add(sub);
+          coeffs.Add(coeff);
+        }
+      }
+      else if (expr is IntVar)
+      {
+        int index = expr.Index;
+        long value = index >= 0 ? response_.Solution[index]
+                                : -response_.Solution[-index - 1];
+        constant += coeff * value;
+      }
+      else if (expr is NotBooleanVariable)
+      {
+        throw new ArgumentException(
+            "Cannot evaluate a literal in an integer expression.");
+      }
+      else
+      {
+        throw new ArgumentException("Cannot evaluate '" + expr.ToString() +
+                                    "' in an integer expression");
+      }
+    }
+    return constant;
+  }
+
+  public Boolean BooleanValue(ILiteral literal)
+  {
+    if (literal is IntVar || literal is NotBooleanVariable)
+    {
+      int index = literal.GetIndex();
+      if (index >= 0)
+      {
+        return response_.Solution[index] != 0;
+      }
+      else
+      {
+        return response_.Solution[index] == 0;
+      }
+    }
+    else
+    {
+      throw new ArgumentException("Cannot evaluate '" + literal.ToString() +
+                                  "' as a boolean literal");
+    }
+  }
+
+  public long NumBranches()
+  {
+    return response_.NumBranches;
+  }
+
+  public long NumConflicts()
+  {
+    return response_.NumConflicts;
+  }
+
+  public double WallTime()
+  {
+    return response_.WallTime;
+  }
+
+
+  private CpModelProto model_;
+  private CpSolverResponse response_;
+  string string_parameters_;
+}
+
+}  // namespace Google.OrTools.Sat
diff --git a/ortools/dotnet/OrTools/sat/IntegerExpressions.cs b/ortools/dotnet/OrTools/sat/IntegerExpressions.cs
new file mode 100644
index 00000000000..287ca5e55ed
--- /dev/null
+++ b/ortools/dotnet/OrTools/sat/IntegerExpressions.cs
@@ -0,0 +1,635 @@
+// Copyright 2010-2017 Google
+// 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;
+
+// Helpers.
+
+// IntVar[] helper class.
+public static class IntVarArrayHelper
+{
+  public static SumArray Sum(this IntVar[] vars)
+  {
+    return new SumArray(vars);
+  }
+}
+
+public interface ILiteral
+{
+  ILiteral Not();
+  int GetIndex();
+}
+
+// Holds an integer expression.
+public class IntegerExpression
+{
+
+  public int Index
+  {
+    get { return GetIndex(); }
+  }
+
+  public virtual int GetIndex()
+  {
+    throw new NotImplementedException();
+  }
+
+  public virtual string ShortString()
+  {
+    return ToString();
+  }
+
+  public static IntegerExpression operator+(IntegerExpression a,
+                                            IntegerExpression b) {
+    return new SumArray(a, b);
+  }
+
+  public static IntegerExpression operator+(IntegerExpression a, long v) {
+    return new SumArray(a, v);
+  }
+
+  public static IntegerExpression operator+(long v, IntegerExpression a) {
+    return new SumArray(a, v);
+  }
+
+  public static IntegerExpression operator-(IntegerExpression a,
+                                            IntegerExpression b) {
+    return new SumArray(a, Prod(b, -1));
+  }
+
+  public static IntegerExpression operator-(IntegerExpression a, long v) {
+    return new SumArray(a, -v);
+  }
+
+  public static IntegerExpression operator-(long v, IntegerExpression a) {
+    return new SumArray(Prod(a, -1), v);
+  }
+
+  public static IntegerExpression operator*(IntegerExpression a, long v) {
+    return Prod(a, v);
+  }
+
+  public static IntegerExpression operator*(long v, IntegerExpression a) {
+    return Prod(a, v);
+  }
+
+  public static IntegerExpression operator-(IntegerExpression a) {
+    return Prod(a, -1);
+  }
+
+  public static BoundIntegerExpression operator ==(IntegerExpression a,
+                                                   IntegerExpression b) {
+    return new BoundIntegerExpression(a, b, true);
+  }
+
+  public static BoundIntegerExpression operator !=(IntegerExpression a,
+                                                   IntegerExpression b) {
+    return new BoundIntegerExpression(a, b, false);
+  }
+
+  public static BoundIntegerExpression operator ==(IntegerExpression a,
+                                                   long v) {
+    return new BoundIntegerExpression(a, v, true);
+  }
+
+  public static BoundIntegerExpression operator !=(IntegerExpression a,
+                                                   long v) {
+    return new BoundIntegerExpression(a, v, false);
+  }
+
+  public static BoundIntegerExpression operator >=(IntegerExpression a,
+                                                   long v) {
+    return new BoundIntegerExpression(v, a, Int64.MaxValue);
+  }
+
+  public static BoundIntegerExpression operator >=(long v,
+                                                   IntegerExpression a) {
+    return a <= v;
+  }
+
+  public static BoundIntegerExpression operator >(IntegerExpression a,
+                                                  long v) {
+    return new BoundIntegerExpression(v + 1, a, Int64.MaxValue);
+  }
+
+  public static BoundIntegerExpression operator >(long v, IntegerExpression a) {
+    return a < v;
+  }
+
+  public static BoundIntegerExpression operator <=(IntegerExpression a,
+                                                   long v) {
+    return new BoundIntegerExpression(Int64.MinValue, a, v);
+  }
+
+    public static BoundIntegerExpression operator <=(long v,
+                                                     IntegerExpression a) {
+      return a >= v;
+  }
+
+  public static BoundIntegerExpression operator <(IntegerExpression a,
+                                                  long v) {
+    return new BoundIntegerExpression(Int64.MinValue, a, v - 1);
+  }
+
+  public static BoundIntegerExpression operator <(long v, IntegerExpression a) {
+    return a > v;
+  }
+
+  public static BoundIntegerExpression operator >=(IntegerExpression a,
+                                                   IntegerExpression b) {
+    return new BoundIntegerExpression(0, a - b, Int64.MaxValue);
+  }
+
+  public static BoundIntegerExpression operator >(IntegerExpression a,
+                                                  IntegerExpression b) {
+    return new BoundIntegerExpression(1, a - b, Int64.MaxValue);
+  }
+
+  public static BoundIntegerExpression operator <=(IntegerExpression a,
+                                                   IntegerExpression b) {
+    return new BoundIntegerExpression(Int64.MinValue, a - b, 0);
+  }
+
+  public static BoundIntegerExpression operator <(IntegerExpression a,
+                                                  IntegerExpression b) {
+    return new BoundIntegerExpression(Int64.MinValue, a - b, -1);
+  }
+
+  public static IntegerExpression Prod(IntegerExpression e, long v)
+  {
+    if (v == 1)
+    {
+      return e;
+    }
+    else if (e is ProductCst)
+    {
+      ProductCst p = (ProductCst)e;
+      return new ProductCst(p.Expr, p.Coeff * v);
+    }
+    else
+    {
+      return new ProductCst(e, v);
+    }
+  }
+
+  public static long GetVarValueMap(IntegerExpression e,
+                                    long initial_coeff,
+                                    Dictionary<IntVar, long> dict)
+  {
+    List<IntegerExpression> exprs = new List<IntegerExpression>();
+    List<long> coeffs = new List<long>();
+    exprs.Add(e);
+    coeffs.Add(initial_coeff);
+    long constant = 0;
+
+    while (exprs.Count > 0)
+    {
+      IntegerExpression expr = exprs[0];
+      exprs.RemoveAt(0);
+      long coeff = coeffs[0];
+      coeffs.RemoveAt(0);
+      if (coeff == 0) continue;
+
+      if (expr is ProductCst)
+      {
+        ProductCst p = (ProductCst)expr;
+        if (p.Coeff != 0)
+        {
+          exprs.Add(p.Expr);
+          coeffs.Add(p.Coeff * coeff);
+        }
+      }
+      else if (expr is SumArray)
+      {
+        SumArray a = (SumArray)expr;
+        constant += coeff * a.Constant;
+        foreach (IntegerExpression sub in a.Expressions)
+        {
+          exprs.Add(sub);
+          coeffs.Add(coeff);
+        }
+      }
+      else if (expr is IntVar)
+      {
+        IntVar i = (IntVar)expr;
+        if (dict.ContainsKey(i))
+        {
+          dict[i] += coeff;
+        }
+        else
+        {
+          dict.Add(i, coeff);
+        }
+
+      }
+      else if (expr is NotBooleanVariable)
+      {
+        throw new ArgumentException(
+            "Cannot interpret a literal in an integer expression.");
+      }
+      else
+      {
+        throw new ArgumentException("Cannot interpret '" + expr.ToString() +
+                                    "' in an integer expression");
+      }
+    }
+    return constant;
+  }
+}
+
+public class ProductCst : IntegerExpression
+{
+  public ProductCst(IntegerExpression e, long v)
+  {
+    expr_ = e;
+    coeff_ = v;
+  }
+
+  public IntegerExpression Expr
+  {
+    get { return expr_; }
+  }
+
+  public long Coeff
+  {
+    get { return coeff_; }
+  }
+
+  private IntegerExpression expr_;
+  private long coeff_;
+
+}
+
+public class SumArray : IntegerExpression
+{
+  public SumArray(IntegerExpression a, IntegerExpression b)
+  {
+    expressions_ = new List<IntegerExpression>();
+    expressions_.Add(a);
+    expressions_.Add(b);
+    constant_ = 0L;
+  }
+
+  public SumArray(IntegerExpression a, long b)
+  {
+    expressions_.Add(a);
+    constant_ = b;
+  }
+
+  public SumArray(IEnumerable<IntegerExpression> exprs)
+  {
+    expressions_ = new List<IntegerExpression>();
+    foreach (IntegerExpression e in exprs)
+    {
+      if (e != null)
+      {
+        expressions_.Add(e);
+      }
+    }
+    constant_ = 0L;
+  }
+
+  public SumArray(IEnumerable<IntegerExpression> exprs, long cte)
+  {
+    expressions_ = new List<IntegerExpression>();
+    foreach (IntegerExpression e in exprs)
+    {
+      if (e != null)
+      {
+        expressions_.Add(e);
+      }
+    }
+    constant_ = cte;
+  }
+
+  public List<IntegerExpression> Expressions
+  {
+    get { return expressions_; }
+  }
+
+  public long Constant
+  {
+    get { return constant_; }
+  }
+
+  public override string ShortString()
+  {
+    return String.Format("({0})", ToString());
+  }
+
+  public override string ToString()
+  {
+    string result = "";
+    for (int i = 0; i < expressions_.Count; ++i)
+    {
+      bool negated = false;
+      IntegerExpression expr = expressions_[i];
+      if (i != 0)
+      {
+        if (expr is ProductCst && ((ProductCst)expr).Coeff < 0)
+        {
+          result += String.Format(" - ");
+          negated = true;
+        }
+        else
+        {
+          result += String.Format(" + ");
+        }
+      }
+
+      if (expr is IntVar)
+      {
+        result += expr.ShortString();
+      }
+      else if (expr is ProductCst)
+      {
+        ProductCst p = (ProductCst)expr;
+        long coeff = negated ? -p.Coeff : p.Coeff;
+        IntegerExpression sub = p.Expr;
+        if (coeff == 1)
+        {
+          result += sub.ShortString();
+        }
+        else if (coeff == -1)
+        {
+          result += String.Format("-{0}", coeff, sub.ShortString());
+        }
+        else
+        {
+          result += String.Format("{0}*{1}", coeff, sub.ShortString());
+        }
+      }
+      else
+      {
+        result += String.Format("({0})", expr.ShortString());
+      }
+    }
+    return result;
+  }
+
+  private List<IntegerExpression> expressions_;
+  private long constant_;
+
+}
+
+public class IntVar : IntegerExpression, ILiteral
+{
+  public IntVar(CpModelProto model, IEnumerable<long> bounds,
+                int is_present_index, string name) {
+    model_ = model;
+    index_ = model.Variables.Count;
+    var_ = new IntegerVariableProto();
+    var_.Name = name;
+    var_.Domain.Add(bounds);
+    var_.EnforcementLiteral.Add(is_present_index);
+    model.Variables.Add(var_);
+    negation_ = null;
+  }
+
+  public IntVar(CpModelProto model, IEnumerable<long> bounds, string name) {
+    model_ = model;
+    index_ = model.Variables.Count;
+    var_ = new IntegerVariableProto();
+    var_.Name = name;
+    var_.Domain.Add(bounds);
+    model.Variables.Add(var_);
+    negation_ = null;
+  }
+
+  public override int GetIndex()
+  {
+    return index_;
+  }
+
+  public override string ToString()
+  {
+    return var_.ToString();
+  }
+
+  public override string ShortString()
+  {
+    if (var_.Name != null)
+    {
+      return var_.Name;
+    }
+    else
+    {
+      return var_.ToString();
+    }
+  }
+
+  public ILiteral Not()
+  {
+    foreach (long b in var_.Domain)
+    {
+      if (b < 0 || b > 1)
+      {
+        throw new ArgumentException(
+            "Cannot call Not() on a non boolean variable");
+      }
+    }
+    if (negation_ == null)
+    {
+      negation_ = new NotBooleanVariable(this);
+    }
+    return negation_;
+  }
+
+
+  private CpModelProto model_;
+  private int index_;
+  private List<long> bounds_;
+  private IntegerVariableProto var_;
+  private NotBooleanVariable negation_;
+}
+
+public class NotBooleanVariable : IntegerExpression, ILiteral
+{
+  public NotBooleanVariable(IntVar boolvar)
+  {
+    boolvar_ = boolvar;
+  }
+
+  public override int GetIndex()
+  {
+    return -boolvar_.Index - 1;
+  }
+
+  public ILiteral Not()
+  {
+    return boolvar_;
+  }
+
+  public string ShortString()
+  {
+    return String.Format("Not({0})", boolvar_.ShortString());
+  }
+
+  private IntVar boolvar_;
+}
+
+public class BoundIntegerExpression
+{
+  public enum Type
+  {
+    BoundExpression,
+    VarEqVar,
+    VarDiffVar,
+    VarEqCst,
+    VarDiffCst,
+  }
+
+  public BoundIntegerExpression(long lb, IntegerExpression expr, long ub)
+  {
+    left_ = expr;
+    right_ = null;
+    lb_ = lb;
+    ub_ = ub;
+    type_ = Type.BoundExpression;
+  }
+
+  public BoundIntegerExpression(IntegerExpression left, IntegerExpression right,
+                                bool equality) {
+    left_ = left;
+    right_ = right;
+    lb_ = 0;
+    ub_ = 0;
+    type_ = equality ? Type.VarEqVar : Type.VarDiffVar;
+  }
+
+  public BoundIntegerExpression(IntegerExpression left, long v, bool equality) {
+    left_ = left;
+    right_ = null;
+    lb_ = v;
+    ub_ = 0;
+    type_ = equality ? Type.VarEqCst : Type.VarDiffCst;
+  }
+
+  bool IsTrue()
+  {
+    if (type_ == Type.VarEqVar)
+    {
+      return (object)left_ == (object)right_;
+    }
+    else if (type_ == Type.VarDiffVar)
+    {
+      return (object)left_ != (object)right_;
+    }
+    return false;
+  }
+
+  public static bool operator true(BoundIntegerExpression bie)
+  {
+    return bie.IsTrue();
+  }
+
+  public static bool operator false(BoundIntegerExpression bie)
+  {
+    return !bie.IsTrue();
+  }
+
+  public override string ToString()
+  {
+    switch (type_)
+    {
+      case Type.BoundExpression:
+        return String.Format("{0} <= {1} <= {2}", lb_, left_, ub_);
+      case Type.VarEqVar:
+        return String.Format("{0} == {1}", left_, right_);
+      case Type.VarDiffVar:
+        return String.Format("{0} != {1}", left_, right_);
+      case Type.VarEqCst:
+        return String.Format("{0} == {1}", left_, lb_);
+      case Type.VarDiffCst:
+        return String.Format("{0} != {1}", left_, lb_);
+      default:
+        throw new ArgumentException("Wrong mode in BoundIntegerExpression.");
+    }
+  }
+
+  public static BoundIntegerExpression operator <=(BoundIntegerExpression a,
+                                                   long v) {
+    if (a.CtType != Type.BoundExpression || a.Ub != Int64.MaxValue)
+    {
+      throw new ArgumentException(
+          "Operator <= not supported for this BoundIntegerExpression");
+    }
+    return new BoundIntegerExpression(a.Lb, a.Left, v);
+  }
+
+  public static BoundIntegerExpression operator <(BoundIntegerExpression a,
+                                                  long v) {
+    if (a.CtType != Type.BoundExpression || a.Ub != Int64.MaxValue)
+    {
+      throw new ArgumentException(
+          "Operator < not supported for this BoundIntegerExpression");
+    }
+    return new BoundIntegerExpression(a.Lb, a.Left, v - 1);
+  }
+
+  public static BoundIntegerExpression operator >=(BoundIntegerExpression a,
+                                                   long v) {
+    if (a.CtType != Type.BoundExpression || a.Lb != Int64.MinValue)
+    {
+      throw new ArgumentException(
+          "Operator >= not supported for this BoundIntegerExpression");
+    }
+    return new BoundIntegerExpression(v, a.Left, a.Ub);
+  }
+
+  public static BoundIntegerExpression operator >(BoundIntegerExpression a,
+                                                  long v) {
+    if (a.CtType != Type.BoundExpression || a.Lb != Int64.MinValue)
+    {
+      throw new ArgumentException(
+          "Operator < not supported for this BoundIntegerExpression");
+    }
+    return new BoundIntegerExpression(v + 1, a.Left, a.Ub);
+  }
+
+  public IntegerExpression Left
+  {
+    get { return left_; }
+  }
+
+  public IntegerExpression Right
+  {
+    get { return right_; }
+  }
+
+  public long Lb
+  {
+    get { return lb_; }
+  }
+
+  public long Ub
+  {
+    get { return ub_; }
+  }
+
+  public Type CtType
+  {
+    get { return type_; }
+  }
+
+  private IntegerExpression left_;
+  private IntegerExpression right_;
+  private long lb_;
+  private long ub_;
+  private Type type_;
+}
+
+}  // namespace Google.OrTools.Sat
diff --git a/ortools/dotnet/OrTools/sat/IntervalVariables.cs b/ortools/dotnet/OrTools/sat/IntervalVariables.cs
new file mode 100644
index 00000000000..a1c324ec6a6
--- /dev/null
+++ b/ortools/dotnet/OrTools/sat/IntervalVariables.cs
@@ -0,0 +1,69 @@
+// Copyright 2010-2017 Google
+// 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;
+
+public class IntervalVar
+{
+  public IntervalVar(CpModelProto model,
+                     int start_index, int size_index, int end_index,
+                     int is_present_index, string name) {
+    model_ = model;
+    index_ = model.Constraints.Count;
+    interval_ = new IntervalConstraintProto();
+    interval_.Start = start_index;
+    interval_.Size = size_index;
+    interval_.End = end_index;
+
+    ConstraintProto ct = new ConstraintProto();
+    ct.Interval = interval_;
+    ct.Name = name;
+    ct.EnforcementLiteral.Add(is_present_index);
+    model.Constraints.Add(ct);
+  }
+
+  public IntervalVar(CpModelProto model,
+                     int start_index, int size_index, int end_index,
+                     string name) {
+    model_ = model;
+    index_ = model.Constraints.Count;
+    interval_ = new IntervalConstraintProto();
+    interval_.Start = start_index;
+    interval_.Size = size_index;
+    interval_.End = end_index;
+
+    ConstraintProto ct = new ConstraintProto();
+    ct.Interval = interval_;
+    ct.Name = name;
+    model_.Constraints.Add(ct);
+  }
+
+  public int GetIndex()
+  {
+    return index_;
+  }
+
+  public override string ToString()
+  {
+    return model_.Constraints[index_].ToString();
+  }
+
+  private CpModelProto model_;
+  private int index_;
+  private IntervalConstraintProto interval_;
+}
+
+}  // namespace Google.OrTools.Sat
diff --git a/ortools/dotnet/OrTools/util/NestedArrayHelper.cs b/ortools/dotnet/OrTools/util/NestedArrayHelper.cs
new file mode 100644
index 00000000000..e543047862e
--- /dev/null
+++ b/ortools/dotnet/OrTools/util/NestedArrayHelper.cs
@@ -0,0 +1,49 @@
+// Copyright 2010-2017 Google
+// 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 {
+
+using System;
+using System.Collections.Generic;
+
+public static class NestedArrayHelper
+{
+  public static T[] GetFlatArray<T>(T[][] arr)
+  {
+    int flatLength = 0;
+    for (var i = 0; i < arr.GetLength(0); i++)
+      flatLength += arr[i].GetLength(0);
+
+    int idx = 0;
+    T[] flat = new T[flatLength];
+
+    for (int i = 0; i < arr.GetLength(0); i++)
+    {
+      for (int j = 0; j < arr[i].GetLength(0); j++)
+        flat[idx++] = arr[i][j];
+    }
+
+    return flat;
+  }
+  public static int[] GetArraySecondSize<T>(T[][]arr)
+  {
+    var result = new int[arr.GetLength(0)];
+    for (var i=0; i<arr.GetLength(0); i++)
+    {
+      if (arr[i] != null)
+        result[i] = arr[i].Length;
+    }
+    return result;
+  }
+}
+}  // namespace Google.OrTools
diff --git a/ortools/dotnet/OrTools/util/ProtoHelper.cs b/ortools/dotnet/OrTools/util/ProtoHelper.cs
new file mode 100644
index 00000000000..e82c32b1948
--- /dev/null
+++ b/ortools/dotnet/OrTools/util/ProtoHelper.cs
@@ -0,0 +1,30 @@
+// Copyright 2010-2017 Google
+// 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 {
+
+using System;
+using Google.Protobuf;
+
+public static class ProtoHelper
+{
+  public static byte[] ProtoToByteArray(IMessage message)
+  {
+    int size = message.CalculateSize();
+    byte[] buffer = new byte[size];
+    CodedOutputStream output = new CodedOutputStream(buffer);
+    message.WriteTo(output);
+    return buffer;
+  }
+}
+}  // namespace Google.OrTools
diff --git a/ortools/dotnet/README.md b/ortools/dotnet/README.md
new file mode 100644
index 00000000000..e06bedc45aa
--- /dev/null
+++ b/ortools/dotnet/README.md
@@ -0,0 +1,5 @@
+# Google OrTools
+
+## Pre-requisites
+- dotnet core 2.0
+- mono 5.4