Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions cmake/dependencies/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ if(BUILD_ZLIB)
zlib
GIT_REPOSITORY "https://github.com/madler/ZLIB.git"
GIT_TAG "v1.2.11"
PATCH_COMMAND git apply "${CMAKE_CURRENT_LIST_DIR}/../../patches/ZLIB.patch")
PATCH_COMMAND git apply --ignore-whitespace "${CMAKE_CURRENT_LIST_DIR}/../../patches/ZLIB.patch")
FetchContent_MakeAvailable(zlib)
list(POP_BACK CMAKE_MESSAGE_INDENT)
message(CHECK_PASS "fetched")
Expand All @@ -67,7 +67,7 @@ if(BUILD_absl)
absl
GIT_REPOSITORY "https://github.com/abseil/abseil-cpp.git"
GIT_TAG "20210324.2"
PATCH_COMMAND git apply "${CMAKE_CURRENT_LIST_DIR}/../../patches/abseil-cpp-20210324.2.patch")
PATCH_COMMAND git apply --ignore-whitespace "${CMAKE_CURRENT_LIST_DIR}/../../patches/abseil-cpp-20210324.2.patch")
FetchContent_MakeAvailable(absl)
list(POP_BACK CMAKE_MESSAGE_INDENT)
message(CHECK_PASS "fetched")
Expand Down Expand Up @@ -116,15 +116,15 @@ if(BUILD_Protobuf)
GIT_REPOSITORY "https://github.com/protocolbuffers/protobuf.git"
GIT_TAG "v3.17.3"
GIT_SUBMODULES ""
PATCH_COMMAND git apply "${CMAKE_CURRENT_LIST_DIR}/../../patches/protobuf-v3.17.3.patch"
PATCH_COMMAND git apply --ignore-whitespace "${CMAKE_CURRENT_LIST_DIR}/../../patches/protobuf-v3.17.3.patch"
SOURCE_SUBDIR cmake)
FetchContent_MakeAvailable(protobuf)
else()
fetch_git_dependency(
NAME Protobuf
REPOSITORY "https://github.com/protocolbuffers/protobuf.git"
TAG "v3.17.3"
PATCH_COMMAND "git apply \"${CMAKE_CURRENT_LIST_DIR}/../../patches/protobuf-v3.17.3.patch\""
PATCH_COMMAND "git apply --ignore-whitespace \"${CMAKE_CURRENT_LIST_DIR}/../../patches/protobuf-v3.17.3.patch\""
SOURCE_SUBDIR cmake
)
endif()
Expand Down
1 change: 1 addition & 0 deletions makefiles/Makefile.dotnet.mk
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ $(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 \
$(SRC_DIR)/ortools/linear_solver/linear_solver_swig_helper.h \
$(GLOP_DEPS) \
$(LP_DEPS) \
| $(GEN_DIR)/ortools/linear_solver
Expand Down
2 changes: 2 additions & 0 deletions makefiles/Makefile.gen.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3625,6 +3625,7 @@ LP_DEPS = \
$(SRC_DIR)/ortools/linear_solver/glop_utils.h \
$(SRC_DIR)/ortools/linear_solver/gurobi_proto_solver.h \
$(SRC_DIR)/ortools/linear_solver/linear_expr.h \
$(SRC_DIR)/ortools/linear_solver/linear_solver_swig_helper.h \
$(SRC_DIR)/ortools/linear_solver/linear_solver_callback.h \
$(SRC_DIR)/ortools/linear_solver/linear_solver.h \
$(SRC_DIR)/ortools/linear_solver/model_exporter.h \
Expand Down Expand Up @@ -3863,6 +3864,7 @@ objs/linear_solver/linear_solver.$O: \
ortools/gen/ortools/linear_solver/linear_solver.pb.h \
ortools/gen/ortools/util/optional_boolean.pb.h \
ortools/linear_solver/linear_solver_callback.h \
ortools/linear_solver/linear_solver_swig_helper.h \
ortools/port/proto_utils.h ortools/base/accurate_sum.h \
ortools/base/map_util.h ortools/base/status_macros.h \
ortools/base/status_builder.h ortools/base/stl_util.h \
Expand Down
5 changes: 5 additions & 0 deletions ortools/linear_solver/csharp/SolverHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,11 @@ public void Maximize(Variable var)
Objective().SetMaximization();
Objective().SetCoefficient(var, 1.0);
}

public void SetCallback(LinearSolutionCallback callback)
{
SetCallback((MPCallback)callback);
}
}

} // namespace Google.OrTools.LinearSolver
66 changes: 66 additions & 0 deletions ortools/linear_solver/csharp/linear_solver.i
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@
%{
#include "ortools/linear_solver/linear_solver.h"
#include "ortools/linear_solver/linear_solver.pb.h"
#include "ortools/linear_solver/linear_solver_callback.h"
#include "ortools/linear_solver/linear_solver_swig_helper.h"
#include "ortools/linear_solver/model_exporter.h"
%}

