Skip to content

Commit

Permalink
Renamed CPLEXMP to CPLEX.
Browse files Browse the repository at this point in the history
Preparing for 20240823 release.
  • Loading branch information
mapgccv committed Aug 23, 2024
1 parent a0b382a commit c5a6e87
Show file tree
Hide file tree
Showing 22 changed files with 147 additions and 43 deletions.
10 changes: 5 additions & 5 deletions solvers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ add_ampl_backend(highsmp DLL_RUNTIME SHARED_LIB MODULE HIGHS
add_ampl_backend(ortoolsmp DLL_RUNTIME SHARED_LIB MODULE ortoolsmp
LIBRARIES ${ortoolsmp_LIBS} ${CMAKE_DL_LIBS})

add_ampl_backend(cplexmp DLL_RUNTIME SHARED_LIB MODULE CPLEX
add_ampl_backend(cplex DLL_RUNTIME SHARED_LIB MODULE CPLEX
LIBRARIES cplex-library ${CMAKE_DL_LIBS})

add_ampl_backend(xpress DLL_RUNTIME SHARED_LIB MODULE XPRESS
Expand Down Expand Up @@ -359,10 +359,10 @@ endif()



set(CPLEXSRC cplexmpbackend.cc cplexmpbackend.h
cplexmpcommon.cc cplexmpcommon.h
cplexmpmodelapi.cc cplexmpmodelapi.h
cplexmp-modelapi-connect.cc
set(CPLEXSRC cplexbackend.cc cplexbackend.h
cplexcommon.cc cplexcommon.h
cplexmodelapi.cc cplexmodelapi.h
cplex-modelapi-connect.cc
model-mgr-with-std-pb.cc)
add_prefix(DIRCPLEXSRC "../cplexmp/" ${CPLEXSRC})
set(CPLEXODHSRC cplexodhbackend.h cplexodhbackend.cc)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
Summary of recent updates to CPLEX MP for AMPL
Summary of recent updates to CPLEX for AMPL
==============================================

## TBD
- Added multiple options
## 20240823
- CPLEX MP driver is now the default. To use the previous ASL-based driver set:
`option solver cplexasl;`
- Added many options available in the ASL driver
- Notable changes with ASL driver:
- Keyword 'basis_cond' is now 'kappa' and follows the standard MP implementation
- Multiobjective optimization follows the MP standard implementation
Expand All @@ -14,6 +16,7 @@ Summary of recent updates to CPLEX MP for AMPL
`tech:numcores`.
- Use MP feature `tech:writemodelonly` instead of `writeprob` + `nosolve`.
Note that `nosolve` still applies when specifying `writemipstart`
- Conversion of basis status for constraints depending on sense

## 20240801
- Fix a problem that occured when reporting IIS
Expand Down
62 changes: 62 additions & 0 deletions solvers/cplex/README.cplex.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
The solver "cplex" uses CPLEX (a trademark of IBM,
Inc.; see https://www.ibm.com/products/ilog-cplex-optimization-studio)
to solve integer, mixed-integer, and linear programming problems;
it is an alternative to the ASL-based driver implemented using the mp
library (https://github.com/ampl/mp) for communicating with AMPL and
for reformlation of certain types of problems.
Normally gurobi is invoked by AMPL's solve command, which gives the
invocation

cplex stub -AMPL

in which stub.nl is an AMPL generic output file (possibly written
by "ampl -obstub" or "ampl -ogstub"). After solving the problem,
cplex writes a stub.sol file for use by ampl's solve and solution
commands. When you run ampl, this all happens automatically if you
give the AMPL commands

option solver cplex;
solve;

You can control cplex by setting the environment variable cplex_options
appropriately (either by using ampl's option command, or by using the
shell's set and export commands before you invoke ampl). You can put
one or more (white-space separated) phrases in $cplex_options. To see
the possibilities, invoke

cplex -=

----------
INSTALLING
==========

On Linux systems, libcplex*.so (where the value of "*" depends
on the current version of CPLEX) and the libcplex.so.* to which
it points need to appear in the current directory when CPLEX
itself appears there, or in one of the standard places (specified by
/etc/ld.so.conf on some systems), or in a directory named in
$LD_LIBRARY_PATH. An alternative is to add a short shell script,
such as

#!/bin/sh
LD_LIBRARY_PATH=/usr/local/lib
export LD_LIBRARY_PATH
exec /usr/local/bin/cplexx "$@"

to a directory in your usual $PATH (and mark the script executable
with, e.g., "chmod +x cplex"). The above script assumes that the
true "cplex" binary has been moved to /usr/local/bin/cplexx and that
the libcplex* files have been moved to /usr/local/lib.

MacOSX systems are similar to Linux systems, but with DYLD_LIBRARY_PATH
in place of LD_LIBRARY_PATH.

On MS Windows systems, cplex.exe and the relevant cplex*.dll must
appear somewhere in your usual search $PATH (or in the current
directory).

If you have questions about or find bugs with this stuff,
please contact:

AMPL Support
[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
* Below are CPLEX-specific AMPLS API functions.
* They complement the 'public' AMPLS API defined in ampls-c-api.h.
*/
DECLARE_SOLVER_API_FUNCTIONS(cplexmp)
DECLARE_SOLVER_API_FUNCTIONS(cplex)

AMPLS_C_EXPORT void* AMPLSGetEnv_cplexmp(AMPLS_MP_Solver* slv);
AMPLS_C_EXPORT void* AMPLSGetEnv_cplex(AMPLS_MP_Solver* slv);

#endif // CPLEXAMPLSCAPI_H
7 changes: 7 additions & 0 deletions solvers/cplex/cplex-lib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "cplex/cplex-ampls-c-api.h"

AMPLS_C_EXPORT AMPLS_MP_Solver* AMPLSOpen_cplex(int argc, char** argv)
{
CCallbacks cb = { NULL };
return Open_cplex(cb);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "mp/flat/redef/MIP/converter_mip.h"
#include "mp/flat/model_api_connect.h"

#include "cplexmpmodelapi.h"
#include "cplexmodelapi.h"


namespace mp {
Expand Down
40 changes: 24 additions & 16 deletions solvers/cplexmp/cplexmpbackend.cc → solvers/cplex/cplexbackend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

#include "mp/env.h"
#include "mp/flat/model_api_base.h"
#include "cplexmpbackend.h"
#include "cplexbackend.h"

extern "C" {
#include "cplexmp-ampls-c-api.h" // CPLEX AMPLS C API
#include "cplex-ampls-c-api.h" // CPLEX AMPLS C API
}
#include "mp/ampls-cpp-api.h"

Expand Down Expand Up @@ -134,7 +134,7 @@ namespace mp {

bool CplexBackend::IsMIP() const {
auto type = CPXgetprobtype(env(), lp());
return (!(type == CPXPROB_LP) || (type == CPXPROB_QP)
return !((type == CPXPROB_LP) || (type == CPXPROB_QP)
|| (type == CPXPROB_QCP));
}
bool CplexBackend::IsQCP() const {
Expand All @@ -145,7 +145,7 @@ namespace mp {
bool CplexBackend::HasSolution() {
if (hasSolution_ == -1){
auto status = GetSolveResult().first;
hasSolution_ = (status == sol::LIMIT_FEAS) || (status == sol::SOLVED);
hasSolution_ = (status == sol::LIMIT_FEAS) || (status == sol::SOLVED) || (status == sol::UNCERTAIN);
}
return hasSolution_;
}
Expand Down Expand Up @@ -214,19 +214,27 @@ namespace mp {
std::vector<int> cons(NumLinCons());
int status = CPXgetbase(env(), lp(), nullptr, cons.data());
if (status) return cons;
for (auto& s : cons) {
switch (s) {
std::vector<char> sense(NumLinCons());
CPLEX_CALL(CPXgetsense(env(), lp(), sense.data(), 0, NumLinCons()-1));

for (auto i = cons.size(); i--; ) {
switch (cons[i]) {
case CPX_BASIC:
s = (int)BasicStatus::bas;
cons[i] = (int)BasicStatus::bas;
break;
case CPX_AT_LOWER:
s = (int)BasicStatus::low;
if (sense[i] == 'L')
cons[i] = (int)BasicStatus::upp;
else if (sense[i] == 'E')
cons[i] = (int)BasicStatus::equ;
else
cons[i] = (int)BasicStatus::low;
break;
case CPX_AT_UPPER: // just for range constraints
s = (int)BasicStatus::upp;
cons[i] = (int)BasicStatus::upp;
break;
default:
MP_RAISE(fmt::format("Unknown CPLEX rstat value: {}", s));
MP_RAISE(fmt::format("Unknown CPLEX rstat value: {}", cons[i]));
}
}
return cons;
Expand Down Expand Up @@ -364,7 +372,7 @@ pre::ValueMapDbl CplexBackend::DualSolution() {
}

ArrayRef<double> CplexBackend::DualSolution_LP() {
if (IsMIP() && need_fixed_MIP() && HasSolution())
if (HasSolution() && ((!IsMIP()) || need_fixed_MIP()))
{
int num_cons = NumLinCons();
std::vector<double> pi(num_cons);
Expand Down Expand Up @@ -1079,7 +1087,7 @@ void CplexBackend::DoCplexFeasRelax() {
std::vector<double> ubpen = feasrelax().ubpen();
if (ubpen.size() && ubpen.size() < (size_t)NumVars())
ubpen.resize(NumVars());
CPLEX_CALL(CPXfeasopt(env(), lp(),
CPLEX_CALL(CPXfeasopt(env(), lp(),
(double*)data_or_null(rhspen), (double*)data_or_null(rhspen),
(double*)data_or_null(lbpen), (double*)data_or_null(ubpen)));
}
Expand Down Expand Up @@ -2302,23 +2310,23 @@ void CplexBackend::CplexPlayObjNParams() {
} // namespace mp


AMPLS_MP_Solver* Open_cplexmp(CCallbacks cb = {}) {
AMPLS_MP_Solver* Open_cplex(CCallbacks cb = {}) {
AMPLS_MP_Solver* slv =
AMPLS__internal__Open(std::unique_ptr<mp::BasicBackend>{new mp::CplexBackend()},
cb);
return slv;
}

void AMPLSClose_cplexmp(AMPLS_MP_Solver* slv) {
void AMPLSClose_cplex(AMPLS_MP_Solver* slv) {
AMPLS__internal__Close(slv);
}

void* AMPLSGetModel_cplexmp(AMPLS_MP_Solver* slv) {
void* AMPLSGetModel_cplex(AMPLS_MP_Solver* slv) {
return
dynamic_cast<mp::CplexBackend*>(AMPLSGetBackend(slv))->lp();
}

void* AMPLSGetEnv_cplexmp(AMPLS_MP_Solver* slv) {
void* AMPLSGetEnv_cplex(AMPLS_MP_Solver* slv) {
return
dynamic_cast<mp::CplexBackend*>(AMPLSGetBackend(slv))->env();
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#include "mp/backend-mip.h"
#include "mp/flat/backend_flat.h"
#include "cplexmpcommon.h"
#include "cplexcommon.h"
#include <map>

namespace mp {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "mp/format.h"
#include "cplexmpcommon.h"
#include "cplexcommon.h"

namespace mp {

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "cplexmpmodelapi.h"
#include "cplexmodelapi.h"


namespace mp {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <memory>

#include "mp/env.h"
#include "cplexmpcommon.h"
#include "cplexcommon.h"
#include "mp/flat/model_api_base.h"
#include "mp/flat/constr_std.h"

Expand Down
File renamed without changes.
File renamed without changes.
Empty file removed solvers/cplexmp/README.cplexmp.txt
Empty file.
7 changes: 0 additions & 7 deletions solvers/cplexmp/cplexmp-lib.c

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
7 changes: 7 additions & 0 deletions solvers/xpress/CHANGES.xpress.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ Summary of recent updates to Xpress for AMPL
============================================


## 20240823
- Updated to Xpress 43.01.03
- Added hybrid gradient algorithm (set *bar:alg* to 4)
- Option *bar:cpuplatform* defaults to -2. To replicate the previous
versions behaviour, set to -1.


## 20240724
- Option *acc:_all*
- Useful to disable all reformulations (acc:_all=2),
Expand Down
30 changes: 27 additions & 3 deletions solvers/xpress/xpressbackend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,8 @@ std::string XpressmpBackend::DoXpressFixedModel()
{ "-1", "Automatic choice (default)", -1},
{ "1", "Infeasible-start barrier algorithm", 1},
{ "2", "Homogeneous self-dual barrier algorithm", 2},
{ "3", "Start with 2 and maybe switch to 1 while solving", 3}
{ "3", "Start with 2 and maybe switch to 1 while solving", 3},
{ "4", "Use the hybrid gradient algorithm", 4}
};

static const mp::OptionValueInfo values_barstart[] = {
Expand Down Expand Up @@ -743,7 +744,16 @@ std::string XpressmpBackend::DoXpressFixedModel()
{ "4", "skip pivots that are \"less numerically reliable\"", 4},
{ "8", "do a slower but more numerically stable crossover", 8},
};

static const mp::OptionValueInfo values_barhgops[] = {
{ "1", "use an asymmetric average for the primal averaging", 1},
{ "2", "use the 1-norm of the coefficient matrix in normalizing the initial solution", 2},
{ "4", "use the 2-norm of the coefficient matrix in normalizing the initial solution", 4},
{ "8", "use the infinity norm of the coefficient matrix in normalizing the initial solution", 8},
{ "16", "take the square root of omega", 16},
{ "32", "contract omega towards 1 if the infeasibility is small enough", 32},
{ "64", "omega is based on the infeasibility", 64},
};

static const mp::OptionValueInfo values_cutselect[] = {
{"32", "clique cuts", 32},
{"64", "mixed - integer founding(MIR) cuts", 64},
Expand Down Expand Up @@ -1688,7 +1698,7 @@ AddSolverOption("alg:resourcestrategy resourcestrategy",

AddSolverOption("bar:cpuplatform cpuplatform",
"Which instruction are allowed to the Newton barrier method:\n:",
XPRS_CPUPLATFORM, values_cpuplatform, -1);
XPRS_CPUPLATFORM, values_cpuplatform, -2);

AddSolverOption("bar:crash barcrash",
"Choice of crash procedure for crossover, higher number "
Expand Down Expand Up @@ -1730,6 +1740,20 @@ AddSolverOption("alg:resourcestrategy resourcestrategy",
"dual infeasibilities; default = 0 (automatic choice)",
XPRS_BARDUALSTOP, 0.0, DBL_MAX);



AddSolverOption("bar:hgextrapolate barhgextrapolate",
"Extrapolation parameter for the hybrid gradient algorithm; default = 0.99",
XPRS_BARHGEXTRAPOLATE, 0.0, 1.0);

AddSolverOption("bar:hgmaxrestarts barhgmaxrestarts",
"Maximum number of restarts in the hybrid gradient algorithm; default =500",
XPRS_BARHGMAXRESTARTS, 0, INT_MAX);

AddSolverOption("bar:hgops barhgops",
"Control option for hybrid gradient (default = 8); sum of:\n"
"\n.. value-table::\n", XPRS_BARHGOPS, values_barhgops, -1);

AddSolverOption("bar:gapstop bargapstop",
"Barrier method convergence tolerance on the relative"
" duality gap; default = 0", XPRS_BARGAPSTOP, 0.0, DBL_MAX);
Expand Down
4 changes: 2 additions & 2 deletions test/end2end/scripts/python/SolverCollection.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ def addStdSolvers(solvers: SolverCollection, binPath=""):
solvers.addSolver(Solver.OcteractSolver(path.join(binPath, "octeract-engine")))
solvers.addSolver(Solver.GurobiDirectSolver(path.join(binPath,"gurobi")))
solvers.addSolver(Solver.GurobiSolver(path.join(binPath,"gurobiasl")))
solvers.addSolver(Solver.CPLEXSolver(path.join(binPath,"cplex")))
solvers.addSolver(Solver.CPLEXDirectSolver(path.join(binPath,"cplexmp"))) ## Need as long as the target is there
solvers.addSolver(Solver.CPLEXSolver(path.join(binPath,"cplexasl")))
solvers.addSolver(Solver.CPLEXDirectSolver(path.join(binPath,"cplex")))
solvers.addSolver(Solver.BaronSolver(path.join(binPath,"baron")))
solvers.addSolver(Solver.ConoptSolver(path.join(binPath,"conopt4")))
solvers.addSolver(Solver.ConoptSolver(path.join(binPath,"conopt")))
Expand Down

0 comments on commit c5a6e87

Please sign in to comment.