2014-07-09 11:09:30 +00:00
|
|
|
// Copyright 2010-2014 Google
|
2014-07-08 09:27:02 +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-08 09:27:02 +00:00
|
|
|
// Command line interface to the MPSolver class.
|
|
|
|
|
// See linear_solver.h and kUsageStr below.
|
|
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
#include "base/commandlineflags.h"
|
|
|
|
|
#include "base/commandlineflags.h"
|
|
|
|
|
#include "base/file.h"
|
|
|
|
|
#include "base/timer.h"
|
|
|
|
|
#include "base/strutil.h"
|
2014-12-16 13:47:07 +00:00
|
|
|
#include "lp_data/mps_reader.h"
|
2014-07-08 09:27:02 +00:00
|
|
|
#include "glop/proto_utils.h"
|
|
|
|
|
#include "linear_solver/linear_solver2.pb.h"
|
|
|
|
|
#include "linear_solver/linear_solver.h"
|
2015-02-03 10:47:21 +00:00
|
|
|
#include "util/proto_tools.h"
|
2014-07-08 09:27:02 +00:00
|
|
|
|
|
|
|
|
DEFINE_string(input, "", "REQUIRED: Input file name.");
|
|
|
|
|
DEFINE_string(solver, "glop",
|
|
|
|
|
"The solver to use: "
|
2015-01-08 16:25:43 +00:00
|
|
|
"cbc, clp, cplex, cplex_mip, glop, glpk, glpk_mip, "
|
|
|
|
|
"gurobi, gurobi_mip, scip.");
|
2014-07-08 09:27:02 +00:00
|
|
|
DEFINE_string(params, "", "Solver specific parameters");
|
|
|
|
|
DEFINE_string(forced_mps_format, "",
|
|
|
|
|
"Set to force the mps format to use: free, fixed");
|
|
|
|
|
|
|
|
|
|
static const char kUsageStr[] =
|
|
|
|
|
"Run MPSolver on the given input file. Many formats are supported: \n"
|
|
|
|
|
" - a .mps or .mps.gz file,\n"
|
|
|
|
|
" - an MPModelProto (binary or text, possibly gzipped),\n"
|
|
|
|
|
" - an MPModelRequest (binary or text, possibly gzipped).\n"
|
|
|
|
|
"MPModelProto and MPModelRequest files can comply with either the "
|
|
|
|
|
"linear_solver.proto or the linear_solver2.proto format.";
|
|
|
|
|
|
|
|
|
|
namespace operations_research {
|
|
|
|
|
namespace {
|
|
|
|
|
void Run() {
|
|
|
|
|
// Create the solver and set its parameters.
|
|
|
|
|
MPSolver::OptimizationProblemType type;
|
|
|
|
|
if (FLAGS_solver == "glop") {
|
|
|
|
|
type = MPSolver::GLOP_LINEAR_PROGRAMMING;
|
|
|
|
|
#if defined(USE_GLPK)
|
|
|
|
|
} else if (FLAGS_solver == "glpk") {
|
|
|
|
|
type = MPSolver::GLPK_LINEAR_PROGRAMMING;
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(USE_CLP)
|
|
|
|
|
} else if (FLAGS_solver == "clp") {
|
|
|
|
|
type = MPSolver::CLP_LINEAR_PROGRAMMING;
|
|
|
|
|
#endif
|
2015-01-08 16:25:43 +00:00
|
|
|
#if defined(USE_CPLEX)
|
|
|
|
|
} else if (FLAGS_solver == "cplex") {
|
|
|
|
|
type = MPSolver::CPLEX_LINEAR_PROGRAMMING;
|
|
|
|
|
#endif
|
2014-07-08 09:27:02 +00:00
|
|
|
#if defined(USE_GUROBI)
|
|
|
|
|
} else if (FLAGS_solver == "gurobi") {
|
|
|
|
|
type = MPSolver::GUROBI_LINEAR_PROGRAMMING;
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(USE_SCIP)
|
|
|
|
|
} else if (FLAGS_solver == "scip") {
|
|
|
|
|
type = MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING;
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(USE_GUROBI)
|
|
|
|
|
} else if (FLAGS_solver == "cbc") {
|
|
|
|
|
type = MPSolver::CBC_MIXED_INTEGER_PROGRAMMING;
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(USE_GLPK)
|
|
|
|
|
} else if (FLAGS_solver == "glpk_mip") {
|
|
|
|
|
type = MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING;
|
|
|
|
|
#endif
|
2015-01-08 16:25:43 +00:00
|
|
|
#if defined(USE_CPLEX)
|
|
|
|
|
} else if (FLAGS_solver == "cplex_mip") {
|
|
|
|
|
type = MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING;
|
|
|
|
|
#endif
|
2014-07-08 09:27:02 +00:00
|
|
|
#if defined(USE_GUROBI)
|
|
|
|
|
} else if (FLAGS_solver == "gurobi_mip") {
|
|
|
|
|
type = MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING;
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
|
|
|
|
LOG(FATAL) << "Unsupported --solver: " << FLAGS_solver;
|
|
|
|
|
}
|
|
|
|
|
MPSolver solver("command line solver", type);
|
|
|
|
|
if (!FLAGS_params.empty()) {
|
|
|
|
|
CHECK(solver.SetSolverSpecificParametersAsString(FLAGS_params))
|
|
|
|
|
<< "Wrong --params format.";
|
|
|
|
|
}
|
|
|
|
|
printf("%-12s: %s\n", "Solver",
|
|
|
|
|
new_proto::MPModelRequest::SolverType_Name(
|
|
|
|
|
static_cast<new_proto::MPModelRequest::SolverType>(
|
|
|
|
|
solver.ProblemType())).c_str());
|
|
|
|
|
|
|
|
|
|
// Load the problem into an MPModelProto.
|
|
|
|
|
new_proto::MPModelProto model_proto;
|
|
|
|
|
new_proto::MPModelRequest request_proto;
|
|
|
|
|
if (HasSuffixString(FLAGS_input, ".mps") ||
|
|
|
|
|
HasSuffixString(FLAGS_input, ".mps.gz")) {
|
|
|
|
|
glop::LinearProgram linear_program_fixed;
|
|
|
|
|
glop::LinearProgram linear_program_free;
|
|
|
|
|
glop::MPSReader mps_reader;
|
|
|
|
|
const bool fixed_read = FLAGS_forced_mps_format != "free" &&
|
|
|
|
|
mps_reader.LoadFileWithMode(FLAGS_input, false, &linear_program_fixed);
|
|
|
|
|
const bool free_read = FLAGS_forced_mps_format != "fixed" &&
|
|
|
|
|
mps_reader.LoadFileWithMode(FLAGS_input, true, &linear_program_free);
|
|
|
|
|
CHECK(fixed_read || free_read)
|
|
|
|
|
<< "Error while parsing the mps file '" << FLAGS_input << "'.";
|
|
|
|
|
if (!fixed_read) {
|
|
|
|
|
LinearProgramToMPModelProto(linear_program_free, &model_proto);
|
|
|
|
|
} else {
|
|
|
|
|
LinearProgramToMPModelProto(linear_program_fixed, &model_proto);
|
|
|
|
|
}
|
|
|
|
|
} else if (!ReadFileToProto(FLAGS_input, &model_proto)) {
|
|
|
|
|
LOG(WARNING) << "Failed to parse as an MPModelProto, trying other formats";
|
|
|
|
|
if (ReadFileToProto(FLAGS_input, &request_proto)) {
|
|
|
|
|
model_proto.Swap(request_proto.mutable_model());
|
|
|
|
|
} else {
|
|
|
|
|
LOG(FATAL) << "Failed to parse '" << FLAGS_input
|
|
|
|
|
<< "' as an MPModelProto or an MPModelRequest.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
printf("%-12s: '%s'\n", "File", FLAGS_input.c_str());
|
|
|
|
|
|
|
|
|
|
// Load the proto into the solver.
|
|
|
|
|
MPSolver::LoadStatus load_status = solver.LoadModelFromProto(model_proto);
|
|
|
|
|
CHECK(load_status == MPSolver::NO_ERROR);
|
|
|
|
|
printf("%-12s: %d x %d\n", "Dimension", solver.NumConstraints(),
|
|
|
|
|
solver.NumVariables());
|
|
|
|
|
|
|
|
|
|
// Solve.
|
|
|
|
|
MPSolverParameters param;
|
|
|
|
|
MPSolver::ResultStatus solve_status;
|
|
|
|
|
double solving_time_in_sec = 0;
|
|
|
|
|
{
|
|
|
|
|
ScopedWallTime timer(&solving_time_in_sec);
|
|
|
|
|
solve_status = solver.Solve(param);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("%-12s: %s\n", "Status",
|
|
|
|
|
new_proto::MPSolutionResponse::Status_Name(
|
|
|
|
|
static_cast<new_proto::MPSolutionResponse::Status>(solve_status))
|
|
|
|
|
.c_str());
|
|
|
|
|
printf("%-12s: %15.15e\n", "Objective", solver.Objective().Value());
|
|
|
|
|
printf("%-12s: %-6.4g\n", "Time", solving_time_in_sec);
|
|
|
|
|
}
|
|
|
|
|
} // namespace
|
|
|
|
|
} // namespace operations_research
|
|
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
2015-03-03 14:31:06 +01:00
|
|
|
gflags::ParseCommandLineFlags( &argc, &argv, /*remove_flags=*/true);
|
2014-07-08 09:27:02 +00:00
|
|
|
CHECK(!FLAGS_input.empty()) << "--input is required";
|
|
|
|
|
operations_research::Run();
|
|
|
|
|
}
|