%module(directors="1") operations_research_linear

// We need to forward-declare the proto here, so that the PROTO_* macros
// involving them work correctly. The order matters very much: this declaration
Expand All @@ -49,6 +52,7 @@ namespace operations_research {
class MPModelProto;
class MPModelRequest;
class MPSolutionResponse;
class MPCallback;
} // namespace operations_research

// Allow partial C# classes. That way, we can put our C# code extension in C#
Expand Down Expand Up @@ -82,6 +86,8 @@ CONVERT_VECTOR(operations_research::MPVariable, MPVariable)
%rename (Constraint) operations_research::MPConstraint;
%rename (Objective) operations_research::MPObjective;
%rename (SolverParameters) operations_research::MPSolverParameters;
%rename (SolverCallbackContext) operations_research::MPCallbackContext;
%rename (SolverSolutionCallbackEvent) operations_research::MPCallbackEvent;

// Expose the MPSolver::OptimizationProblemType enum.
%unignore operations_research::MPSolver::OptimizationProblemType;
Expand Down Expand Up @@ -132,6 +138,7 @@ CONVERT_VECTOR(operations_research::MPVariable, MPVariable)
%unignore operations_research::MPSolver::Solve;
%unignore operations_research::MPSolver::VerifySolution;
%unignore operations_research::MPSolver::Reset;
%unignore operations_research::MPSolver::SupportsCallbacks;
%rename (SetTimeLimit) operations_research::MPSolver::set_time_limit;

