2014-07-09 10:01:48 +00:00
|
|
|
// Copyright 2010-2014 Google
|
2011-04-11 15:00:18 +00:00
|
|
|
// 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.
|
2014-07-09 15:18:27 +00:00
|
|
|
|
2014-07-09 10:01:48 +00:00
|
|
|
// This .swig file exposes the linear programming and integer programming
|
|
|
|
|
//
|
|
|
|
|
// The python API is enriched by custom code defined here, making it
|
|
|
|
|
// extremely intuitive, like:
|
|
|
|
|
// solver = pywraplp.Solver(pywraplp.Solver.LINEAR_PROGRAMMING_GLOP)
|
|
|
|
|
// x1 = solver.NumVar(0.0, 1.0, 'x1')
|
|
|
|
|
// x2 = solver.NumVar(-3.0, 2.0, 'x2')
|
|
|
|
|
// c1 = solver.Add(2 * x1 - 3.2 * x2 + 1 <= 2.5)
|
|
|
|
|
// solver.Maximize(10 * x1 + 6 * x2)
|
|
|
|
|
//
|
|
|
|
|
// USAGE EXAMPLES:
|
|
|
|
|
// - python/linear_programming.py
|
|
|
|
|
// - ./pywraplp_test.py
|
|
|
|
|
//
|
|
|
|
|
// TODO(user): test all the APIs that are currently marked as 'untested'.
|
2011-03-31 08:39:26 +00:00
|
|
|
|
2015-06-16 10:08:44 +02:00
|
|
|
%include "base/base.swig"
|
2014-06-13 10:03:03 +00:00
|
|
|
|
2011-03-31 08:39:26 +00:00
|
|
|
|
2015-11-20 11:32:37 +01:00
|
|
|
// We need to forward-declare the proto here, so that the PROTO_* macros
|
|
|
|
|
// involving them work correctly. The order matters very much: this declaration
|
|
|
|
|
// needs to be before the %{ #include ".../linear_solver.h" %}.
|
|
|
|
|
namespace operations_research {
|
|
|
|
|
class MPModelProto;
|
|
|
|
|
class MPModelRequest;
|
|
|
|
|
class MPSolutionResponse;
|
|
|
|
|
} // namespace operations_research
|
|
|
|
|
|
2011-03-31 08:39:26 +00:00
|
|
|
%{
|
2014-07-09 10:01:48 +00:00
|
|
|
#include "linear_solver/linear_solver.h"
|
2011-03-31 08:39:26 +00:00
|
|
|
%}
|
|
|
|
|
|
|
|
|
|
namespace operations_research {
|
|
|
|
|
|
2014-07-09 10:01:48 +00:00
|
|
|
%pythoncode {
|
2015-11-02 15:27:08 +01:00
|
|
|
import numbers
|
2016-02-03 15:15:58 +01:00
|
|
|
from ortools.linear_solver.linear_solver_natural_api import OFFSET_KEY
|
|
|
|
|
from ortools.linear_solver.linear_solver_natural_api import inf
|
2014-07-09 10:01:48 +00:00
|
|
|
from ortools.linear_solver.linear_solver_natural_api import LinearExpr
|
|
|
|
|
from ortools.linear_solver.linear_solver_natural_api import ProductCst
|
|
|
|
|
from ortools.linear_solver.linear_solver_natural_api import Sum
|
|
|
|
|
from ortools.linear_solver.linear_solver_natural_api import SumArray
|
|
|
|
|
from ortools.linear_solver.linear_solver_natural_api import SumCst
|
|
|
|
|
from ortools.linear_solver.linear_solver_natural_api import LinearConstraint
|
2016-02-03 15:15:58 +01:00
|
|
|
from ortools.linear_solver.linear_solver_natural_api import VariableExpr
|
2014-07-09 10:01:48 +00:00
|
|
|
} // %pythoncode
|
2011-03-31 08:39:26 +00:00
|
|
|
|
|
|
|
|
%extend MPVariable {
|
2014-07-24 18:12:50 +00:00
|
|
|
std::string __str__() {
|
2015-06-16 10:08:44 +02:00
|
|
|
return $self->name();
|
2011-03-31 08:39:26 +00:00
|
|
|
}
|
2014-07-24 18:12:50 +00:00
|
|
|
std::string __repr__() {
|
2015-06-16 10:08:44 +02:00
|
|
|
return $self->name();
|
2011-03-31 08:39:26 +00:00
|
|
|
}
|
2013-12-29 11:31:40 +00:00
|
|
|
|
2014-07-09 10:01:48 +00:00
|
|
|
%pythoncode {
|
2016-02-03 15:15:58 +01:00
|
|
|
def __getattr__(self, name):
|
|
|
|
|
return getattr(VariableExpr(self), name)
|
2014-07-09 10:01:48 +00:00
|
|
|
} // %pythoncode
|
2011-03-31 08:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
%extend MPSolver {
|
2015-06-18 14:26:12 +02:00
|
|
|
// Change a (bool, std::string*) outputs to a python std::string (empty if bool=false).
|
2014-07-24 18:12:50 +00:00
|
|
|
std::string ExportModelAsLpFormat(bool obfuscated) {
|
|
|
|
|
std::string output;
|
2015-06-18 14:26:12 +02:00
|
|
|
if (!$self->ExportModelAsLpFormat(obfuscated, &output)) return "";
|
2013-06-11 14:49:45 +00:00
|
|
|
return output;
|
|
|
|
|
}
|
2014-07-24 18:12:50 +00:00
|
|
|
std::string ExportModelAsMpsFormat(bool fixed_format, bool obfuscated) {
|
|
|
|
|
std::string output;
|
2015-06-18 14:26:12 +02:00
|
|
|
if (!$self->ExportModelAsMpsFormat(fixed_format, obfuscated, &output)) {
|
2013-06-11 14:49:45 +00:00
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-18 14:26:12 +02:00
|
|
|
// Change the API of LoadModelFromProto() to simply return the error message:
|
|
|
|
|
// it will always be empty iff the model was valid.
|
|
|
|
|
std::string LoadModelFromProto(const MPModelProto& input_model) {
|
|
|
|
|
std::string error_message;
|
|
|
|
|
$self->LoadModelFromProto(input_model, &error_message);
|
|
|
|
|
return error_message;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-31 08:39:26 +00:00
|
|
|
%pythoncode {
|
2014-07-09 10:01:48 +00:00
|
|
|
def Add(self, constraint, name=''):
|
|
|
|
|
if isinstance(constraint, bool):
|
|
|
|
|
if constraint:
|
|
|
|
|
return self.RowConstraint(0, 0, name)
|
2013-12-29 11:31:40 +00:00
|
|
|
else:
|
2014-07-09 10:01:48 +00:00
|
|
|
return self.RowConstraint(1, 1, name)
|
|
|
|
|
else:
|
|
|
|
|
return constraint.Extract(self, name)
|
|
|
|
|
|
|
|
|
|
def Sum(self, expr_array):
|
|
|
|
|
result = SumArray(expr_array)
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def RowConstraint(self, *args):
|
|
|
|
|
return self.Constraint(*args)
|
|
|
|
|
|
|
|
|
|
def Minimize(self, expr):
|
|
|
|
|
objective = self.Objective()
|
|
|
|
|
objective.Clear()
|
|
|
|
|
objective.SetMinimization()
|
2015-11-02 15:27:08 +01:00
|
|
|
if isinstance(expr, numbers.Number):
|
|
|
|
|
objective.AddOffset(expr)
|
|
|
|
|
else:
|
2016-02-04 14:06:30 +01:00
|
|
|
coeffs = expr.GetCoeffs()
|
|
|
|
|
objective.AddOffset(coeffs.pop(OFFSET_KEY, 0.0))
|
2016-03-21 09:48:13 +01:00
|
|
|
for v, c, in list(coeffs.items()):
|
|
|
|
|
objective.SetCoefficient(v, float(c))
|
2014-07-09 10:01:48 +00:00
|
|
|
|
|
|
|
|
def Maximize(self, expr):
|
|
|
|
|
objective = self.Objective()
|
|
|
|
|
objective.Clear()
|
|
|
|
|
objective.SetMaximization()
|
2015-11-02 15:27:08 +01:00
|
|
|
if isinstance(expr, numbers.Number):
|
|
|
|
|
objective.AddOffset(expr)
|
|
|
|
|
else:
|
2016-02-04 14:06:30 +01:00
|
|
|
coeffs = expr.GetCoeffs()
|
|
|
|
|
objective.AddOffset(coeffs.pop(OFFSET_KEY, 0.0))
|
2016-03-21 09:48:13 +01:00
|
|
|
for v, c, in list(coeffs.items()):
|
|
|
|
|
objective.SetCoefficient(v, float(c))
|
2014-07-09 10:01:48 +00:00
|
|
|
} // %pythoncode
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
%extend MPSolver {
|
2014-07-23 05:43:00 +00:00
|
|
|
static double Infinity() { return operations_research::MPSolver::infinity(); }
|
|
|
|
|
void SetTimeLimit(int64 x) { $self->set_time_limit(x); }
|
|
|
|
|
int64 WallTime() const { return $self->wall_time(); }
|
|
|
|
|
int64 Iterations() const { return $self->iterations(); }
|
|
|
|
|
} // extend MPSolver
|
2011-03-31 08:39:26 +00:00
|
|
|
|
2014-07-09 10:01:48 +00:00
|
|
|
%extend MPVariable {
|
2014-07-23 05:43:00 +00:00
|
|
|
double SolutionValue() const { return $self->solution_value(); }
|
|
|
|
|
bool Integer() const { return $self->integer(); }
|
|
|
|
|
double Lb() const { return $self->lb(); }
|
|
|
|
|
double Ub() const { return $self->ub(); }
|
2015-03-30 10:33:04 +02:00
|
|
|
void SetLb(double x) { $self->SetLB(x); }
|
|
|
|
|
void SetUb(double x) { $self->SetUB(x); }
|
2014-07-23 05:43:00 +00:00
|
|
|
double ReducedCost() const { return $self->reduced_cost(); }
|
|
|
|
|
} // extend MPVariable
|
2014-07-09 10:01:48 +00:00
|
|
|
|
|
|
|
|
%extend MPConstraint {
|
2014-07-23 05:43:00 +00:00
|
|
|
double Lb() const { return $self->lb(); }
|
|
|
|
|
double Ub() const { return $self->ub(); }
|
|
|
|
|
void SetLb(double x) { $self->SetLB(x); }
|
|
|
|
|
void SetUb(double x) { $self->SetUB(x); }
|
|
|
|
|
double DualValue() const { return $self->dual_value(); }
|
|
|
|
|
} // extend MPConstraint
|
|
|
|
|
|
|
|
|
|
%extend MPObjective {
|
|
|
|
|
double Offset() const { return $self->offset();}
|
|
|
|
|
} // extend MPObjective
|
2014-07-09 10:01:48 +00:00
|
|
|
} // namespace operations_research
|
|
|
|
|
|
2014-07-24 18:12:50 +00:00
|
|
|
|
2014-07-09 10:01:48 +00:00
|
|
|
%ignoreall
|
|
|
|
|
|
|
|
|
|
%unignore operations_research;
|
|
|
|
|
|
|
|
|
|
// Strip the "MP" prefix from the exposed classes.
|
|
|
|
|
%rename (Solver) operations_research::MPSolver;
|
|
|
|
|
%rename (Solver) operations_research::MPSolver::MPSolver;
|
|
|
|
|
%rename (Constraint) operations_research::MPConstraint;
|
|
|
|
|
%rename (Variable) operations_research::MPVariable;
|
|
|
|
|
%rename (Objective) operations_research::MPObjective;
|
|
|
|
|
|
|
|
|
|
// Expose the MPSolver::OptimizationProblemType enum.
|
|
|
|
|
%unignore operations_research::MPSolver::OptimizationProblemType;
|
|
|
|
|
%unignore operations_research::MPSolver::GLOP_LINEAR_PROGRAMMING;
|
|
|
|
|
%unignore operations_research::MPSolver::CLP_LINEAR_PROGRAMMING;
|
|
|
|
|
%unignore operations_research::MPSolver::GLPK_LINEAR_PROGRAMMING;
|
|
|
|
|
%unignore operations_research::MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING;
|
|
|
|
|
%unignore operations_research::MPSolver::CBC_MIXED_INTEGER_PROGRAMMING;
|
|
|
|
|
%unignore operations_research::MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING;
|
2015-06-18 14:26:12 +02:00
|
|
|
%unignore operations_research::MPSolver::BOP_INTEGER_PROGRAMMING;
|
2014-07-09 10:01:48 +00:00
|
|
|
// These aren't unit tested, as they only run on machines with a Gurobi license.
|
|
|
|
|
%unignore operations_research::MPSolver::GUROBI_LINEAR_PROGRAMMING;
|
|
|
|
|
%unignore operations_research::MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING;
|
|
|
|
|
%unignore operations_research::MPSolver::SULUM_LINEAR_PROGRAMMING;
|
|
|
|
|
%unignore operations_research::MPSolver::SULUM_MIXED_INTEGER_PROGRAMMING;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Expose the MPSolver::ResultStatus enum.
|
|
|
|
|
%unignore operations_research::MPSolver::ResultStatus;
|
|
|
|
|
%unignore operations_research::MPSolver::OPTIMAL;
|
|
|
|
|
%unignore operations_research::MPSolver::FEASIBLE; // No unit test
|
|
|
|
|
%unignore operations_research::MPSolver::INFEASIBLE;
|
|
|
|
|
%unignore operations_research::MPSolver::UNBOUNDED; // No unit test
|
|
|
|
|
%unignore operations_research::MPSolver::ABNORMAL;
|
|
|
|
|
%unignore operations_research::MPSolver::NOT_SOLVED; // No unit test
|
|
|
|
|
|
|
|
|
|
// Expose the MPSolver's basic API, with some renames.
|
|
|
|
|
%rename (Objective) operations_research::MPSolver::MutableObjective;
|
|
|
|
|
%rename (BoolVar) operations_research::MPSolver::MakeBoolVar; // No unit test
|
|
|
|
|
%rename (IntVar) operations_research::MPSolver::MakeIntVar;
|
|
|
|
|
%rename (NumVar) operations_research::MPSolver::MakeNumVar;
|
|
|
|
|
%rename (Constraint) operations_research::MPSolver::MakeRowConstraint;
|
|
|
|
|
%unignore operations_research::MPSolver::~MPSolver;
|
|
|
|
|
%unignore operations_research::MPSolver::Solve;
|
|
|
|
|
%unignore operations_research::MPSolver::VerifySolution;
|
|
|
|
|
%unignore operations_research::MPSolver::infinity;
|
|
|
|
|
%unignore operations_research::MPSolver::set_time_limit; // No unit test
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Expose some of the more advanced MPSolver API.
|
2015-11-02 15:27:08 +01:00
|
|
|
%unignore operations_research::MPSolver::InterruptSolve;
|
2014-07-09 10:01:48 +00:00
|
|
|
%unignore operations_research::MPSolver::SupportsProblemType; // No unit test
|
|
|
|
|
%unignore operations_research::MPSolver::wall_time; // No unit test
|
|
|
|
|
%unignore operations_research::MPSolver::Clear; // No unit test
|
|
|
|
|
%unignore operations_research::MPSolver::NumVariables;
|
|
|
|
|
%unignore operations_research::MPSolver::NumConstraints;
|
|
|
|
|
%unignore operations_research::MPSolver::EnableOutput; // No unit test
|
|
|
|
|
%unignore operations_research::MPSolver::SuppressOutput; // No unit test
|
|
|
|
|
%rename (LookupConstraint)
|
|
|
|
|
operations_research::MPSolver::LookupConstraintOrNull;
|
|
|
|
|
%rename (LookupVariable) operations_research::MPSolver::LookupVariableOrNull;
|
2015-06-18 14:26:12 +02:00
|
|
|
%unignore operations_research::MPSolver::SetSolverSpecificParametersAsString;
|
2014-07-09 10:01:48 +00:00
|
|
|
|
|
|
|
|
// Expose very advanced parts of the MPSolver API. For expert users only.
|
2015-06-18 14:26:12 +02:00
|
|
|
%unignore operations_research::MPSolver::ComputeConstraintActivities;
|
2014-07-09 10:01:48 +00:00
|
|
|
%unignore operations_research::MPSolver::ComputeExactConditionNumber;
|
|
|
|
|
%unignore operations_research::MPSolver::nodes;
|
|
|
|
|
%unignore operations_research::MPSolver::iterations; // No unit test
|
|
|
|
|
%unignore operations_research::MPSolver::BasisStatus;
|
|
|
|
|
%unignore operations_research::MPSolver::FREE; // No unit test
|
|
|
|
|
%unignore operations_research::MPSolver::AT_LOWER_BOUND;
|
|
|
|
|
%unignore operations_research::MPSolver::AT_UPPER_BOUND;
|
|
|
|
|
%unignore operations_research::MPSolver::FIXED_VALUE; // No unit test
|
|
|
|
|
%unignore operations_research::MPSolver::BASIC;
|
|
|
|
|
|
|
|
|
|
// MPVariable: reader API.
|
|
|
|
|
%unignore operations_research::MPVariable::solution_value;
|
|
|
|
|
%unignore operations_research::MPVariable::lb; // No unit test
|
|
|
|
|
%unignore operations_research::MPVariable::ub; // No unit test
|
2015-06-18 14:26:12 +02:00
|
|
|
%unignore operations_research::MPVariable::integer; // No unit test
|
2014-07-09 10:01:48 +00:00
|
|
|
%unignore operations_research::MPVariable::name; // No unit test
|
2015-06-18 14:26:12 +02:00
|
|
|
%unignore operations_research::MPVariable::index; // No unit test
|
2014-07-09 10:01:48 +00:00
|
|
|
%unignore operations_research::MPVariable::basis_status;
|
|
|
|
|
%unignore operations_research::MPVariable::reduced_cost; // For experts only.
|
|
|
|
|
|
|
|
|
|
// MPConstraint: writer API.
|
|
|
|
|
%unignore operations_research::MPConstraint::SetCoefficient;
|
|
|
|
|
%unignore operations_research::MPConstraint::SetLB;
|
|
|
|
|
%unignore operations_research::MPConstraint::SetUB;
|
|
|
|
|
%unignore operations_research::MPConstraint::SetBounds;
|
|
|
|
|
%unignore operations_research::MPConstraint::set_is_lazy;
|
|
|
|
|
|
|
|
|
|
// MPConstraint: reader API.
|
|
|
|
|
%unignore operations_research::MPConstraint::GetCoefficient;
|
|
|
|
|
%unignore operations_research::MPConstraint::lb;
|
|
|
|
|
%unignore operations_research::MPConstraint::ub;
|
|
|
|
|
%unignore operations_research::MPConstraint::name;
|
2015-06-18 14:26:12 +02:00
|
|
|
%unignore operations_research::MPConstraint::index;
|
2014-07-09 10:01:48 +00:00
|
|
|
%unignore operations_research::MPConstraint::basis_status;
|
|
|
|
|
%unignore operations_research::MPConstraint::dual_value; // For experts only.
|
|
|
|
|
|
|
|
|
|
// MPObjective: writer API.
|
|
|
|
|
%unignore operations_research::MPObjective::SetCoefficient;
|
|
|
|
|
%unignore operations_research::MPObjective::SetMinimization;
|
|
|
|
|
%unignore operations_research::MPObjective::SetMaximization;
|
|
|
|
|
%unignore operations_research::MPObjective::SetOptimizationDirection;
|
|
|
|
|
%unignore operations_research::MPObjective::Clear; // No unit test
|
|
|
|
|
%unignore operations_research::MPObjective::SetOffset;
|
|
|
|
|
%unignore operations_research::MPObjective::AddOffset; // No unit test
|
|
|
|
|
|
|
|
|
|
// MPObjective: reader API.
|
|
|
|
|
%unignore operations_research::MPObjective::Value;
|
|
|
|
|
%unignore operations_research::MPObjective::GetCoefficient;
|
|
|
|
|
%unignore operations_research::MPObjective::minimization;
|
|
|
|
|
%unignore operations_research::MPObjective::maximization;
|
|
|
|
|
%unignore operations_research::MPObjective::offset;
|
|
|
|
|
%unignore operations_research::MPObjective::BestBound;
|
|
|
|
|
|
|
|
|
|
// MPSolverParameters API. For expert users only.
|
|
|
|
|
// TODO(user): also strip "MP" from the class name.
|
|
|
|
|
%unignore operations_research::MPSolverParameters;
|
|
|
|
|
%unignore operations_research::MPSolverParameters::MPSolverParameters;
|
|
|
|
|
%unignore operations_research::MPSolverParameters::DoubleParam;
|
2015-08-13 16:00:54 +02:00
|
|
|
%unignore operations_research::MPSolverParameters::GetDoubleParam;
|
2014-07-09 10:01:48 +00:00
|
|
|
%unignore operations_research::MPSolverParameters::SetDoubleParam;
|
2015-08-13 16:00:54 +02:00
|
|
|
%unignore operations_research::MPSolverParameters::IntegerParam;
|
|
|
|
|
%unignore operations_research::MPSolverParameters::GetIntegerParam;
|
|
|
|
|
%unignore operations_research::MPSolverParameters::SetIntegerParam;
|
|
|
|
|
%unignore operations_research::MPSolverParameters::PRESOLVE;
|
|
|
|
|
%unignore operations_research::MPSolverParameters::RELATIVE_MIP_GAP;
|
2014-07-09 10:01:48 +00:00
|
|
|
%unignore operations_research::MPSolverParameters::kDefaultPrimalTolerance;
|
2015-08-13 16:00:54 +02:00
|
|
|
// TODO(user): unit test kDefaultPrimalTolerance.
|
2014-07-09 10:01:48 +00:00
|
|
|
|
|
|
|
|
// We want to ignore the CoeffMap class; but since it inherits from some
|
|
|
|
|
// hash_map<>, swig complains about an undefined base class. Silence it.
|
|
|
|
|
%warnfilter(401) CoeffMap;
|
2012-01-02 21:11:36 +00:00
|
|
|
|
2011-03-31 08:39:26 +00:00
|
|
|
%include "linear_solver/linear_solver.h"
|
2014-07-09 10:01:48 +00:00
|
|
|
|
|
|
|
|
%unignoreall
|
2016-02-03 15:15:58 +01:00
|
|
|
|
|
|
|
|
%pythoncode {
|
|
|
|
|
def setup_variable_operator(opname):
|
|
|
|
|
setattr(Variable, opname,
|
|
|
|
|
lambda self, *args: getattr(VariableExpr(self), opname)(*args))
|
|
|
|
|
for opname in LinearExpr.SUPPORTED_OPERATOR_METHODS:
|
|
|
|
|
setup_variable_operator(opname)
|
|
|
|
|
} // %pythoncode
|