Skip to content

Commit

Permalink
polish lp code
Browse files Browse the repository at this point in the history
  • Loading branch information
lperron committed Nov 19, 2019
1 parent 888fbe3 commit 3765c97
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 103 deletions.
18 changes: 3 additions & 15 deletions ortools/linear_solver/linear_solver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1675,21 +1675,9 @@ bool MPSolverInterface::SetSolverSpecificParametersAsString(
if (parameters.empty()) return true;

std::string extension = ValidFileExtensionForParameterFile();
#if defined(__linux)
int32 tid = static_cast<int32>(pthread_self());
#else // defined(__linux__)
int32 tid = 123;
#endif // defined(__linux__)
#if !defined(_MSC_VER)
int32 pid = static_cast<int32>(getpid());
#else // _MSC_VER
int32 pid = 456;
#endif // _MSC_VER
int64 now = absl::GetCurrentTimeNanos();
std::string filename =
absl::StrFormat("/tmp/parameters-tempfile-%x-%d-%llx%s", tid, pid, now,
extension.c_str());
bool no_error_so_far = true;
std::string filename;
bool no_error_so_far = PortableTemporaryFile(nullptr, &filename);
filename += extension;
if (no_error_so_far) {
no_error_so_far = PortableFileSetContents(filename, parameters).ok();
}
Expand Down
137 changes: 69 additions & 68 deletions ortools/linear_solver/samples/mip_var_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,89 +15,90 @@
# [START import]
from __future__ import print_function
from ortools.linear_solver import pywraplp

# [END import]


# [START data_model]
def create_data_model():
"""Stores the data for the problem."""
data = {}
# Locations in block units
data['constraint_coeffs'] = [
[5, 7, 9, 2, 1],
[18, 4, -9, 10, 12],
[4, 7, 3, 8, 5],
[5, 13, 16, 3, -7],
]
data['bounds'] = [250, 285, 211, 315]
data['obj_coeffs'] = [7, 8, 2, 9, 6]
data['num_vars'] = 5
data['num_constraints'] = 4
return data
"""Stores the data for the problem."""
data = {}
# Locations in block units
data['constraint_coeffs'] = [
[5, 7, 9, 2, 1],
[18, 4, -9, 10, 12],
[4, 7, 3, 8, 5],
[5, 13, 16, 3, -7],
]
data['bounds'] = [250, 285, 211, 315]
data['obj_coeffs'] = [7, 8, 2, 9, 6]
data['num_vars'] = 5
data['num_constraints'] = 4
return data


# [END data_model]


def main():
# [START data]
data = create_data_model()
# [END data]

# [START solver]
# MOE:begin_strip
# Create the mip solver with the CBC backend.
solver = pywraplp.Solver(
'simple_mip_program',
pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)
# [END solver]
# [START variables]
infinity = solver.infinity()
x = {}
for j in range(data['num_vars']):
x[j] = solver.IntVar(0, infinity, 'x[%i]' % j)
print('Number of variables =', solver.NumVariables())
# [END variables]
# [START data]
data = create_data_model()
# [END data]

# [START constraints]
for i in range(data['num_constraints']):
constraint = solver.RowConstraint(0, data['bounds'][i], '')
# [START solver]
# Create the mip solver with the CBC backend.
solver = pywraplp.Solver('simple_mip_program',
pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)
# [END solver]
# [START variables]
infinity = solver.infinity()
x = {}
for j in range(data['num_vars']):
constraint.SetCoefficient(x[j], data['constraint_coeffs'][i][j])
print('Number of constraints =', solver.NumConstraints())
# In Python, you can also set the constraints as follows.
# for i in range(data['num_constraints']):
# constraint_expr = \
# [data['constraint_coeffs'][i][j] * x[j] for j in range(data['num_vars'])]
# solver.Add(sum(constraint_expr) <= data['bounds'][i])
# [END constraints]
x[j] = solver.IntVar(0, infinity, 'x[%i]' % j)
print('Number of variables =', solver.NumVariables())
# [END variables]

# [START objective]
objective = solver.Objective()
for j in range(data['num_vars']):
objective.SetCoefficient(x[j], data['obj_coeffs'][j])
objective.SetMaximization()
# In Python, you can also set the objective as follows.
# obj_expr = [data['obj_coeffs'][j] * x[j] for j in range(data['num_vars'])]
# solver.Maximize(solver.Sum(obj_expr))
# [END objective]
# [START constraints]
for i in range(data['num_constraints']):
constraint = solver.RowConstraint(0, data['bounds'][i], '')
for j in range(data['num_vars']):
constraint.SetCoefficient(x[j], data['constraint_coeffs'][i][j])
print('Number of constraints =', solver.NumConstraints())
# In Python, you can also set the constraints as follows.
# for i in range(data['num_constraints']):
# constraint_expr = \
# [data['constraint_coeffs'][i][j] * x[j] for j in range(data['num_vars'])]
# solver.Add(sum(constraint_expr) <= data['bounds'][i])
# [END constraints]

# [START solve]
status = solver.Solve()
# [END solve]

# [START print_solution]
if status == pywraplp.Solver.OPTIMAL:
print('Objective value =', solver.Objective().Value())
# [START objective]
objective = solver.Objective()
for j in range(data['num_vars']):
print(x[j].name(), ' = ', x[j].solution_value())
print()
print('Problem solved in %f milliseconds' % solver.wall_time())
print('Problem solved in %d iterations' % solver.iterations())
print('Problem solved in %d branch-and-bound nodes' % solver.nodes())
else:
print('The problem does not have an optimal solution.')
# [END print_solution]
objective.SetCoefficient(x[j], data['obj_coeffs'][j])
objective.SetMaximization()
# In Python, you can also set the objective as follows.
# obj_expr = [data['obj_coeffs'][j] * x[j] for j in range(data['num_vars'])]
# solver.Maximize(solver.Sum(obj_expr))
# [END objective]

# [START solve]
status = solver.Solve()
# [END solve]

# [START print_solution]
if status == pywraplp.Solver.OPTIMAL:
print('Objective value =', solver.Objective().Value())
for j in range(data['num_vars']):
print(x[j].name(), ' = ', x[j].solution_value())
print()
print('Problem solved in %f milliseconds' % solver.wall_time())
print('Problem solved in %d iterations' % solver.iterations())
print('Problem solved in %d branch-and-bound nodes' % solver.nodes())
else:
print('The problem does not have an optimal solution.')
# [END print_solution]


if __name__ == '__main__':
main()
main()
# [END program]
17 changes: 16 additions & 1 deletion ortools/linear_solver/sat_proto_solver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,22 @@ util::StatusOr<MPSolutionResponse> SatSolveProto(
}

MPModelProto* const mp_model = request.mutable_model();
auto shift_bounds_preprocessor = ApplyMipPresolveSteps(mp_model);
std::unique_ptr<glop::ShiftVariableBoundsPreprocessor>
shift_bounds_preprocessor;

const auto status =
ApplyMipPresolveSteps(mp_model, &shift_bounds_preprocessor);
if (status == MPSolverResponseStatus::MPSOLVER_INFEASIBLE) {
if (params.log_search_progress()) {
// This is needed for our benchmark scripts.
sat::CpSolverResponse cp_response;
cp_response.set_status(sat::CpSolverStatus::INFEASIBLE);
LOG(INFO) << CpSolverResponseStats(cp_response);
}
response.set_status(MPSolverResponseStatus::MPSOLVER_INFEASIBLE);
response.set_status_str("Problem proven infeasible during MIP presolve");
return response;
}
const std::vector<double> var_scaling =
sat::ScaleContinuousVariables(params.mip_var_scaling(), mp_model);

Expand Down
7 changes: 4 additions & 3 deletions ortools/linear_solver/sat_solver_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@

namespace operations_research {

std::unique_ptr<glop::ShiftVariableBoundsPreprocessor> ApplyMipPresolveSteps(
MPModelProto* model) {
return nullptr;
MPSolverResponseStatus ApplyMipPresolveSteps(
MPModelProto* model, std::unique_ptr<glop::ShiftVariableBoundsPreprocessor>*
shift_bounds_preprocessor) {
return MPSolverResponseStatus::MPSOLVER_NOT_SOLVED;
}

} // namespace operations_research
14 changes: 10 additions & 4 deletions ortools/linear_solver/sat_solver_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@

namespace operations_research {

// Apply presolve steps to improve the MIP -> IP imperfect conversion. The
// Applies presolve steps to improve the MIP -> IP imperfect conversion. The
// stricter the domain of the variable, the more room we have for scaling the
// constraint to integers and prevent overflow.
// If the bounds were shifted, returns the shifting preprocessor.
std::unique_ptr<glop::ShiftVariableBoundsPreprocessor> ApplyMipPresolveSteps(
MPModelProto* model);
//
// If the bounds were shifted, pass in the preprocessor for postsolve to the
// given unique_ptr.
//
// Returns the presolve status which is currently UNKNOWN for most cases but
// might be INFEASIBLE if there is some trivial infeasiblity in the model.
MPSolverResponseStatus ApplyMipPresolveSteps(
MPModelProto* model, std::unique_ptr<glop::ShiftVariableBoundsPreprocessor>*
shift_bounds_preprocessor);

} // namespace operations_research
#endif // OR_TOOLS_LINEAR_SOLVER_SAT_SOLVER_UTILS_H_
23 changes: 12 additions & 11 deletions ortools/linear_solver/scip_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ class SCIPInterface : public MPSolverInterface {
void SetRelativeMipGap(double value) override;
void SetPrimalTolerance(double value) override;
void SetDualTolerance(double value) override;
void SetPresolveMode(int value) override;
void SetScalingMode(int value) override;
void SetLpAlgorithm(int value) override;
void SetPresolveMode(int presolve) override;
void SetScalingMode(int scaling) override;
void SetLpAlgorithm(int lp_algorithm) override;

// SCIP parameters allow to lower and upper bound the number of threads used
// (via "parallel/minnthreads" and "parallel/maxnthread", respectively). Here,
Expand Down Expand Up @@ -712,7 +712,8 @@ MPSolver::ResultStatus SCIPInterface::Solve(const MPSolverParameters& param) {
default:
if (solution != nullptr) {
result_status_ = MPSolver::FEASIBLE;
} else if (scip_status == SCIP_STATUS_TIMELIMIT) {
} else if (scip_status == SCIP_STATUS_TIMELIMIT ||
scip_status == SCIP_STATUS_TOTALNODELIMIT) {
result_status_ = MPSolver::NOT_SOLVED;
} else {
result_status_ = MPSolver::ABNORMAL;
Expand Down Expand Up @@ -821,9 +822,9 @@ void SCIPInterface::SetDualTolerance(double value) {
if (status_.ok()) status_ = status;
}

void SCIPInterface::SetPresolveMode(int value) {
void SCIPInterface::SetPresolveMode(int presolve) {
// See the NOTE on SetRelativeMipGap().
switch (value) {
switch (presolve) {
case MPSolverParameters::PRESOLVE_OFF: {
const auto status =
SCIP_TO_STATUS(SCIPsetIntParam(scip_, "presolving/maxrounds", 0));
Expand All @@ -837,22 +838,22 @@ void SCIPInterface::SetPresolveMode(int value) {
return;
}
default: {
SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value);
SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, presolve);
return;
}
}
}

void SCIPInterface::SetScalingMode(int value) {
void SCIPInterface::SetScalingMode(int scaling) {
SetUnsupportedIntegerParam(MPSolverParameters::SCALING);
}

// Only the root LP algorithm is set as setting the node LP to a
// non-default value rarely is beneficial. The node LP algorithm could
// be set as well with "lp/resolvealgorithm".
void SCIPInterface::SetLpAlgorithm(int value) {
void SCIPInterface::SetLpAlgorithm(int lp_algorithm) {
// See the NOTE on SetRelativeMipGap().
switch (value) {
switch (lp_algorithm) {
case MPSolverParameters::DUAL: {
const auto status =
SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'd'));
Expand All @@ -874,7 +875,7 @@ void SCIPInterface::SetLpAlgorithm(int value) {
}
default: {
SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM,
value);
lp_algorithm);
return;
}
}
Expand Down
22 changes: 21 additions & 1 deletion ortools/port/file_nonport.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.


#if !defined(_MSC_VER)
#include <unistd.h>
#endif

#include "absl/strings/str_format.h"
#include "absl/time/clock.h"
#include "ortools/base/file.h"
#include "ortools/port/file.h"

Expand All @@ -28,7 +35,20 @@ ::util::Status PortableFileGetContents(absl::string_view file_name,

bool PortableTemporaryFile(const char* directory_prefix,
std::string* filename_out) {
return false;
#if defined(__linux)
int32 tid = static_cast<int32>(pthread_self());
#else // defined(__linux__)
int32 tid = 123;
#endif // defined(__linux__)
#if !defined(_MSC_VER)
int32 pid = static_cast<int32>(getpid());
#else // _MSC_VER
int32 pid = 456;
#endif // _MSC_VER
int64 now = absl::GetCurrentTimeNanos();
std::string filename =
absl::StrFormat("/tmp/parameters-tempfile-%x-%d-%llx", tid, pid, now);
return true;
}

::util::Status PortableDeleteFile(absl::string_view file_name) {
Expand Down

0 comments on commit 3765c97

Please sign in to comment.