// Expose some of the more advanced MPSolver API.
Expand Down Expand Up @@ -170,6 +177,8 @@ CONVERT_VECTOR(operations_research::MPVariable, MPVariable)
const std::vector<operations_research::MPVariable*>&,
const std::vector<double>&);
%unignore operations_research::MPSolver::SetNumThreads;
%unignore operations_research::MPSolver::SetCallback;
%csmethodmodifiers operations_research::MPSolver::SetCallback "internal";
%extend operations_research::MPSolver {
std::string ExportModelAsLpFormat(bool obfuscated) {
operations_research::MPModelExportOptions options;
Expand Down Expand Up @@ -302,7 +311,64 @@ CONVERT_VECTOR(operations_research::MPVariable, MPVariable)
%unignore operations_research::MPSolverParameters::SCALING_OFF; // no test
%unignore operations_research::MPSolverParameters::SCALING_ON; // no test

// Callback API

// Expose callback event type enum
%unignore operations_research::MPCallbackEvent::kUnknown;
%rename (Unknown) operations_research::MPCallbackEvent::kUnknown;
%unignore operations_research::MPCallbackEvent::kPolling;
%rename (Polling) operations_research::MPCallbackEvent::kPolling;
%unignore operations_research::MPCallbackEvent::kPresolve;
%rename (Presolve) operations_research::MPCallbackEvent::kPresolve;
%unignore operations_research::MPCallbackEvent::kSimplex;
%rename (Simplex) operations_research::MPCallbackEvent::kSimplex;
%unignore operations_research::MPCallbackEvent::kMip;
%rename (Mip) operations_research::MPCallbackEvent::kMip;
%unignore operations_research::MPCallbackEvent::kMipSolution;
%rename (MipSolution) operations_research::MPCallbackEvent::kMipSolution;
%unignore operations_research::MPCallbackEvent::kMipNode;
%rename (MipNode) operations_research::MPCallbackEvent::kMipNode;
%unignore operations_research::MPCallbackEvent::kBarrier;
%rename (Barrier) operations_research::MPCallbackEvent::kBarrier;
%unignore operations_research::MPCallbackEvent::kMessage;
%rename (Message) operations_research::MPCallbackEvent::kMessage;
%unignore operations_research::MPCallbackEvent::kMultiObj;
%rename (MultiObj) operations_research::MPCallbackEvent::kMultiObj;

// MPCallbackContext
%unignore operations_research::MPCallbackContext::MPCallbackContext;
%unignore operations_research::MPCallbackContext::~MPCallbackContext;
%rename (GetEventType) operations_research::MPCallbackContext::Event;
%unignore operations_research::MPCallbackContext::CanQueryVariableValues;
%unignore operations_research::MPCallbackContext::VariableValue;
%unignore operations_research::MPCallbackContext::NumExploredNodes;

%unignore operations_research::MPCallback;

%feature("director") operations_research::LinearSolutionCallback;
%unignore operations_research::LinearSolutionCallback;
%unignore operations_research::LinearSolutionCallback::LinearSolutionCallback;
%unignore operations_research::LinearSolutionCallback::~LinearSolutionCallback;
%unignore operations_research::LinearSolutionCallback::VariableValue;
%feature("nodirector") operations_research::LinearSolutionCallback::VariableValue;
%unignore operations_research::LinearSolutionCallback::CanQueryVariableValues;
%feature("nodirector") operations_research::LinearSolutionCallback::CanQueryVariableValues;
%unignore operations_research::LinearSolutionCallback::Event;
%feature("nodirector") operations_research::LinearSolutionCallback::Event;
%rename (GetEventType) operations_research::LinearSolutionCallback::Event;
%unignore operations_research::LinearSolutionCallback::NumExploredNodes;
%feature("nodirector") operations_research::LinearSolutionCallback::NumExploredNodes;
%unignore operations_research::LinearSolutionCallback::GetRelativeMipGap;
%feature("nodirector") operations_research::LinearSolutionCallback::GetRelativeMipGap;
%unignore operations_research::LinearSolutionCallback::HasValidMipSolution;
%feature("nodirector") operations_research::LinearSolutionCallback::HasValidMipSolution;
%unignore operations_research::LinearSolutionCallback::IsNewSolution;
%feature("nodirector") operations_research::LinearSolutionCallback::IsNewSolution;
%unignore operations_research::LinearSolutionCallback::OnSolutionCallback;

%include "ortools/linear_solver/linear_solver.h"
%include "ortools/linear_solver/linear_solver_callback.h"
%include "ortools/linear_solver/linear_solver_swig_helper.h"
%include "ortools/linear_solver/model_exporter.h"

%unignoreall
6 changes: 6 additions & 0 deletions ortools/linear_solver/linear_solver_callback.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ class MPCallbackContext {
//
// Call only when the event is kMipSolution or kMipNode.
virtual int64_t NumExploredNodes() = 0;

virtual double GetRelativeMipGap() { return 0; }

virtual bool HasValidMipSolution() { return false; }

virtual bool IsNewSolution() { return false; }
};

// Extend this class with model specific logic, and register through
Expand Down
58 changes: 58 additions & 0 deletions ortools/linear_solver/linear_solver_swig_helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2010-2021 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// See go/mpsolver-callbacks for documentation on how to use this file.

#ifndef OR_TOOLS_LINEAR_SOLVER_SWIG_HELPER_H_
#define OR_TOOLS_LINEAR_SOLVER_SWIG_HELPER_H_

#include "ortools/linear_solver/linear_solver.h"
#include "ortools/linear_solver/linear_solver_callback.h"

namespace operations_research {
class LinearSolutionCallback : public MPCallback {
public:
LinearSolutionCallback() : MPCallback(false, false) {
context_ = NULL;
}

virtual ~LinearSolutionCallback() {}

virtual void OnSolutionCallback() {}

double VariableValue(const MPVariable* variable) { return context_->VariableValue(variable); }

bool CanQueryVariableValues(){ return context_->CanQueryVariableValues(); }

MPCallbackEvent Event() { return context_->Event(); }

int64_t NumExploredNodes() { return context_->NumExploredNodes(); }

double GetRelativeMipGap() { return context_->GetRelativeMipGap(); }

bool HasValidMipSolution() { return context_->HasValidMipSolution(); }

bool IsNewSolution() { return context_->IsNewSolution(); }

void RunCallback(MPCallbackContext* callback_context) override{
context_ = callback_context;

OnSolutionCallback();
}

private:
MPCallbackContext* context_;
};
} // namespace operations_research

#endif // OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_CALLBACK_H_
2 changes: 2 additions & 0 deletions ortools/linear_solver/scip_callback.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ class ScipConstraintHandlerContext {
// TODO(user): maybe this can be abstracted away.
bool is_pseudo_solution() const { return is_pseudo_solution_; }

bool IsNewSolution() const { return solution_ != SCIPgetBestSol(scip_); }

private:
SCIP* scip_;
SCIP_SOL* solution_;
Expand Down
16 changes: 16 additions & 0 deletions ortools/linear_solver/scip_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,22 @@ class ScipMPCallbackContext : public MPCallbackContext {
LOG(FATAL) << "SuggestSolution() not currently supported for SCIP.";
}

double GetRelativeMipGap() override {
SCIP* scip = scip_context_->scip();
SCIP_SET* set = scip->set;

return SCIPcomputeGap(set->num_epsilon, set->num_infinity, SCIPgetPrimalbound(scip), SCIPgetDualbound(scip));
}

bool HasValidMipSolution() override {
SCIP* scip = scip_context_->scip();
return SCIPgetBestSol(scip) != 0;
}

bool IsNewSolution() {
return HasValidMipSolution() && scip_context_->IsNewSolution();
}

int64_t NumExploredNodes() override {
// scip_context_->NumNodesProcessed() returns:
// 0 before the root node is solved, e.g. if a heuristic finds a solution.
Expand Down