From fcb272d425a7009c8f186991ef80481eb967d518 Mon Sep 17 00:00:00 2001 From: Gleb Date: Fri, 17 Jun 2022 18:59:48 +1000 Subject: [PATCH] Revert "Revert "Ortools" (#179)" This reverts commit 347d6d97813dfeda796948b25f9fb5576fd84925. --- CMakeLists.txt | 8 +- doc/rst/components.rst | 31 +- doc/rst/details.rst | 7 + doc/rst/model-guide.rst | 11 +- include/mp/ampls-c-api.h | 19 ++ include/mp/ampls-cpp-api.h | 3 + include/mp/backend-base.h | 24 +- include/mp/backend-mip.h | 4 +- include/mp/backend.h | 6 +- ...traints_algebraic.h => constr_algebraic.h} | 2 +- .../flat/{constraint_base.h => constr_base.h} | 0 ...aints_functional.h => constr_functional.h} | 2 +- ...constraints_general.h => constr_general.h} | 2 +- .../flat/{constraint_hash.h => constr_hash.h} | 2 +- .../{constraint_keeper.h => constr_keeper.h} | 8 +- .../{constraints_static.h => constr_static.h} | 4 +- .../flat/{constraints_std.h => constr_std.h} | 4 +- include/mp/flat/converter.h | 26 +- include/mp/flat/converter_model.h | 4 +- include/mp/flat/model_api_base.h | 2 +- include/mp/flat/model_api_connect.h | 4 +- include/mp/flat/problem_flattener.h | 35 +- include/mp/flat/redef/MIP/abs.h | 2 +- include/mp/flat/redef/MIP/alldiff.h | 4 +- include/mp/flat/redef/MIP/complement.h | 2 +- include/mp/flat/redef/MIP/cond_eq.h | 2 +- include/mp/flat/redef/MIP/cond_ineq.h | 2 +- include/mp/flat/redef/MIP/count.h | 2 +- include/mp/flat/redef/MIP/div.h | 2 +- include/mp/flat/redef/MIP/ifthenelse.h | 2 +- include/mp/flat/redef/MIP/indicator_ge.h | 2 +- include/mp/flat/redef/MIP/indicator_le.h | 2 +- include/mp/flat/redef/MIP/indicator_quad.h | 2 +- include/mp/flat/redef/MIP/logical_and.h | 2 +- include/mp/flat/redef/MIP/logical_not.h | 2 +- include/mp/flat/redef/MIP/logical_or.h | 2 +- include/mp/flat/redef/MIP/min_max.h | 2 +- include/mp/flat/redef/MIP/numberof_const.h | 2 +- include/mp/flat/redef/MIP/numberof_var.h | 2 +- include/mp/flat/redef/redef_base.h | 8 +- include/mp/flat/redef/std/range_con.h | 48 +-- include/mp/model-mgr-base.h | 3 +- include/mp/model-mgr-with-pb.h | 4 +- include/mp/{presolve-base.h => valcvt-base.h} | 33 +- .../mp/{presolve-bridge.h => valcvt-link.h} | 154 ++++----- include/mp/{presolve-node.h => valcvt-node.h} | 12 +- include/mp/{presolve.h => valcvt.h} | 60 ++-- solvers/CMakeLists.txt | 4 + solvers/copt/copt-lib.c | 4 +- solvers/copt/coptbackend.cc | 16 +- solvers/copt/coptbackend.h | 4 +- solvers/copt/coptmodelapi.cc | 2 +- solvers/copt/coptmodelapi.h | 2 +- solvers/copt/main.cc | 9 +- solvers/cplexdirect/cplexbackend.cc | 10 +- solvers/cplexdirect/cplexbackend.h | 4 +- solvers/cplexdirect/cplexdirect-lib.c | 9 +- solvers/cplexdirect/cplexmodelapi.cc | 2 +- solvers/cplexdirect/cplexmodelapi.h | 2 +- solvers/cplexdirect/main.cc | 9 +- solvers/gurobi/gurobi-lib.c | 2 +- solvers/gurobi/gurobibackend.cc | 28 +- solvers/gurobi/gurobibackend.h | 4 +- solvers/gurobi/gurobimodelapi.cc | 2 +- solvers/gurobi/gurobimodelapi.h | 2 +- solvers/gurobi/main.cc | 7 +- solvers/highsdirect/highsdirectbackend.cc | 12 +- solvers/highsdirect/highsdirectbackend.h | 4 +- solvers/highsdirect/highsdirectmodelapi.cc | 6 +- solvers/highsdirect/highsdirectmodelapi.h | 2 +- solvers/ortoolsmp/CHANGES.ortoolsmp.md | 5 + solvers/ortoolsmp/README.ortoolsmp.txt | 5 + solvers/ortoolsmp/main.cc | 10 + solvers/ortoolsmp/model-mgr-with-std-pb.cc | 8 + solvers/ortoolsmp/ortoolsmp-ampls-c-api.h | 29 ++ solvers/ortoolsmp/ortoolsmp-lib.c | 27 ++ solvers/ortoolsmp/ortoolsmpbackend.cc | 299 ++++++++++++++++++ solvers/ortoolsmp/ortoolsmpbackend.h | 131 ++++++++ solvers/ortoolsmp/ortoolsmpcommon.cc | 70 ++++ solvers/ortoolsmp/ortoolsmpcommon.h | 72 +++++ solvers/ortoolsmp/ortoolsmpmodelapi.cc | 77 +++++ solvers/ortoolsmp/ortoolsmpmodelapi.h | 71 +++++ solvers/visitor/visitorbackend.cc | 14 +- solvers/visitor/visitorbackend.h | 4 +- solvers/visitor/visitormodelapi.cc | 2 +- solvers/visitor/visitormodelapi.h | 2 +- src/mp/flat/piecewise_linear.cpp | 2 +- src/solver.cc | 7 +- 88 files changed, 1204 insertions(+), 343 deletions(-) rename include/mp/flat/{constraints_algebraic.h => constr_algebraic.h} (99%) rename include/mp/flat/{constraint_base.h => constr_base.h} (100%) rename include/mp/flat/{constraints_functional.h => constr_functional.h} (99%) rename include/mp/flat/{constraints_general.h => constr_general.h} (98%) rename include/mp/flat/{constraint_hash.h => constr_hash.h} (99%) rename include/mp/flat/{constraint_keeper.h => constr_keeper.h} (98%) rename include/mp/flat/{constraints_static.h => constr_static.h} (63%) rename include/mp/flat/{constraints_std.h => constr_std.h} (63%) rename include/mp/{presolve-base.h => valcvt-base.h} (89%) rename include/mp/{presolve-bridge.h => valcvt-link.h} (52%) rename include/mp/{presolve-node.h => valcvt-node.h} (95%) rename include/mp/{presolve.h => valcvt.h} (61%) create mode 100644 solvers/ortoolsmp/CHANGES.ortoolsmp.md create mode 100644 solvers/ortoolsmp/README.ortoolsmp.txt create mode 100644 solvers/ortoolsmp/main.cc create mode 100644 solvers/ortoolsmp/model-mgr-with-std-pb.cc create mode 100644 solvers/ortoolsmp/ortoolsmp-ampls-c-api.h create mode 100644 solvers/ortoolsmp/ortoolsmp-lib.c create mode 100644 solvers/ortoolsmp/ortoolsmpbackend.cc create mode 100644 solvers/ortoolsmp/ortoolsmpbackend.h create mode 100644 solvers/ortoolsmp/ortoolsmpcommon.cc create mode 100644 solvers/ortoolsmp/ortoolsmpcommon.h create mode 100644 solvers/ortoolsmp/ortoolsmpmodelapi.cc create mode 100644 solvers/ortoolsmp/ortoolsmpmodelapi.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 30f7af961..577049484 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -316,15 +316,15 @@ add_prefix(MP_HEADERS include/mp/ model-mgr-base.h model-mgr-with-pb.h model-mgr-with-std-pb.h model-mgr-with-std-pb.hpp nl.h nl-reader.h option.h os.h problem.h problem-builder.h - presolve-base.h presolve-node.h presolve-bridge.h presolve.h + valcvt-base.h valcvt-node.h valcvt-link.h valcvt.h rstparser.h safeint.h sol.h solver.h solver-opt.h solver-base.h solver-io.h solver-app-base.h solver-app.h suffix.h utils-file.h utils-hash.h utils-hash-stream.h utils-string.h) add_prefix(MP_FLAT_HEADERS include/mp/flat/ - constraint_base.h constraint_keeper.h constraint_hash.h - constraints_std.h constraints_static.h constraints_functional.h - constraints_algebraic.h constraints_general.h + constr_base.h constr_keeper.h constr_hash.h + constr_std.h constr_static.h constr_functional.h + constr_algebraic.h constr_general.h context.h converter.h converter_model.h convert_functional.h eexpr.h expr_algebraic.h expr_affine.h expr_quadratic.h diff --git a/doc/rst/components.rst b/doc/rst/components.rst index ef7804bf9..f6b67ecc5 100644 --- a/doc/rst/components.rst +++ b/doc/rst/components.rst @@ -156,8 +156,20 @@ solver messages and status reporting, simplex basis statuses, and other suffix I/O. Their solver-specific subclasses can be customized for a particular solver. They rely on the :ref:`model-manager` interface -for model and solution I/O. See the classes' documentation -for details. +for model and solution I/O. + +As an example, if the driver should read and write simplex basis status suffixes, +the derived Backend class can declare + +.. code-block:: c++ + + ALLOW_STD_FEATURE( BASIS, true ) + SolutionBasis GetBasis() override; + void SetBasis(SolutionBasis ) override; + +and define the `GetBasis`, `SetBasis` methods. +See the classes' documentation +for further details. .. _solver-classes: @@ -248,6 +260,19 @@ via the solver's modeling API wrapper: * `mp::BasicFlatModelAPI` is the interface via which `mp::FlatConverter` addresses the underlying solver. A subclassed wrapper, such as `mp::GurobiModelAPI`, signals its accepted constraints and which model conversions are preferable. + For example, `GurobiModelAPI` declares the following in order to natively + receive the logical OR constraint: + + .. code-block:: c++ + + ACCEPT_CONSTRAINT(OrConstraint, + Recommended, // Driver recommends native form + CG_General) // Constraint group for suffix exchange + void AddConstraint(const OrConstraint& ); + + By default, if the driver does not mark a constraint as acceptable, + `mp::FlatConverter` and its descendants attempt to simplify it. See the + classes' documentation for further details. * :ref:`value-presolver` transforms solutions and suffixes between the original NL model and the flat model. @@ -258,7 +283,7 @@ via the solver's modeling API wrapper: Value Presolver ~~~~~~~~~~~~~~~ -Class `mp::pre::Presolver` manages transformations of solutions and suffixes +Class `mp::pre::ValuePresolver` manages transformations of solutions and suffixes between the original NL model and the converted model. For driver architectures with :ref:`model-manager`, the value presolver object should be shared between the model converter and the :ref:`Backend ` to enable diff --git a/doc/rst/details.rst b/doc/rst/details.rst index bfe9d8fa8..0b61bc03e 100644 --- a/doc/rst/details.rst +++ b/doc/rst/details.rst @@ -17,6 +17,13 @@ Namespace mp :members: +Namespace mp::pre +----------------- + +.. doxygennamespace:: mp::pre + :members: + + Namespace fmt ------------- diff --git a/doc/rst/model-guide.rst b/doc/rst/model-guide.rst index 0b87360d7..178ab4501 100644 --- a/doc/rst/model-guide.rst +++ b/doc/rst/model-guide.rst @@ -205,8 +205,8 @@ to the solver natively (if supported; e.g., Gurobi options *acc:and*, *acc:or*). -SOS variable domains -~~~~~~~~~~~~~~~~~~~~ +SOS constraints and non-contiguous variable domains +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SOS1 is mainly relevant for models that restrict some variables to take a value from an arbitrary list of values. A simple example: @@ -218,8 +218,11 @@ value from an arbitrary list of values. A simple example: An appropriate SOS1 representation will be automatically generated from this declaration. +SOS2 are one of the two ways to linearize +:ref:`piecewise-linear expressions ` by AMPL. + It is possible to specify SOS1 or SOS2 variables and corresponding "reference rows" -explicitly using AMPL suffixes .sosno and .ref, +explicitly using AMPL suffixes .sos(no) and .(sos)ref, as described in the solver documentation. However this requires some study to understand whether SOS1/2 is appropriate and how to apply it, and we don't recommend going to that trouble unless you @@ -243,6 +246,8 @@ or passed to the solver natively (if supported; e.g., Gurobi options *acc:min*, *acc:max*, *acc:abs*). +.. _piecewize-linear-expr: + Piecewise-linear expressions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/include/mp/ampls-c-api.h b/include/mp/ampls-c-api.h index 273b42c74..a8ad3f54f 100644 --- a/include/mp/ampls-c-api.h +++ b/include/mp/ampls-c-api.h @@ -1,9 +1,14 @@ #ifndef AMPLS_C_INTERFACE_H #define AMPLS_C_INTERFACE_H +#include + /* * A generic C API for MP */ + +#include // for size_t + #ifdef _WIN32 #define AMPLS_C_EXPORT __declspec(dllexport) #else @@ -45,4 +50,18 @@ AMPLS_C_EXPORT void AMPLSAddMessage(AMPLS_MP_Solver* slv, const char* msg); const char* const * AMPLSGetMessages(AMPLS_MP_Solver* slv); +/// Set of callbacks provided to a driver for licensing issues +typedef struct CCallbacks_T { + /// If provided, replacement function to create solver environment + /// for a given solver. + void* (*init)(); + /// Check if model sizes are allowed; throw if not. + /// Parameters: n_vars, n_alg_con, n_log_con + void (*check)(size_t, size_t, size_t); + /// Return additional text to be displayed on '-v' output + const char* (*additionalText)(); + /// Function called after failures to provide additional diagnostics + void (*diagnostics)(); +} CCallbacks; + #endif // AMPLS_C_INTERFACE_H diff --git a/include/mp/ampls-cpp-api.h b/include/mp/ampls-cpp-api.h index dc3473a70..eaaa7807c 100644 --- a/include/mp/ampls-cpp-api.h +++ b/include/mp/ampls-cpp-api.h @@ -28,6 +28,9 @@ AMPLS_MP_Solver* AMPLS__internal__Open(std::unique_ptr p_be, const char* slv_opt); /// Shut down solver instance. Internal only. +/// Deallocate the mp-related info and the structure itself. +/// Before calling this function, a solver-specific implementation should +/// delete solver_info_ and user_info_ if allocated. void AMPLS__internal__Close(AMPLS_MP_Solver* slv); /// Retrieve the Backend diff --git a/include/mp/backend-base.h b/include/mp/backend-base.h index 95d8b774a..01f5cd817 100644 --- a/include/mp/backend-base.h +++ b/include/mp/backend-base.h @@ -2,7 +2,10 @@ #define BACKEND_BASE_H #include -#include + +extern "C" { + #include "mp/ampls-c-api.h" // for CCallbacks +} #include "mp/solver-base.h" @@ -76,26 +79,13 @@ class BasicBackend : public BasicSolver { /// Chance to consider options immediately (open cloud, etc) virtual void FinishOptionParsing() { } - /// Callbacks, e.g., for licensing information - struct Callbacks { - /// If given, has the custom solver GetEnv() method - std::function cb_initsolver_; - - /// If given, should be called after reading the NL (header) - /// with n_vars, n_algebraic_constr, n_logical_constr - std::function cb_checkmodel_; - - /// If given, provides the license description - std::function cb_license_text_; - - /// If given, the function is called to provide additional - // diagnostics if a solver environment cannot be created - std::function cb_diagnostics_; - }; + /// Callbacks typedef + using Callbacks = CCallbacks; /// Obtain callbacks Callbacks& GetCallbacks() { return callbacks_; } + private: Callbacks callbacks_; }; diff --git a/include/mp/backend-mip.h b/include/mp/backend-mip.h index 17a361670..a1437b04a 100644 --- a/include/mp/backend-mip.h +++ b/include/mp/backend-mip.h @@ -85,9 +85,9 @@ class MIPBackend : public BaseBackend /// The basis statuses of vars and cons. /// MIPBackend handles them in postsolved form (for the NL model) /// Impl has to perform value pre- / postsolve if needed - /// Getter (unpresolved) + /// Getter (returns unpresolved basis) virtual SolutionBasis GetBasis() { return {}; } - /// Setter (unpresolved) + /// Setter (takes unpresolved basis) virtual void SetBasis(SolutionBasis ) { MP_UNSUPPORTED("MIPBackend::SetBasis"); } /** diff --git a/include/mp/backend.h b/include/mp/backend.h index 872017676..222337125 100644 --- a/include/mp/backend.h +++ b/include/mp/backend.h @@ -57,7 +57,7 @@ DEFAULT_STD_FEATURES_TO( false ) namespace mp { -/// Basis status values of a solution (unpresolved) +/// Solution (normally unpresolved) struct Solution { /// primal std::vector primal; @@ -186,7 +186,7 @@ class Backend : void ReadNL(const std::string& nl_filename, const std::string& filename_no_ext) override { GetMM().ReadNLModel(nl_filename, filename_no_ext, - GetCallbacks().cb_checkmodel_); + GetCallbacks().check); } /// Input warm start, suffixes, and all that can modify the model. @@ -846,7 +846,7 @@ class Backend : this->set_long_name( fmt::format("{} {}", name, version ) ); this->set_version( fmt::format("AMPL/{} Optimizer [{}]", name, version ) ); - auto lic_cb = GetCallbacks().cb_license_text_; + auto lic_cb = GetCallbacks().additionalText; if (lic_cb) this->set_license_info(lic_cb()); } diff --git a/include/mp/flat/constraints_algebraic.h b/include/mp/flat/constr_algebraic.h similarity index 99% rename from include/mp/flat/constraints_algebraic.h rename to include/mp/flat/constr_algebraic.h index 1d403cfae..b41ed399f 100644 --- a/include/mp/flat/constraints_algebraic.h +++ b/include/mp/flat/constr_algebraic.h @@ -8,7 +8,7 @@ #include #include -#include "mp/flat/constraint_base.h" +#include "mp/flat/constr_base.h" #include "mp/flat/expr_quadratic.h" diff --git a/include/mp/flat/constraint_base.h b/include/mp/flat/constr_base.h similarity index 100% rename from include/mp/flat/constraint_base.h rename to include/mp/flat/constr_base.h diff --git a/include/mp/flat/constraints_functional.h b/include/mp/flat/constr_functional.h similarity index 99% rename from include/mp/flat/constraints_functional.h rename to include/mp/flat/constr_functional.h index b2786375c..4b7186847 100644 --- a/include/mp/flat/constraints_functional.h +++ b/include/mp/flat/constr_functional.h @@ -5,7 +5,7 @@ * Functional flat constraints */ -#include "mp/flat/constraints_static.h" +#include "mp/flat/constr_static.h" namespace mp { diff --git a/include/mp/flat/constraints_general.h b/include/mp/flat/constr_general.h similarity index 98% rename from include/mp/flat/constraints_general.h rename to include/mp/flat/constr_general.h index 732254097..18fa40549 100644 --- a/include/mp/flat/constraints_general.h +++ b/include/mp/flat/constr_general.h @@ -8,7 +8,7 @@ #include #include -#include "mp/flat/constraints_algebraic.h" +#include "mp/flat/constr_algebraic.h" namespace mp { diff --git a/include/mp/flat/constraint_hash.h b/include/mp/flat/constr_hash.h similarity index 99% rename from include/mp/flat/constraint_hash.h rename to include/mp/flat/constr_hash.h index f12e93f13..f32fff9eb 100644 --- a/include/mp/flat/constraint_hash.h +++ b/include/mp/flat/constr_hash.h @@ -8,7 +8,7 @@ #include #include "mp/utils-hash-stream.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" #include "mp/flat/expr_affine.h" namespace std { diff --git a/include/mp/flat/constraint_keeper.h b/include/mp/flat/constr_keeper.h similarity index 98% rename from include/mp/flat/constraint_keeper.h rename to include/mp/flat/constr_keeper.h index d9eca33f0..74332cac8 100644 --- a/include/mp/flat/constraint_keeper.h +++ b/include/mp/flat/constr_keeper.h @@ -9,9 +9,9 @@ #include "mp/common.h" #include "mp/flat/model_api_base.h" -#include "mp/flat/constraint_hash.h" +#include "mp/flat/constr_hash.h" #include "mp/flat/redef/redef_base.h" -#include "mp/presolve-node.h" +#include "mp/valcvt-node.h" namespace mp { @@ -318,10 +318,10 @@ class ConstraintKeeper : public BasicConstraintKeeper { for (const auto& cont: cons_) { if (!cont.IsBridged()) { static_cast(be).AddConstraint(cont.con_); - GetConverter().GetCopyBridge(). + GetConverter().GetCopyLink(). AddEntry({ GetValueNode().Select(con_index), - GetConverter().GetPresolver().GetTargetNodes(). + GetConverter().GetValuePresolver().GetTargetNodes(). GetConValues()(con_group).Add() }); } diff --git a/include/mp/flat/constraints_static.h b/include/mp/flat/constr_static.h similarity index 63% rename from include/mp/flat/constraints_static.h rename to include/mp/flat/constr_static.h index fc639fd66..4e4780ced 100644 --- a/include/mp/flat/constraints_static.h +++ b/include/mp/flat/constr_static.h @@ -5,7 +5,7 @@ * Static (non-functional) flat constraints */ -#include "mp/flat/constraints_algebraic.h" -#include "mp/flat/constraints_general.h" +#include "mp/flat/constr_algebraic.h" +#include "mp/flat/constr_general.h" #endif // CONSTRAINTS_STATIC_H diff --git a/include/mp/flat/constraints_std.h b/include/mp/flat/constr_std.h similarity index 63% rename from include/mp/flat/constraints_std.h rename to include/mp/flat/constr_std.h index 726affdca..50ab5b54c 100644 --- a/include/mp/flat/constraints_std.h +++ b/include/mp/flat/constr_std.h @@ -6,7 +6,7 @@ * flat constraints */ -#include "mp/flat/constraints_static.h" -#include "mp/flat/constraints_functional.h" +#include "mp/flat/constr_static.h" +#include "mp/flat/constr_functional.h" #endif // STD_CONSTR_H diff --git a/include/mp/flat/converter.h b/include/mp/flat/converter.h index fd9b481b9..b97708f5c 100644 --- a/include/mp/flat/converter.h +++ b/include/mp/flat/converter.h @@ -12,9 +12,9 @@ #include "mp/solver-base.h" #include "mp/flat/converter_model.h" #include "mp/flat/convert_functional.h" -#include "mp/flat/constraint_keeper.h" -#include "mp/flat/constraints_std.h" -#include "mp/presolve.h" +#include "mp/flat/constr_keeper.h" +#include "mp/flat/constr_std.h" +#include "mp/valcvt.h" #include "mp/flat/redef/std/range_con.h" namespace mp { @@ -881,7 +881,7 @@ class FlatConverter : void FinishModelInput() { MPD( ConvertModel() ); - if (relax()) // TODO bridge? + if (relax()) // TODO value presolve link? GetModel().RelaxIntegrality(); GetModel().PushModelTo(GetModelAPI()); } @@ -909,9 +909,9 @@ class FlatConverter : const ModelAPI& GetModelAPI() const { return modelapi_; } ModelAPI& GetModelAPI() { return modelapi_; } - /// Expose Presolver - const pre::Presolver& GetPresolver() const { return presolver_; } - pre::Presolver& GetPresolver() { return presolver_; } + /// Expose ValuePresolver + const pre::ValuePresolver& GetValuePresolver() const { return value_presolver_; } + pre::ValuePresolver& GetValuePresolver() { return value_presolver_; } private: std::unordered_map map_fixed_vars_; @@ -949,7 +949,7 @@ class FlatConverter : /// Reuse Presolver's target nodes for all variables pre::ValueNode& GetVarValueNode() - { return GetPresolver().GetTargetNodes().GetVarValues().MakeSingleKey(); } + { return GetValuePresolver().GetTargetNodes().GetVarValues().MakeSingleKey(); } /// Constraint type's Value Node template @@ -1067,7 +1067,7 @@ class FlatConverter : private: void InitOwnOptions() { GetEnv().AddOption("cvt:pre:all", - "0/1*: Set to 0 to disable all presolve in the flat converter.", + "0/1*: Set to 0 to disable most presolve in the flat converter.", options_.preprocessAnything_, 0, 1); GetEnv().AddOption("cvt:pre:eqresult", "0/1*: Preprocess reified equality comparison's boolean result bounds.", @@ -1099,8 +1099,8 @@ class FlatConverter : private: ModelAPIType modelapi_; // We store modelapi in the converter for speed - pre::Presolver presolver_; - pre::CopyBridge copy_bridge_ { GetPresolver() }; + pre::ValuePresolver value_presolver_; + pre::CopyLink copy_link_ { GetValuePresolver() }; protected: @@ -1232,8 +1232,8 @@ class FlatConverter : INSTALL_ITEM_CONVERTER(RangeQuadraticConstraintConverter) public: - /// Presolve bridge copying values between model items - pre::CopyBridge& GetCopyBridge() { return copy_bridge_; } + /// Presolve link copying values between model items + pre::CopyLink& GetCopyLink() { return copy_link_; } }; diff --git a/include/mp/flat/converter_model.h b/include/mp/flat/converter_model.h index 4ed9ba3ac..d2fbf7416 100644 --- a/include/mp/flat/converter_model.h +++ b/include/mp/flat/converter_model.h @@ -7,8 +7,8 @@ #include #include "mp/flat/obj_std.h" -#include "mp/flat/constraints_std.h" -#include "mp/flat/constraint_keeper.h" +#include "mp/flat/constr_std.h" +#include "mp/flat/constr_keeper.h" namespace mp { diff --git a/include/mp/flat/model_api_base.h b/include/mp/flat/model_api_base.h index d1ad83e8e..dd2a29895 100644 --- a/include/mp/flat/model_api_base.h +++ b/include/mp/flat/model_api_base.h @@ -28,7 +28,7 @@ #include "mp/arrayref.h" #include "mp/common.h" -#include "mp/flat/constraint_base.h" +#include "mp/flat/constr_base.h" #include "mp/flat/obj_std.h" namespace mp { diff --git a/include/mp/flat/model_api_connect.h b/include/mp/flat/model_api_connect.h index 878b02efb..36a0f3edd 100644 --- a/include/mp/flat/model_api_connect.h +++ b/include/mp/flat/model_api_connect.h @@ -26,7 +26,7 @@ template std::unique_ptr CreateModelMgrWithFlatConverter(Backend& gc, Env& e, - pre::BasicPresolver*& pPre) { + pre::BasicValuePresolver*& pPre) { using SolverFlatCvt = FlatCvtImpl; using SolverProblemFlattener = mp::ProblemFltImpl< mp::ProblemFlattener, mp::Problem, SolverFlatCvt>; @@ -36,7 +36,7 @@ CreateModelMgrWithFlatConverter(Backend& gc, Env& e, pcvt->GetFlatCvt().GetModelAPI().set_other(&gc); gc.set_other( &pcvt->GetFlatCvt().GetModelAPI()); - pPre = &pcvt->GetFlatCvt().GetPresolver(); + pPre = &pcvt->GetFlatCvt().GetValuePresolver(); return res; } diff --git a/include/mp/flat/problem_flattener.h b/include/mp/flat/problem_flattener.h index 8a05c6da9..737d4f855 100644 --- a/include/mp/flat/problem_flattener.h +++ b/include/mp/flat/problem_flattener.h @@ -10,9 +10,9 @@ #include "mp/converter-base.h" #include "mp/expr-visitor.h" #include "mp/flat/eexpr.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" #include "mp/flat/obj_std.h" -#include "mp/presolve.h" +#include "mp/valcvt.h" namespace mp { @@ -109,6 +109,7 @@ class ProblemFlattener : } protected: + /// Convert problem items void ConvertStandardItems() { ////////////////////////// Variables ConvertVars(); @@ -149,16 +150,18 @@ class ProblemFlattener : types[i] = mpvar.type(); } auto vnr = GetFlatCvt().AddVars(lbs, ubs, types); - GetCopyBridge().AddEntry({ - GetPresolver().GetSourceNodes().GetVarValues().MakeSingleKey(). + GetCopyLink().AddEntry({ + GetValuePresolver().GetSourceNodes().GetVarValues().MakeSingleKey(). Add(lbs.size()), vnr }); } + /// Convert a common expr void Convert(typename ProblemType::MutCommonExpr ) { /// Converting on demand, see VisitCommonExpr } + /// Convert an objective void Convert(typename ProblemType::MutObjective obj) { auto le = ToLinTerms(obj.linear_expr()); NumericExpr e = obj.nonlinear_expr(); @@ -187,10 +190,11 @@ class ProblemFlattener : std::move(eexpr.GetQPTerms())}); } + /// Convert an algebraic constraint void ConvertAlgCon(int i) { auto pr = PrepareAlgConstraint(i); auto nr = AddAlgebraicConstraint(pr); - AddCopyBridgeFromSource(nr); + AddCopyLinkFromSource(nr); } /// Preparation info @@ -235,7 +239,7 @@ class ProblemFlattener : /// Add algebraic constraint to FlatCvt pre::NodeRange AddAlgebraicConstraint(const AlgConPrepare& pr) { - pre::NodeRange nr; // presolve bridge + pre::NodeRange nr; // value presolve link if (pr.qt.empty()) { if (pr.compl_var<0) nr = AddConstraint( LinConRange{ std::move(pr.lt), @@ -259,13 +263,15 @@ class ProblemFlattener : return nr; } - void AddCopyBridgeFromSource(pre::NodeRange nr) { - GetCopyBridge().AddEntry( { - GetPresolver().GetSourceNodes().GetConValues()(0).Add(), + /// Add a copy link from a source item + void AddCopyLinkFromSource(pre::NodeRange nr) { + GetCopyLink().AddEntry( { + GetValuePresolver().GetSourceNodes().GetConValues()(0).Add(), nr } ); } + /// Convert a logical constraint void ConvertLogicalCon(int i) { auto e = GetModel().logical_con(i); const auto resvar = MP_DISPATCH( Convert2Var(e.expr()) ); @@ -273,7 +279,7 @@ class ProblemFlattener : assert(GetFlatCvt().HasInitExpression(resvar)); const auto& ie = GetFlatCvt().GetInitExpression(resvar); /// TODO check that logical cons' values come after algebraic ones - AddCopyBridgeFromSource( + AddCopyLinkFromSource( ie.GetCK()->GetValueNode().Select( ie.GetIndex() )); } @@ -627,7 +633,7 @@ class ProblemFlattener : return VisitFunctionalExpression({ e.arg() }); } - /// TODO how to bridge them if they are no real items in NL? + /// TODO how to link them if they are no real items in NL? void ConvertSOSConstraints() { if (sos()) { auto sosno = GetModel(). @@ -737,7 +743,8 @@ class ProblemFlattener : //////////////////////////// UTILITIES ///////////////////////////////// /// protected: - pre::Presolver& GetPresolver() { return GetFlatCvt().GetPresolver(); } + pre::ValuePresolver& GetValuePresolver() + { return GetFlatCvt().GetValuePresolver(); } private: std::unordered_map map_fixed_vars_; @@ -750,8 +757,8 @@ class ProblemFlattener : int MakeFixedVar(double value) // TODO use proper const term in obj { return GetFlatCvt().MakeFixedVar(value); } - /// Presolve bridge copying values between model items - pre::CopyBridge& GetCopyBridge() { return GetFlatCvt().GetCopyBridge(); } + /// Presolve link just copying values between model items + pre::CopyLink& GetCopyLink() { return GetFlatCvt().GetCopyLink(); } /////////////////////////////////////////////////////////////////////// /////////////////////// OPTIONS ///////////////////////// diff --git a/include/mp/flat/redef/MIP/abs.h b/include/mp/flat/redef/MIP/abs.h index 1dfb25e89..e352b66d5 100644 --- a/include/mp/flat/redef/MIP/abs.h +++ b/include/mp/flat/redef/MIP/abs.h @@ -2,7 +2,7 @@ #define ABS_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/alldiff.h b/include/mp/flat/redef/MIP/alldiff.h index 3a8a0a2d1..c08d98330 100644 --- a/include/mp/flat/redef/MIP/alldiff.h +++ b/include/mp/flat/redef/MIP/alldiff.h @@ -6,7 +6,7 @@ */ #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { @@ -25,7 +25,7 @@ class AllDiffConverter_MIP : using ItemType = AllDiffConstraint; /// Convert in positive context - /// TODO add presolve bridge? + /// TODO add presolve link? void ConvertCtxPos(const ItemType& alld, int ) { const auto& args = alld.GetArguments(); const auto lba_dbl = GetMC().lb_array(args); diff --git a/include/mp/flat/redef/MIP/complement.h b/include/mp/flat/redef/MIP/complement.h index 4c901bcaa..a8335f250 100644 --- a/include/mp/flat/redef/MIP/complement.h +++ b/include/mp/flat/redef/MIP/complement.h @@ -4,7 +4,7 @@ #include #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/cond_eq.h b/include/mp/flat/redef/MIP/cond_eq.h index 179a3d081..1b3f95f1c 100644 --- a/include/mp/flat/redef/MIP/cond_eq.h +++ b/include/mp/flat/redef/MIP/cond_eq.h @@ -2,7 +2,7 @@ #define COND_EQ_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/cond_ineq.h b/include/mp/flat/redef/MIP/cond_ineq.h index 88211a515..78e2d51ca 100644 --- a/include/mp/flat/redef/MIP/cond_ineq.h +++ b/include/mp/flat/redef/MIP/cond_ineq.h @@ -2,7 +2,7 @@ #define COND_INEQ_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/count.h b/include/mp/flat/redef/MIP/count.h index 5f3bc2c80..6aed9aad4 100644 --- a/include/mp/flat/redef/MIP/count.h +++ b/include/mp/flat/redef/MIP/count.h @@ -2,7 +2,7 @@ #define COUNT_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/div.h b/include/mp/flat/redef/MIP/div.h index f641b97b3..501d29b32 100644 --- a/include/mp/flat/redef/MIP/div.h +++ b/include/mp/flat/redef/MIP/div.h @@ -2,7 +2,7 @@ #define DIV_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/ifthenelse.h b/include/mp/flat/redef/MIP/ifthenelse.h index 7bdf1933a..cbd7b9bc9 100644 --- a/include/mp/flat/redef/MIP/ifthenelse.h +++ b/include/mp/flat/redef/MIP/ifthenelse.h @@ -2,7 +2,7 @@ #define IFTHENELSE_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/indicator_ge.h b/include/mp/flat/redef/MIP/indicator_ge.h index dab1f9dad..4b72769fe 100644 --- a/include/mp/flat/redef/MIP/indicator_ge.h +++ b/include/mp/flat/redef/MIP/indicator_ge.h @@ -2,7 +2,7 @@ #define INDICATOR_GE_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/indicator_le.h b/include/mp/flat/redef/MIP/indicator_le.h index 3aa8a33c9..f751a44ee 100644 --- a/include/mp/flat/redef/MIP/indicator_le.h +++ b/include/mp/flat/redef/MIP/indicator_le.h @@ -2,7 +2,7 @@ #define INDICATOR_LE_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/indicator_quad.h b/include/mp/flat/redef/MIP/indicator_quad.h index b1ec3d65c..8525364c4 100644 --- a/include/mp/flat/redef/MIP/indicator_quad.h +++ b/include/mp/flat/redef/MIP/indicator_quad.h @@ -6,7 +6,7 @@ */ #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/logical_and.h b/include/mp/flat/redef/MIP/logical_and.h index 6eab87f01..f08d649d4 100644 --- a/include/mp/flat/redef/MIP/logical_and.h +++ b/include/mp/flat/redef/MIP/logical_and.h @@ -2,7 +2,7 @@ #define LOGICAL_AND_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/logical_not.h b/include/mp/flat/redef/MIP/logical_not.h index f92cc6b47..2acac9029 100644 --- a/include/mp/flat/redef/MIP/logical_not.h +++ b/include/mp/flat/redef/MIP/logical_not.h @@ -2,7 +2,7 @@ #define LOGICAL_NOT_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/logical_or.h b/include/mp/flat/redef/MIP/logical_or.h index 4ecf41774..3380e8064 100644 --- a/include/mp/flat/redef/MIP/logical_or.h +++ b/include/mp/flat/redef/MIP/logical_or.h @@ -2,7 +2,7 @@ #define LOGICAL_OR_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/min_max.h b/include/mp/flat/redef/MIP/min_max.h index 41cecaa5f..92efaeb04 100644 --- a/include/mp/flat/redef/MIP/min_max.h +++ b/include/mp/flat/redef/MIP/min_max.h @@ -6,7 +6,7 @@ */ #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/numberof_const.h b/include/mp/flat/redef/MIP/numberof_const.h index 503cde945..3c18b3dbd 100644 --- a/include/mp/flat/redef/MIP/numberof_const.h +++ b/include/mp/flat/redef/MIP/numberof_const.h @@ -2,7 +2,7 @@ #define NUMBEROF_CONST_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/numberof_var.h b/include/mp/flat/redef/MIP/numberof_var.h index fd3fe3d69..3b8cea148 100644 --- a/include/mp/flat/redef/MIP/numberof_var.h +++ b/include/mp/flat/redef/MIP/numberof_var.h @@ -2,7 +2,7 @@ #define NUMBEROF_VAR_H #include "mp/flat/redef/redef_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/include/mp/flat/redef/redef_base.h b/include/mp/flat/redef/redef_base.h index ac79a2c8a..cc05a53f2 100644 --- a/include/mp/flat/redef/redef_base.h +++ b/include/mp/flat/redef/redef_base.h @@ -2,7 +2,7 @@ #define REDEF_BASE_H #include "mp/format.h" -#include "mp/presolve.h" +#include "mp/valcvt.h" namespace mp { @@ -19,7 +19,7 @@ class BasicItemConverter { /// Access ModelConverter ModelConverter& GetMC() { return mdl_cvt_; } /// Access Presolver - pre::Presolver& GetPre() { return GetMC().GetPresolver(); } + pre::ValuePresolver& GetPre() { return GetMC().GetPresolver(); } /// Access specific item's ValueNode template pre::ValueNode& GetVN(Item* pc) @@ -47,9 +47,9 @@ class BasicFuncConstrCvt : /// if only one of these is necessary, significant model reduction /// can be achieved in certain cases. /// - /// Responsible for adding presolve bridges, if any + /// Responsible for adding presolve links, if any /// @param item: the item to be converted - /// @param i: item index, used to create a presolve bridge + /// @param i: item index, used to create a presolve link /// /// The Impl can reimplement this template diff --git a/include/mp/flat/redef/std/range_con.h b/include/mp/flat/redef/std/range_con.h index 8f2fedd38..f1d2f5f54 100644 --- a/include/mp/flat/redef/std/range_con.h +++ b/include/mp/flat/redef/std/range_con.h @@ -6,32 +6,32 @@ */ #include "mp/flat/redef/redef_base.h" -#include "mp/presolve-bridge.h" -#include "mp/flat/constraints_std.h" +#include "mp/valcvt-link.h" +#include "mp/flat/constr_std.h" namespace mp { namespace pre { -/// Presolve bridge between RangeCon and Con(LE/EQ/GE)+Slack. +/// Presolve link between RangeCon and Con(LE/EQ/GE)+Slack. /// TODO dependency inversion #164 -/// (FlatConverter needs just a BasicBridge*? Entry type?) +/// (FlatConverter needs just a BasicLink*? Entry type?) template class RangeCon2Slack : - public BasicStaticIndivEntryBridge< + public BasicStaticIndivEntryLink< RangeCon2Slack, 3, 3> { public: /// Base class - using Base = BasicStaticIndivEntryBridge< + using Base = BasicStaticIndivEntryLink< RangeCon2Slack, 3, 3>; /// Constructor RangeCon2Slack(ModelConverter& cvt, const typename Base::NodeList& ndl) : - Base(cvt.GetPresolver(), ndl), cvt_(cvt) { } + Base(cvt.GetValuePresolver(), ndl), cvt_(cvt) { } - /// Define pre- / postsolve methods for individual bridge entries. - /// Typedef BridgeEntry is created in Base as std::array + /// Define pre- / postsolve methods for individual link entries. + /// Typedef LinkEntry is created in Base as std::array /// (3 is the base class template parameter) /// and means the following indexes: {range_con, lin_con, slack_index} @@ -40,7 +40,7 @@ class RangeCon2Slack : /// Primals: compute slack. /// Slacks are probably only needed for Gurobi LP warmstart. /// Who does not need them, can use unpresolved primal solution. - void PresolveSolutionEntry(const typename Base::BridgeEntry& be) { + void PresolveSolutionEntry(const typename Base::LinkEntry& be) { SetDbl(be, 1, GetDbl(be, 0)); const auto& orig_cons = GetMC().template GetConstraint(be[0]); @@ -48,7 +48,7 @@ class RangeCon2Slack : } /// Postsolve solution (primal + dual) - void PostsolveSolutionEntry(const typename Base::BridgeEntry& be) { + void PostsolveSolutionEntry(const typename Base::LinkEntry& be) { SetDbl(be, 0, GetDbl(be, 1)); } @@ -57,26 +57,26 @@ class RangeCon2Slack : /// From a range constraint's basis status, /// transfer it to the slack. /// Set the new constraint's status to 'equ'. - void PresolveBasisEntry(const typename Base::BridgeEntry& be) { + void PresolveBasisEntry(const typename Base::LinkEntry& be) { SetInt(be, 2, GetInt(be, 0)); SetInt(be, 1, (int)BasicStatus::equ); } /// Postsolve basis /// /// The reverse (forget solver's constraint status) - void PostsolveBasisEntry(const typename Base::BridgeEntry& be) { + void PostsolveBasisEntry(const typename Base::LinkEntry& be) { SetInt(be, 0, GetInt(be, 2)); } /// Presolve IIS - void PresolveIISEntry(const typename Base::BridgeEntry& ) { + void PresolveIISEntry(const typename Base::LinkEntry& ) { /// Should not need } /// Postsolve IIS /// /// Take slack's if set, otherwise the constraint's - void PostsolveIISEntry(const typename Base::BridgeEntry& be) { + void PostsolveIISEntry(const typename Base::LinkEntry& be) { if (auto slk_iis = GetInt(be, 2)) SetInt(be, 0, slk_iis); else @@ -84,11 +84,11 @@ class RangeCon2Slack : } /// Mark Lazy/user cut: copy flag - void PresolveLazyUserCutFlagsEntry(const typename Base::BridgeEntry& be) { + void PresolveLazyUserCutFlagsEntry(const typename Base::LinkEntry& be) { SetInt(be, 1, GetInt(be, 0)); } - void PostsolveLazyUserCutFlagsEntry(const typename Base::BridgeEntry& ) { + void PostsolveLazyUserCutFlagsEntry(const typename Base::LinkEntry& ) { /// Should not need } @@ -142,9 +142,9 @@ class RangeConstraintConverter : /// Conversion /// - /// Responsible for adding presolve bridges + /// Responsible for adding presolve links /// @param item: the item to be converted - /// @param i: item index, used to create a presolve bridge + /// @param i: item index, used to create a presolve link void Convert(const ItemType& item, int i) { auto rr = Relate(item.lb(), item.ub()); if (rr[0] && rr[1] && rr[2]) @@ -165,7 +165,7 @@ class RangeConstraintConverter : body.add_term(1.0, slk); AlgConEQ lceq { std::move(body), item.ub() }; int i1 = GetMC().AddConstraint(std::move(lceq)); - GetSlackBridge().AddEntry({i, i1, slk}); + GetSlackLink().AddEntry({i, i1, slk}); } void ConvertWithRhs(const ItemType& item, int i, RangeRelations rr) { pre::NodeRange nr; // target node+index @@ -181,15 +181,15 @@ class RangeConstraintConverter : AlgConEQ( item.GetBody(), (item.lb()+item.ub()) / 2.0 ) ); } // else, both are inf, forget - GetMC().GetCopyBridge().AddEntry( + GetMC().GetCopyLink().AddEntry( { GET_CONSTRAINT_VALUE_NODE(ItemType).Select(i), nr }); } - using SlackBridge = pre::RangeLinCon2Slack; - SlackBridge& GetSlackBridge() { return bridge_rng2slk_; } + using SlackLink = pre::RangeLinCon2Slack; + SlackLink& GetSlackLink() { return link_rng2slk_; } private: - SlackBridge bridge_rng2slk_ { + SlackLink link_rng2slk_ { GetMC(), { &GET_CONSTRAINT_VALUE_NODE(ItemType), &GET_CONSTRAINT_VALUE_NODE(AlgConEQ), diff --git a/include/mp/model-mgr-base.h b/include/mp/model-mgr-base.h index 248098bc6..6f59eb179 100644 --- a/include/mp/model-mgr-base.h +++ b/include/mp/model-mgr-base.h @@ -32,8 +32,7 @@ class BasicModelManager { /// Read NL model virtual void ReadNLModel(const std::string& nl_filename, const std::string& filename_no_ext, - std::function - cb_checkmodel) = 0; + void (*cb_checkmodel)(size_t, size_t, size_t)) = 0; /// User-provided primal solution virtual ArrayRef InitialValues() = 0; diff --git a/include/mp/model-mgr-with-pb.h b/include/mp/model-mgr-with-pb.h index fb1848400..798242f65 100644 --- a/include/mp/model-mgr-with-pb.h +++ b/include/mp/model-mgr-with-pb.h @@ -86,8 +86,8 @@ class ModelManagerWithProblemBuilder : void ReadNLModel(const std::string& nl_filename, const std::string& filename_no_ext, - std::function - cb_checkmodel) override { + void (*cb_checkmodel)(size_t, size_t, size_t)) + override { steady_clock::time_point start = steady_clock::now(); ReadNLFile(nl_filename); diff --git a/include/mp/presolve-base.h b/include/mp/valcvt-base.h similarity index 89% rename from include/mp/presolve-base.h rename to include/mp/valcvt-base.h index 72c5d35f0..21da43116 100644 --- a/include/mp/presolve-base.h +++ b/include/mp/valcvt-base.h @@ -1,9 +1,8 @@ -#ifndef PRESOLVE_BASE_H -#define PRESOLVE_BASE_H +#ifndef VALUE_PRESOLVE_BASE_H +#define VALUE_PRESOLVE_BASE_H /** - Interface for value presolver: transforms solutions etc. - between original and presolved model + Interface for value presolver: */ #include @@ -14,6 +13,10 @@ namespace mp { + +/// Namespace mp::pre: value presolve methods. +/// They transform solutions, etc., +/// between the original and presolved models namespace pre { /// Debugging template @@ -179,12 +182,12 @@ using ModelValuesInt = ModelValues< ValueMapInt >; using ModelValuesDbl = ModelValues< ValueMapDbl >; -/// Presolver interface -/// Currently only addresses value pre- / postsolve (solutions, basis, ...) -class BasicPresolver { +/// ValuePresolver interface. +/// Addresses value pre- / postsolve (solutions, basis, etc) +class BasicValuePresolver { public: /// Virtual destructor - virtual ~BasicPresolver() = default; + virtual ~BasicValuePresolver() = default; /// Presolve solution (primal + dual) virtual ModelValuesDbl PresolveSolution(const ModelValuesDbl& ) = 0; @@ -206,7 +209,7 @@ class BasicPresolver { }; -/// index range for some bridge or node +/// index range for some link or node struct IndexRange { /// Construct, possibly from a single index IndexRange(int b=0, int e=-1) : beg(b), end(e<0 ? b+1 : e) { } @@ -231,22 +234,22 @@ struct IndexRange { /// Some backends need presolver /// for pre- / postsolving of suffix values etc -class BasicPresolverKeeper { +class BasicValuePresolverKeeper { protected: - void SetPresolver(pre::BasicPresolver* pPre) { + void SetValuePresolver(pre::BasicValuePresolver* pPre) { pPresolver_ = pPre; } - const pre::BasicPresolver& GetPresolver() const + const pre::BasicValuePresolver& GetValuePresolver() const { assert(pPresolver_); return *pPresolver_; } - pre::BasicPresolver& GetPresolver() + pre::BasicValuePresolver& GetValuePresolver() { assert(pPresolver_); return *pPresolver_; } private: - pre::BasicPresolver* pPresolver_ = nullptr; + pre::BasicValuePresolver* pPresolver_ = nullptr; }; } // namespace mp -#endif // PRESOLVE_BASE_H +#endif // VALUE_PRESOLVE_BASE_H diff --git a/include/mp/presolve-bridge.h b/include/mp/valcvt-link.h similarity index 52% rename from include/mp/presolve-bridge.h rename to include/mp/valcvt-link.h index f70507b65..5e519721d 100644 --- a/include/mp/presolve-bridge.h +++ b/include/mp/valcvt-link.h @@ -1,25 +1,25 @@ -#ifndef PRESOLVE_BRIDGE_H -#define PRESOLVE_BRIDGE_H +#ifndef VALUE_PRESOLVE_LINK_H +#define VALUE_PRESOLVE_LINK_H #include #include #include "mp/common.h" -#include "presolve-node.h" +#include "valcvt-node.h" namespace mp { namespace pre { -/// Index range in a bridge -using BridgeIndexRange = IndexRange; +/// Index range in a link +using ValcvtLinkIndexRange = IndexRange; -/// Declare Presolver -class Presolver; +/// Declare ValuePresolver +class ValuePresolver; /// Macro for a list of pre- / postsolve method definitions -/// in a bridge. +/// in a link. /// Requires PRESOLVE_KIND defined to declare / define corr. methods #define LIST_PRESOLVE_METHODS \ PRESOLVE_KIND(Solution) \ @@ -28,49 +28,53 @@ class Presolver; PRESOLVE_KIND(LazyUserCutFlags) // ... -/// Bridge interface + +/// ValuePresolveLink interface /// -/// A bridge is an array of value converters between nodes. +/// A link is an array of value converters between nodes. /// All converters are of the same type -class BasicBridge { +class BasicValcvtLink { public: /// Constructor - BasicBridge(Presolver& pre) : presolver_(pre) { } + BasicValcvtLink(ValuePresolver& pre) : vsalue_presolver_(pre) { } /// Virtual destructor - virtual ~BasicBridge() = default; + virtual ~BasicValcvtLink() = default; - /// The below pre- / postsolves work on a range of bridge entries + /// The below pre- / postsolve methods + /// work on a range of link entries /// Postsolves should usually loop the range backwards #define PRESOLVE_KIND(name) \ - virtual void Presolve ## name (BridgeIndexRange ) = 0; \ - virtual void Postsolve ## name(BridgeIndexRange ) = 0; + virtual void Presolve ## name (ValcvtLinkIndexRange ) = 0; \ + virtual void Postsolve ## name(ValcvtLinkIndexRange ) = 0; LIST_PRESOLVE_METHODS protected: - /// Add a range of bridge entries to the Presolver's list - /// Every derived bridge should call either of the next two - /// whenever adding a bridge entry - void RegisterBridgeIndex(int i) - { RegisterBridgeIndexRange( {i, i+1} ); } - void RegisterBridgeIndexRange(BridgeIndexRange ); + /// Add a range of link entries to the Presolver's list. + /// Every derived link should call either of the next two methods + /// whenever adding a link entry. + /// Version 1: add single link + void RegisterLinkIndex(int i) + { RegisterLinkIndexRange( {i, i+1} ); } + /// Version 2: add a range of links + void RegisterLinkIndexRange(ValcvtLinkIndexRange ); private: - Presolver& presolver_; + ValuePresolver& vsalue_presolver_; }; -/// Bridge range: range of conversion specifiers of certain type -/// The bridge is specified as well -struct BridgeRange { +/// Link range: range of conversion specifiers of certain type. +/// The link is specified as well +struct LinkRange { /// Try & extend the range /// @return true iff extension worked, /// otherwise the caller would have to add the new range /// separately - bool ExtendRange(BridgeRange br) { - if (&b_ == &br.b_) { // same bridge - if (ir_.end == br.ir_.beg) { // and consecutive ranges + bool ExtendRange(LinkRange br) { + if (&b_ == &br.b_) { // same link? + if (ir_.end == br.ir_.beg) { // and consecutive ranges? ir_.end = br.ir_.end; return true; } @@ -78,35 +82,35 @@ struct BridgeRange { return false; } - BasicBridge& b_; - BridgeIndexRange ir_; + BasicValcvtLink& b_; + ValcvtLinkIndexRange ir_; }; -/// A specific bridge: each entry just copies a range of values +/// A specific link: each entry just copies a range of values/ /// Useful to transfer values between NL and internal model, /// internal model and solver, and in conversions preserving /// all values -class CopyBridge : public BasicBridge { +class CopyLink : public BasicValcvtLink { public: /// Constructor - CopyBridge(Presolver& pre) : BasicBridge(pre) { } + CopyLink(ValuePresolver& pre) : BasicValcvtLink(pre) { } - /// Single bridge entry - using BridgeEntry = std::pair; + /// Single link entry + using LinkEntry = std::pair; /// Collection of entries - using CollectionOfEntries = std::vector; + using CollectionOfEntries = std::vector; /// Add entry /// Instead of a new entry, tries to extend the last one /// if exists - void AddEntry(BridgeEntry be) { + void AddEntry(LinkEntry be) { if (entries_.empty() || !entries_.back().first.ExtendableBy(be.first) || !entries_.back().second.ExtendableBy(be.second)) { entries_.push_back(be); // Add new entry - RegisterBridgeIndex(entries_.size()-1); + RegisterLinkIndex(entries_.size()-1); } else { // Extend last entry entries_.back().first.ExtendBy(be.first); entries_.back().second.ExtendBy(be.second); @@ -118,23 +122,23 @@ class CopyBridge : public BasicBridge { #undef PRESOLVE_KIND #define PRESOLVE_KIND(name) \ - void Presolve ## name (BridgeIndexRange ir) override \ + void Presolve ## name (ValcvtLinkIndexRange ir) override \ { CopySrcDest(ir); } \ - void Postsolve ## name(BridgeIndexRange ir) override \ + void Postsolve ## name(ValcvtLinkIndexRange ir) override \ { CopyDestSrc(ir); } LIST_PRESOLVE_METHODS protected: /// Copy src -> dest for index range ir - void CopySrcDest(BridgeIndexRange ir) { + void CopySrcDest(ValcvtLinkIndexRange ir) { for (int i=ir.beg; i!=ir.end; ++i) { const auto& br = entries_[i]; Copy(br.first, br.second); } } /// Copy src <- dest for index range ir. Loop backwards - void CopyDestSrc(BridgeIndexRange ir) { + void CopyDestSrc(ValcvtLinkIndexRange ir) { for (int i=ir.end; (i--)!=ir.beg; ) { const auto& br = entries_[i]; Copy(br.second, br.first); @@ -146,40 +150,42 @@ class CopyBridge : public BasicBridge { }; -/// A stub for bridges which process each entry individually, -/// in contrast to Presolve...(BridgeIndexRange ...) -/// Some of such bridges could be optimized to store +/// A stub for links which process each entry individually, +/// in contrast to Presolve...(ValcvtLinkIndexRange ...). +/// Some of such links could be optimized to store /// a range of transformations in each entry if that helps +/// (but this could be an overoptimization?) +/// +/// Usage: a derived class should define some methods +/// Presolve...(const LinkEntry& ) and Postsolve...(const LinkEntry&). /// -/// Usage: a derived class should define types -/// BridgeEntry and NodeList, and some methods -/// Presolve...(const BridgeEntry& ) and Postsolve...(const BridgeEntry&). -/// TODO: Those methods which are not defined, just copy values +/// TODO: we could default as follows: +/// Those methods which are not defined, just copy values /// (which might be correct in _some_ cases). -/// Need a "default copy" method. +/// Then, need a "default copy" method. /// /// Using CRTP: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern -template -class BasicIndivEntryBridge : public BasicBridge { +template +class BasicIndivEntryLink : public BasicValcvtLink { public: /// Constructor - BasicIndivEntryBridge(Presolver& pre) : - BasicBridge(pre) { } + BasicIndivEntryLink(ValuePresolver& pre) : + BasicValcvtLink(pre) { } /// Add entry /// Instead of a new entry, tries to extend the last one /// if exists - void AddEntry(BridgeEntry be) { + void AddEntry(LinkEntry be) { entries_.push_back(be); // Add new entry - RegisterBridgeIndex(entries_.size()-1); + RegisterLinkIndex(entries_.size()-1); } #undef PRESOLVE_KIND #define PRESOLVE_KIND(name) \ - void Presolve ## name (BridgeIndexRange ir) override { \ + void Presolve ## name (ValcvtLinkIndexRange ir) override { \ for (int i=ir.beg; i!=ir.end; ++i) \ MPD( Presolve ## name ## Entry(entries_.at(i)) ); } \ - void Postsolve ## name(BridgeIndexRange ir) override { \ + void Postsolve ## name(ValcvtLinkIndexRange ir) override { \ for (int i=ir.end; i--!=ir.beg; ) \ MPD( Postsolve ## name ## Entry(entries_.at(i)) ); } @@ -187,26 +193,26 @@ class BasicIndivEntryBridge : public BasicBridge { private: - std::vector entries_; + std::vector entries_; }; -/// A static indiv entry bridge has a fixed number of ValueNodes +/// A static indiv entry link has a fixed number of ValueNodes /// and indexes into them. /// Generally NNodes==NIndexes template -class BasicStaticIndivEntryBridge : - public BasicIndivEntryBridge > { +class BasicStaticIndivEntryLink : + public BasicIndivEntryLink > { public: /// Base class - using Base = BasicIndivEntryBridge >; + using Base = BasicIndivEntryLink >; /// Typedef NodeList using NodeList = std::array; - /// Typedef: BridgeEntry is just an array if node indexes - using BridgeEntry = std::array; + /// Typedef: LinkEntry is just an array if node indexes + using LinkEntry = std::array; /// Constructor - BasicStaticIndivEntryBridge(Presolver& pre, const NodeList& ndl) : + BasicStaticIndivEntryLink(ValuePresolver& pre, const NodeList& ndl) : Base(pre), ndl_(ndl) { } protected: @@ -218,23 +224,23 @@ class BasicStaticIndivEntryBridge : /// Access int value at the node \a pos at the index /// stored in \a be[pos] /// - /// @param be: a BridgeEntry + /// @param be: a LinkEntry /// @param pos: node number from 0..NNodes-1 - int GetInt(const BridgeEntry& be, size_t pos) const + int GetInt(const LinkEntry& be, size_t pos) const { return GetNode(pos).GetInt(be[pos]); } /// SetInt - void SetInt(const BridgeEntry& be, size_t pos, int i) + void SetInt(const LinkEntry& be, size_t pos, int i) { GetNode(pos).SetInt(be[pos], i); } /// Access double value at the node \a pos at the index /// stored in \a be[pos] /// - /// @param be: a BridgeEntry + /// @param be: a LinkEntry /// @param pos: node number from 0..NNodes-1 - double GetDbl(const BridgeEntry& be, size_t pos) const + double GetDbl(const LinkEntry& be, size_t pos) const { return GetNode(pos).GetDbl(be[pos]); } /// SetDbl - void SetDbl(const BridgeEntry& be, size_t pos, double i) + void SetDbl(const LinkEntry& be, size_t pos, double i) { GetNode(pos).SetDbl(be[pos], i); } private: @@ -245,4 +251,4 @@ class BasicStaticIndivEntryBridge : } // namespace mp -#endif // PRESOLVE_BRIDGE_H +#endif // VALUE_PRESOLVE_LINK_H diff --git a/include/mp/presolve-node.h b/include/mp/valcvt-node.h similarity index 95% rename from include/mp/presolve-node.h rename to include/mp/valcvt-node.h index daeaa0c4f..bffdcd3ab 100644 --- a/include/mp/presolve-node.h +++ b/include/mp/valcvt-node.h @@ -1,7 +1,7 @@ -#ifndef PRESOLVE_NODE_H -#define PRESOLVE_NODE_H +#ifndef VALUE_PRESOLVE_NODE_H +#define VALUE_PRESOLVE_NODE_H -#include "presolve-base.h" +#include "valcvt-base.h" namespace mp { @@ -71,7 +71,7 @@ class ValueNode { /// Constructor ValueNode(std::string nm) : name_(nm) { } - /// Declared size (what is being used by bridges) + /// Declared size (what is being used by links) size_t size() const { return sz_; } /// Create entry (range) pointer: add n elements @@ -95,7 +95,7 @@ class ValueNode { /// Assign from ArrayRef. Always copy the values. /// TODO Check that values fit the declared size? - /// Problematic since e.g. Gurobi adds more variables in feasrelax + /// Problematic since, e.g., Gurobi adds more variables in feasrelax ValueNode& operator=(std::vector ai) { // assert(ai.size() <= size()); @@ -206,4 +206,4 @@ using ModelValuesTerminal = ModelValues< NodeMap >; } // namespace mp -#endif // PRESOLVE_NODE_H +#endif // VALUE_PRESOLVE_NODE_H diff --git a/include/mp/presolve.h b/include/mp/valcvt.h similarity index 61% rename from include/mp/presolve.h rename to include/mp/valcvt.h index 8d2b933d5..b7f13321e 100644 --- a/include/mp/presolve.h +++ b/include/mp/valcvt.h @@ -1,15 +1,15 @@ -#ifndef PRESOLVE_H -#define PRESOLVE_H +#ifndef VALUE_PRESOLVE_H +#define VALUE_PRESOLVE_H /** - @file presolve.h + @file valcvt.h. Implementation of value presolver */ #include -#include "presolve-node.h" -#include "presolve-bridge.h" +#include "valcvt-node.h" +#include "valcvt-link.h" namespace mp { @@ -17,17 +17,17 @@ namespace mp { namespace pre { -/// Array of bridge ranges +/// Array of link ranges /// /// This defines a chain of transformations -class BridgeRangeList : private std::deque { +class LinkRangeList : private std::deque { public: /// Base class typedef - using Base = std::deque; + using Base = std::deque; /// Add another range to the list, /// tries to extend the last range if possible - void Add(BridgeRange br) { + void Add(LinkRange br) { if (empty() || !back().ExtendRange(br)) push_back(br); } @@ -49,8 +49,10 @@ class BridgeRangeList : private std::deque { }; -/// Value presolver implementation -class Presolver : public BasicPresolver { +/// Value presolver implementation. +/// A ValuePresolver converts solutions and suffixes +/// between the original model and the presolved one. +class ValuePresolver : public BasicValuePresolver { public: /// Source nodes for model items const ModelValuesTerminal& GetSourceNodes() const { return src_; } @@ -60,43 +62,43 @@ class Presolver : public BasicPresolver { const ModelValuesTerminal& GetTargetNodes() const { return dest_; } ModelValuesTerminal& GetTargetNodes() { return dest_; } - /// Add (register) a bridge range - /// This is normally called automatically from a bridge + /// Add (register) a link range + /// This is normally called automatically from a link /// when an entry is added - void Add(BridgeRange br) { brl_.Add(br); } + void Add(LinkRange br) { brl_.Add(br); } /// Presolve solution (primal + dual) ModelValuesDbl PresolveSolution(const ModelValuesDbl& mvd) override - { return RunPresolve(&BasicBridge::PresolveSolution, mvd); } + { return RunPresolve(&BasicValcvtLink::PresolveSolution, mvd); } /// Postsolve solution (primal + dual) ModelValuesDbl PostsolveSolution(const ModelValuesDbl& mvd) override - { return RunPostsolve(&BasicBridge::PostsolveSolution, mvd); } + { return RunPostsolve(&BasicValcvtLink::PostsolveSolution, mvd); } /// Presolve basis (vars + cons) ModelValuesInt PresolveBasis(const ModelValuesInt& mvi) override - { return RunPresolve(&BasicBridge::PresolveBasis, mvi); } + { return RunPresolve(&BasicValcvtLink::PresolveBasis, mvi); } /// Postsolve solution (vars + cons) ModelValuesInt PostsolveBasis(const ModelValuesInt& mvi) override - { return RunPostsolve(&BasicBridge::PostsolveBasis, mvi); } + { return RunPostsolve(&BasicValcvtLink::PostsolveBasis, mvi); } /// Presolve IIS (vars + cons) ModelValuesInt PresolveIIS(const ModelValuesInt& mvi) override - { return RunPresolve(&BasicBridge::PresolveIIS, mvi); } + { return RunPresolve(&BasicValcvtLink::PresolveIIS, mvi); } /// Postsolve IIS (vars + cons) ModelValuesInt PostsolveIIS(const ModelValuesInt& mvi) override - { return RunPostsolve(&BasicBridge::PostsolveIIS, mvi); } + { return RunPostsolve(&BasicValcvtLink::PostsolveIIS, mvi); } /// Presolve LazyUserCutFlags (vars + cons) ModelValuesInt PresolveLazyUserCutFlags(const ModelValuesInt& mvi) override - { return RunPresolve(&BasicBridge::PresolveLazyUserCutFlags, mvi); } + { return RunPresolve(&BasicValcvtLink::PresolveLazyUserCutFlags, mvi); } protected: /// Helper type: virtual member function pointer - using BridgeFn = void (BasicBridge::*)(BridgeIndexRange); + using LinkFn = void (BasicValcvtLink::*)(ValcvtLinkIndexRange); /// Generic value presolve loop: forward template - ModelValues RunPresolve(BridgeFn fn, const ModelValues& mv) const { + ModelValues RunPresolve(LinkFn fn, const ModelValues& mv) const { src_ = mv; for (const auto& br: brl_) (br.b_.*fn)(br.ir_); @@ -105,7 +107,7 @@ class Presolver : public BasicPresolver { /// Generic value postsolve loop: backward template - ModelValues RunPostsolve(BridgeFn fn, const ModelValues& mv) const { + ModelValues RunPostsolve(LinkFn fn, const ModelValues& mv) const { dest_ = mv; for (auto rit=brl_.rbegin(); rit!=brl_.rend(); ++rit) (rit->b_.*fn)(rit->ir_); @@ -115,17 +117,17 @@ class Presolver : public BasicPresolver { private: mutable ModelValuesTerminal src_{std::string("src")}, dest_{std::string("dest")}; - BridgeRangeList brl_; + LinkRangeList brl_; }; -/// Implement bridge range registration in global Presolver +/// Implement link range registration in global Presolver inline void -BasicBridge::RegisterBridgeIndexRange(BridgeIndexRange bir) -{ presolver_.Add( { *this, bir } ); } +BasicValcvtLink::RegisterLinkIndexRange(ValcvtLinkIndexRange bir) +{ vsalue_presolver_.Add( { *this, bir } ); } } // namespace pre } // namespace mp -#endif // PRESOLVE_H +#endif // VALUE_PRESOLVE_H diff --git a/solvers/CMakeLists.txt b/solvers/CMakeLists.txt index 29f903533..03cd93756 100644 --- a/solvers/CMakeLists.txt +++ b/solvers/CMakeLists.txt @@ -233,6 +233,10 @@ add_ampl_backend(copt DLL_RUNTIME SHARED_LIB MODULE COPT LIBRARIES ${COPT_LIBS} add_ampl_backend(highsdirect DLL_RUNTIME SHARED_LIB MODULE HIGHS LIBRARIES ${HIGHS_LIBS} ${CMAKE_DL_LIBS}) + +add_ampl_backend(ortoolsmp DLL_RUNTIME SHARED_LIB + MODULE ortoolsmp LIBRARIES ${ortoolsmp_LIBS} ${CMAKE_DL_LIBS}) + ## TODO Cannot use 'add_ampl_backend' because of the -direct name suffix add_ampl_solver(cplexdirect DLL_RUNTIME SHARED_LIB MODULE CPLEX cplex-ampls-c-api.h diff --git a/solvers/copt/copt-lib.c b/solvers/copt/copt-lib.c index c5ec1031d..fec59fdca 100644 --- a/solvers/copt/copt-lib.c +++ b/solvers/copt/copt-lib.c @@ -17,9 +17,9 @@ APIEXPORT copt_prob* AMPLloadmodel(int argc, char** argv, void** slvout) { } APIEXPORT void AMPLwritesolution(AMPLS_MP_Solver* slv) { - AMPLSReportResults(&slv); + AMPLSReportResults(slv); } APIEXPORT void AMPLclosesolver(AMPLS_MP_Solver* slv) { - AMPLSCloseCopt(&slv); + AMPLSCloseCopt(slv); } \ No newline at end of file diff --git a/solvers/copt/coptbackend.cc b/solvers/copt/coptbackend.cc index 59f955bb3..b9cf10df3 100644 --- a/solvers/copt/coptbackend.cc +++ b/solvers/copt/coptbackend.cc @@ -34,12 +34,12 @@ namespace mp { /// need it to convert solution data /// @return CoptModelMgr std::unique_ptr -CreateCoptModelMgr(CoptCommon&, Env&, pre::BasicPresolver*&); +CreateCoptModelMgr(CoptCommon&, Env&, pre::BasicValuePresolver*&); void CoptBackend::OpenSolver() { int status = 0; - const auto& create_fn = GetCallbacks().cb_initsolver_; + const auto create_fn = GetCallbacks().init; if (create_fn) set_env((copt_env*)create_fn()); else @@ -71,10 +71,10 @@ void CoptBackend::CloseSolver() { CoptBackend::CoptBackend() { /// Create a ModelManager - pre::BasicPresolver* pPre; + pre::BasicValuePresolver* pPre; auto data = CreateCoptModelMgr(*this, *this, pPre); SetMM( std::move( data ) ); - SetPresolver(pPre); + SetValuePresolver(pPre); } CoptBackend::~CoptBackend() { @@ -102,7 +102,7 @@ void CoptBackend::InitOptionParsing() { } Solution CoptBackend::GetSolution() { - auto mv = GetPresolver().PostsolveSolution( + auto mv = GetValuePresolver().PostsolveSolution( { PrimalSolution(), DualSolution() } ); return { mv.GetVarValues()(), mv.GetConValues()(), GetObjectiveValues() }; // TODO postsolve obj values @@ -632,7 +632,7 @@ SolutionBasis CoptBackend::GetBasis() { std::vector varstt = VarStatii(); std::vector constt = ConStatii(); if (varstt.size() && constt.size()) { - auto mv = GetPresolver().PostsolveBasis( + auto mv = GetValuePresolver().PostsolveBasis( { std::move(varstt), {{{ CG_Linear, std::move(constt) }}} }); varstt = mv.GetVarValues()(); @@ -644,7 +644,7 @@ SolutionBasis CoptBackend::GetBasis() { } void CoptBackend::SetBasis(SolutionBasis basis) { - auto mv = GetPresolver().PresolveBasis( + auto mv = GetValuePresolver().PresolveBasis( { basis.varstt, basis.constt }); auto varstt = mv.GetVarValues()(); auto constt = mv.GetConValues()(CG_Linear); @@ -664,7 +664,7 @@ IIS CoptBackend::GetIIS() { auto variis = VarsIIS(); auto coniis = ConsIIS(); // TODO: This can be moved to a parent class? - auto mv = GetPresolver().PostsolveIIS( + auto mv = GetValuePresolver().PostsolveIIS( { variis, coniis }); return { mv.GetVarValues()(), mv.GetConValues()() }; } diff --git a/solvers/copt/coptbackend.h b/solvers/copt/coptbackend.h index 1be53c6a5..f6749a545 100644 --- a/solvers/copt/coptbackend.h +++ b/solvers/copt/coptbackend.h @@ -19,14 +19,14 @@ #include #include "mp/backend-mip.h" -#include "mp/presolve-base.h" +#include "mp/valcvt-base.h" #include "coptcommon.h" namespace mp { class CoptBackend : public MIPBackend, - public BasicPresolverKeeper, + public BasicValuePresolverKeeper, public CoptCommon { using BaseBackend = MIPBackend; diff --git a/solvers/copt/coptmodelapi.cc b/solvers/copt/coptmodelapi.cc index 853dd38ee..e0ad6835c 100644 --- a/solvers/copt/coptmodelapi.cc +++ b/solvers/copt/coptmodelapi.cc @@ -11,7 +11,7 @@ namespace mp { /// for recompilation speed std::unique_ptr CreateCoptModelMgr(CoptCommon& cc, Env& e, - pre::BasicPresolver*& pPre) { + pre::BasicValuePresolver*& pPre) { return CreateModelMgrWithFlatConverter< CoptModelAPI, MIPFlatConverter >(cc, e, pPre); } diff --git a/solvers/copt/coptmodelapi.h b/solvers/copt/coptmodelapi.h index 8616f9859..c99848066 100644 --- a/solvers/copt/coptmodelapi.h +++ b/solvers/copt/coptmodelapi.h @@ -6,7 +6,7 @@ #include "mp/env.h" #include "coptcommon.h" #include "mp/flat/model_api_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/solvers/copt/main.cc b/solvers/copt/main.cc index 99e820e24..00150c58d 100644 --- a/solvers/copt/main.cc +++ b/solvers/copt/main.cc @@ -8,9 +8,6 @@ extern "C" int main1(int, char **argv) { mp::RunBackendApp(argv, CreateCoptBackend); } -extern "C" int main2(int, char** argv, - void* (*init)(), void (*check)(size_t, size_t, size_t), - const char* (*text)()) { - mp::BasicBackend::Callbacks callbacks = { init, check, text }; - return mp::RunBackendApp(argv, CreateCoptBackend, callbacks); -} \ No newline at end of file +extern "C" int main2(int, char** argv, CCallbacks cb) { + return mp::RunBackendApp(argv, CreateCoptBackend, cb); +} diff --git a/solvers/cplexdirect/cplexbackend.cc b/solvers/cplexdirect/cplexbackend.cc index bf499a8d9..4c8de092f 100644 --- a/solvers/cplexdirect/cplexbackend.cc +++ b/solvers/cplexdirect/cplexbackend.cc @@ -35,16 +35,16 @@ namespace mp { /// need it to convert solution data /// @return GurobiModelMgr std::unique_ptr -CreateCplexModelMgr(CplexCommon&, Env&, pre::BasicPresolver*&); +CreateCplexModelMgr(CplexCommon&, Env&, pre::BasicValuePresolver*&); CplexBackend::CplexBackend() { OpenSolver(); - pre::BasicPresolver* pPre; + pre::BasicValuePresolver* pPre; auto data = CreateCplexModelMgr(*this, *this, pPre); SetMM( std::move( data ) ); - SetPresolver(pPre); + SetValuePresolver(pPre); /// Copy env/lp to ModelAPI copy_common_info_to_other(); @@ -58,7 +58,7 @@ void CplexBackend::OpenSolver() { int status; // Typically try the registered function first; // if not available call the solver's API function directly - const auto& create_fn = GetCallbacks().cb_initsolver_; + const auto create_fn = GetCallbacks().init; if (create_fn) set_env((CPXENVptr)create_fn()); else @@ -115,7 +115,7 @@ bool CplexBackend::IsQCP() const { Solution CplexBackend::GetSolution() { - auto mv = GetPresolver().PostsolveSolution( + auto mv = GetValuePresolver().PostsolveSolution( { PrimalSolution(), DualSolution() } ); return { mv.GetVarValues()(), mv.GetConValues()(), GetObjectiveValues() }; // TODO postsolve obj values diff --git a/solvers/cplexdirect/cplexbackend.h b/solvers/cplexdirect/cplexbackend.h index 94c9870fc..4f5a5e8a4 100644 --- a/solvers/cplexdirect/cplexbackend.h +++ b/solvers/cplexdirect/cplexbackend.h @@ -19,14 +19,14 @@ #include #include "mp/backend-mip.h" -#include "mp/presolve-base.h" +#include "mp/valcvt-base.h" #include "cplexcommon.h" namespace mp { class CplexBackend : public MIPBackend, - public BasicPresolverKeeper, + public BasicValuePresolverKeeper, public CplexCommon { using BaseBackend = MIPBackend; diff --git a/solvers/cplexdirect/cplexdirect-lib.c b/solvers/cplexdirect/cplexdirect-lib.c index 688274a4a..260384d8d 100644 --- a/solvers/cplexdirect/cplexdirect-lib.c +++ b/solvers/cplexdirect/cplexdirect-lib.c @@ -10,17 +10,16 @@ APIEXPORT CPXLPptr AMPLloadmodel(int argc, char** argv, void** slvout) { const char* nl_filename = argv[1]; const char *slv_opt= argv[2]; AMPLS_MP_Solver* slv= AMPLSOpenCPLEX(slv_opt); - int ret = -1; - ret = AMPLSLoadNLModel(slv, nl_filename); + AMPLSLoadNLModel(slv, nl_filename); CPXLPptr mdl = GetCPLEXmodel(slv); *slvout = slv; return mdl; } APIEXPORT void AMPLwritesolution(AMPLS_MP_Solver* slv) { - AMPLSReportResults(&slv); + AMPLSReportResults(slv); } APIEXPORT void AMPLclosesolver(AMPLS_MP_Solver* slv) { - AMPLSCloseCPLEX(&slv); -} \ No newline at end of file + AMPLSCloseCPLEX(slv); +} diff --git a/solvers/cplexdirect/cplexmodelapi.cc b/solvers/cplexdirect/cplexmodelapi.cc index f4af65b2c..d89e507aa 100644 --- a/solvers/cplexdirect/cplexmodelapi.cc +++ b/solvers/cplexdirect/cplexmodelapi.cc @@ -11,7 +11,7 @@ namespace mp { /// for recompilation speed std::unique_ptr CreateCplexModelMgr(CplexCommon& cc, Env& e, - pre::BasicPresolver*& pPre) { + pre::BasicValuePresolver*& pPre) { return CreateModelMgrWithFlatConverter< CplexModelAPI, MIPFlatConverter >(cc, e, pPre); } diff --git a/solvers/cplexdirect/cplexmodelapi.h b/solvers/cplexdirect/cplexmodelapi.h index 890600703..0de9884f4 100644 --- a/solvers/cplexdirect/cplexmodelapi.h +++ b/solvers/cplexdirect/cplexmodelapi.h @@ -6,7 +6,7 @@ #include "mp/env.h" #include "cplexcommon.h" #include "mp/flat/model_api_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/solvers/cplexdirect/main.cc b/solvers/cplexdirect/main.cc index c7cced9ff..a7800d617 100644 --- a/solvers/cplexdirect/main.cc +++ b/solvers/cplexdirect/main.cc @@ -8,9 +8,6 @@ extern "C" int main1(int, char **argv) { mp::RunBackendApp(argv, CreateCplexBackend); } -extern "C" int main2(int, char** argv, - void* (*init)(), void (*check)(size_t, size_t, size_t), - const char* (*text)()) { - mp::BasicBackend::Callbacks callbacks = { init, check, text }; - return mp::RunBackendApp(argv, CreateCplexBackend, callbacks); -} \ No newline at end of file +extern "C" int main2(int, char** argv, CCallbacks cb) { + return mp::RunBackendApp(argv, CreateCplexBackend, cb); +} diff --git a/solvers/gurobi/gurobi-lib.c b/solvers/gurobi/gurobi-lib.c index 1ff5af312..872a1744a 100644 --- a/solvers/gurobi/gurobi-lib.c +++ b/solvers/gurobi/gurobi-lib.c @@ -14,7 +14,7 @@ APIEXPORT GRBmodel* AMPLdirectloadmodel( AMPLS_MP_Solver *slv = AMPLSOpenGurobi(slv_opt); if (!slv) return NULL; - int ret = AMPLSLoadNLModel(slv, nl_filename); + AMPLSLoadNLModel(slv, nl_filename); GRBmodel* mdl = GetGRBmodel(slv); *slvout = slv; return mdl; diff --git a/solvers/gurobi/gurobibackend.cc b/solvers/gurobi/gurobibackend.cc index 59872b12b..324c73465 100644 --- a/solvers/gurobi/gurobibackend.cc +++ b/solvers/gurobi/gurobibackend.cc @@ -33,14 +33,14 @@ namespace mp { /// @return GurobiModelMgr std::unique_ptr CreateGurobiModelMgr(GurobiCommon& gc, - Env& e, pre::BasicPresolver*& pPre); + Env& e, pre::BasicValuePresolver*& pPre); GurobiBackend::GurobiBackend() { - pre::BasicPresolver* pPre; + pre::BasicValuePresolver* pPre; auto data = CreateGurobiModelMgr(*this, *this, pPre); SetMM( std::move( data ) ); - SetPresolver(pPre); + SetValuePresolver(pPre); } GurobiBackend::~GurobiBackend() { @@ -82,7 +82,7 @@ void GurobiBackend::OpenGurobi() { // Typically try the registered function first; // if not available call the solver's API function to create // an empty environment. Will be started later. - const auto& create_fn = GetCallbacks().cb_initsolver_; + const auto create_fn = GetCallbacks().init; if (create_fn) set_env((GRBenv*)create_fn()); else @@ -113,12 +113,12 @@ void GurobiBackend::FinishOptionParsing() { else { // If a user defined function had been provided, the environment is assumed // as already started - if (!GetCallbacks().cb_initsolver_) + if (!GetCallbacks().init) { int res = GRBstartenv(env_ref()); if (res) { - const auto& diag = GetCallbacks().cb_diagnostics_; + const auto diag = GetCallbacks().diagnostics; if (diag) diag(); else { @@ -218,7 +218,7 @@ std::vector GurobiBackend::PrimalSolution() { } Solution GurobiBackend::GetSolution() { - auto mv = GetPresolver().PostsolveSolution( + auto mv = GetValuePresolver().PostsolveSolution( { PrimalSolution(), DualSolution() } ); return { mv.GetVarValues()(), mv.GetConValues()(), GetObjectiveValues() }; // TODO postsolve obj values @@ -277,7 +277,7 @@ double GurobiBackend::CurrentGrbPoolObjectiveValue() const { void GurobiBackend::MarkLazyOrUserCuts(ArrayRef lazyVals) { - auto vm = GetPresolver().PresolveLazyUserCutFlags({ + auto vm = GetValuePresolver().PresolveLazyUserCutFlags({ {}, lazyVals }); std::vector lv_lin = vm.GetConValues()(CG_Linear); @@ -305,7 +305,7 @@ SolutionBasis GurobiBackend::GetBasis() { std::vector varstt = VarStatii(); std::vector constt = ConStatii(); if (varstt.size() && constt.size()) { - auto mv = GetPresolver().PostsolveBasis( + auto mv = GetValuePresolver().PostsolveBasis( { std::move(varstt), {{{ CG_Linear, std::move(constt) }}} } ); varstt = mv.GetVarValues()(); @@ -317,7 +317,7 @@ SolutionBasis GurobiBackend::GetBasis() { } void GurobiBackend::SetBasis(SolutionBasis basis) { - auto mv = GetPresolver().PresolveBasis( + auto mv = GetValuePresolver().PresolveBasis( { basis.varstt, basis.constt } ); auto varstt = mv.GetVarValues()(); auto constt = mv.GetConValues()(CG_Linear); @@ -434,7 +434,7 @@ void GurobiBackend::ConStatii(ArrayRef cst) { } void GurobiBackend::AddPrimalDualStart(Solution sol0) { - auto mv = GetPresolver().PresolveSolution( + auto mv = GetValuePresolver().PresolveSolution( { sol0.primal, sol0.dual } ); auto x0 = mv.GetVarValues()(); auto pi0 = mv.GetConValues()(CG_Linear); @@ -501,7 +501,7 @@ ArrayRef GurobiBackend::Ray() { ArrayRef GurobiBackend::DRay() { auto fd = GrbGetDblAttrArray(GRB_DBL_ATTR_FARKASDUAL, NumLinCons()); - auto vm = GetPresolver().PostsolveSolution({ + auto vm = GetValuePresolver().PostsolveSolution({ {}, {{{CG_Linear, std::move(fd)}}} }); @@ -512,7 +512,7 @@ IIS GurobiBackend::GetIIS() { auto variis = VarsIIS(); auto coniis = ConsIIS(); - auto mv = GetPresolver().PostsolveIIS( + auto mv = GetValuePresolver().PostsolveIIS( { variis, coniis } ); return { mv.GetVarValues()(), mv.GetConValues()() }; } @@ -816,7 +816,7 @@ void GurobiBackend::DoGurobiFeasRelax() { feasrelax().flag_orig_obj_available(); } /// Gurobi 9.5 only relaxes linear constraints - auto mv = GetPresolver().PresolveSolution({ + auto mv = GetValuePresolver().PresolveSolution({ {}, feasrelax().rhspen() }); diff --git a/solvers/gurobi/gurobibackend.h b/solvers/gurobi/gurobibackend.h index 6a7f510d5..ab4f3819a 100644 --- a/solvers/gurobi/gurobibackend.h +++ b/solvers/gurobi/gurobibackend.h @@ -20,13 +20,13 @@ #include "gurobicommon.h" #include "mp/backend-mip.h" -#include "mp/presolve-base.h" +#include "mp/valcvt-base.h" namespace mp { class GurobiBackend : public MIPBackend, - public BasicPresolverKeeper, + public BasicValuePresolverKeeper, public GurobiCommon { using BaseBackend = MIPBackend; diff --git a/solvers/gurobi/gurobimodelapi.cc b/solvers/gurobi/gurobimodelapi.cc index 77b0abfc1..b5cb1a5c4 100644 --- a/solvers/gurobi/gurobimodelapi.cc +++ b/solvers/gurobi/gurobimodelapi.cc @@ -8,7 +8,7 @@ namespace mp { /// for recompilation speed std::unique_ptr CreateGurobiModelMgr(GurobiCommon& gc, Env& e, - pre::BasicPresolver*& pPre) { + pre::BasicValuePresolver*& pPre) { return CreateModelMgrWithFlatConverter< GurobiModelAPI, MIPFlatConverter >(gc, e, pPre); } diff --git a/solvers/gurobi/gurobimodelapi.h b/solvers/gurobi/gurobimodelapi.h index e247c5728..9bfae4165 100644 --- a/solvers/gurobi/gurobimodelapi.h +++ b/solvers/gurobi/gurobimodelapi.h @@ -5,7 +5,7 @@ #include "mp/env.h" #include "mp/flat/model_api_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" #include "gurobicommon.h" diff --git a/solvers/gurobi/main.cc b/solvers/gurobi/main.cc index c3ca66d58..056324c3c 100644 --- a/solvers/gurobi/main.cc +++ b/solvers/gurobi/main.cc @@ -7,9 +7,6 @@ extern "C" int main1(int, char **argv) { return mp::RunBackendApp(argv, CreateGurobiBackend); } -extern "C" int main2(int, char** argv, - void* (*init)(), void (*check)(size_t, size_t, size_t), - const char* (*text)(), void(*diag)()) { - mp::BasicBackend::Callbacks callbacks = { init, check, text, diag }; - return mp::RunBackendApp(argv, CreateGurobiBackend, callbacks); +extern "C" int main2(int, char** argv, CCallbacks cb) { + return mp::RunBackendApp(argv, CreateGurobiBackend, cb); } diff --git a/solvers/highsdirect/highsdirectbackend.cc b/solvers/highsdirect/highsdirectbackend.cc index a558b88a7..05c7d0492 100644 --- a/solvers/highsdirect/highsdirectbackend.cc +++ b/solvers/highsdirect/highsdirectbackend.cc @@ -35,16 +35,16 @@ namespace mp { /// need it to convert solution data /// @return HighsModelMgr std::unique_ptr -CreateHighsModelMgr(HighsCommon&, Env&, pre::BasicPresolver*&); +CreateHighsModelMgr(HighsCommon&, Env&, pre::BasicValuePresolver*&); HighsBackend::HighsBackend() { OpenSolver(); - pre::BasicPresolver* pPre; + pre::BasicValuePresolver* pPre; auto data = CreateHighsModelMgr(*this, *this, pPre); SetMM( std::move( data ) ); - SetPresolver(pPre); + SetValuePresolver(pPre); /// Copy env/lp to ModelAPI copy_common_info_to_other(); @@ -72,7 +72,7 @@ bool HighsBackend::IsQCP() const { } Solution HighsBackend::GetSolution() { - auto mv = GetPresolver().PostsolveSolution( + auto mv = GetValuePresolver().PostsolveSolution( { PrimalSolution(), DualSolution() } ); return { mv.GetVarValues()(), mv.GetConValues()(), GetObjectiveValues() }; // TODO postsolve obj values @@ -149,7 +149,7 @@ SolutionBasis HighsBackend::GetBasis() { std::vector varstt = VarStatii(); std::vector constt = ConStatii(); if (varstt.size() && constt.size()) { - auto mv = GetPresolver().PostsolveBasis( + auto mv = GetValuePresolver().PostsolveBasis( { std::move(varstt), {{{ CG_Linear, std::move(constt) }}} }); varstt = mv.GetVarValues()(); @@ -161,7 +161,7 @@ SolutionBasis HighsBackend::GetBasis() { } void HighsBackend::SetBasis(SolutionBasis basis) { - auto mv = GetPresolver().PresolveBasis( + auto mv = GetValuePresolver().PresolveBasis( { basis.varstt, basis.constt }); auto varstt = mv.GetVarValues()(); auto constt = mv.GetConValues()(CG_Linear); diff --git a/solvers/highsdirect/highsdirectbackend.h b/solvers/highsdirect/highsdirectbackend.h index 299faa949..f881b4c87 100644 --- a/solvers/highsdirect/highsdirectbackend.h +++ b/solvers/highsdirect/highsdirectbackend.h @@ -19,14 +19,14 @@ #include #include "mp/backend-mip.h" -#include "mp/presolve-base.h" +#include "mp/valcvt-base.h" #include "highsdirectcommon.h" namespace mp { class HighsBackend : public MIPBackend, - public BasicPresolverKeeper, + public BasicValuePresolverKeeper, public HighsCommon { using BaseBackend = MIPBackend; diff --git a/solvers/highsdirect/highsdirectmodelapi.cc b/solvers/highsdirect/highsdirectmodelapi.cc index 92e62ba53..0586a92e6 100644 --- a/solvers/highsdirect/highsdirectmodelapi.cc +++ b/solvers/highsdirect/highsdirectmodelapi.cc @@ -13,7 +13,7 @@ namespace mp { /// for recompilation speed std::unique_ptr CreateHighsModelMgr(HighsCommon& cc, Env& e, - pre::BasicPresolver*& pPre) { + pre::BasicValuePresolver*& pPre) { return CreateModelMgrWithFlatConverter< HighsModelAPI, MIPFlatConverter >(cc, e, pPre); } @@ -26,7 +26,7 @@ void HighsModelAPI::AddVariables(const VarArrayDef& v) { std::vector costs(v.size(), 0); std::vector lbs(v.size()); std::vector ubs(v.size()); - for (size_t i = 0; i < v.size(); i++) { + for (int i = 0; i < v.size(); i++) { if (var::Type::INTEGER == v.ptype()[i]) intIndices.push_back(i); lbs[i] = std::isinf(v.plb()[i]) ? MinusInfinity() : v.plb()[i]; ubs[i] = std::isinf(v.pub()[i]) ? Infinity() : v.pub()[i]; @@ -64,7 +64,7 @@ void HighsModelAPI::SetQuadraticObjective(int iobj, const QuadraticObjective& qo int currentCol = 0, newCol = 0; startCols[0] = 0; // Convert to Highs Hessian upper triangular format - for (int i = 0; i < qt.size(); i++) + for (size_t i = 0; i < qt.size(); i++) { newCol = qt.vars1()[i]; coeffs[i] = (qt.vars2()[i] == newCol) ? qt.coefs()[i]*2 : qt.coefs()[i]; diff --git a/solvers/highsdirect/highsdirectmodelapi.h b/solvers/highsdirect/highsdirectmodelapi.h index 32e8aa674..b29f0c214 100644 --- a/solvers/highsdirect/highsdirectmodelapi.h +++ b/solvers/highsdirect/highsdirectmodelapi.h @@ -6,7 +6,7 @@ #include "mp/env.h" #include "highsdirectcommon.h" #include "mp/flat/model_api_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/solvers/ortoolsmp/CHANGES.ortoolsmp.md b/solvers/ortoolsmp/CHANGES.ortoolsmp.md new file mode 100644 index 000000000..7e0a10590 --- /dev/null +++ b/solvers/ortoolsmp/CHANGES.ortoolsmp.md @@ -0,0 +1,5 @@ +Summary of recent updates to ORTOOLS for AMPL +============================================= + +### 20220420 +- First release of mock driver \ No newline at end of file diff --git a/solvers/ortoolsmp/README.ortoolsmp.txt b/solvers/ortoolsmp/README.ortoolsmp.txt new file mode 100644 index 000000000..137398179 --- /dev/null +++ b/solvers/ortoolsmp/README.ortoolsmp.txt @@ -0,0 +1,5 @@ +ortools tutorial driver +======================= + +The solver "ortools" is a mock solver, provided as an example - and as a template - +on how to getting started using mp with FlatAPI to develop an mp-based solver interface. \ No newline at end of file diff --git a/solvers/ortoolsmp/main.cc b/solvers/ortoolsmp/main.cc new file mode 100644 index 000000000..291daede8 --- /dev/null +++ b/solvers/ortoolsmp/main.cc @@ -0,0 +1,10 @@ +#include "mp/backend-app.h" +#include "ortoolsmpbackend.h" + +/// Declare a backend factory +std::unique_ptr CreateOrtoolsBackend(); + +int main(int, char** argv) { + return + mp::RunBackendApp(argv, CreateOrtoolsBackend); +} diff --git a/solvers/ortoolsmp/model-mgr-with-std-pb.cc b/solvers/ortoolsmp/model-mgr-with-std-pb.cc new file mode 100644 index 000000000..2ffcce081 --- /dev/null +++ b/solvers/ortoolsmp/model-mgr-with-std-pb.cc @@ -0,0 +1,8 @@ +/** + * Generate ModelManagerWithPB + * + * Having a separate .cc should improve compilation speed + */ + +#include "mp/model-mgr-with-std-pb.hpp" + diff --git a/solvers/ortoolsmp/ortoolsmp-ampls-c-api.h b/solvers/ortoolsmp/ortoolsmp-ampls-c-api.h new file mode 100644 index 000000000..5b2379f3d --- /dev/null +++ b/solvers/ortoolsmp/ortoolsmp-ampls-c-api.h @@ -0,0 +1,29 @@ +#ifndef ORTOOLSAMPLSCAPI_H +#define ORTOOLSAMPLSCAPI_H +/* + * C API for MP/Ortools + */ + +#include "mp/ampls-c-api.h" + +/* + * Below are Ortools-specific AMPLS API functions. + * They complement the 'public' AMPLS API defined in ampls-c-api.h. + */ + +/// Initialize AMPLS ortools. +/// @param slv: pointer to struct AMPLS_MP_Solver to be populated. +/// @param slv_opt: a string of solver options +/// (normally provided in the _options string). +/// Can be NULL. +/// @return 0 on success, otherwise see slv->warnings_and_or_errors_ +int AMPLSOpenOrtools(AMPLS_MP_Solver* slv, const char* slv_opt); + +/// Shut down solver instance +void AMPLSCloseOrtools(AMPLS_MP_Solver* slv); + +/// Extract the Ortools model handle +void* GetOrtoolsmodel(AMPLS_MP_Solver* slv); + + +#endif // ORTOOLSAMPLSCAPI_H diff --git a/solvers/ortoolsmp/ortoolsmp-lib.c b/solvers/ortoolsmp/ortoolsmp-lib.c new file mode 100644 index 000000000..89fd58085 --- /dev/null +++ b/solvers/ortoolsmp/ortoolsmp-lib.c @@ -0,0 +1,27 @@ +#include "ortoolsmp-ampls-c-api.h" + +#ifdef _WIN32 +#define APIEXPORT __declspec(dllexport) +#else +#define APIEXPORT __attribute__((visibility("default"))) +#endif + +APIEXPORT void* AMPLloadmodel(int argc, char** argv, void* slvout) { + const char* nl_filename = argv[1]; + const char *slv_opt= argv[2]; + AMPLS_MP_Solver slv; + int ret = -1; + ret = AMPLSOpenOrtools(&slv, slv_opt); + ret = AMPLSLoadNLModel(&slv, nl_filename); + void* mdl = GetOrtoolsmodel(&slv); + slvout = &slv; + return mdl; +} + +APIEXPORT void AMPLwritesolution(AMPLS_MP_Solver* slv) { + AMPLSReportResults(&slv); +} + +APIEXPORT void AMPLclosesolver(AMPLS_MP_Solver* slv) { + AMPLSCloseOrtools(&slv); +} \ No newline at end of file diff --git a/solvers/ortoolsmp/ortoolsmpbackend.cc b/solvers/ortoolsmp/ortoolsmpbackend.cc new file mode 100644 index 000000000..651ca132d --- /dev/null +++ b/solvers/ortoolsmp/ortoolsmpbackend.cc @@ -0,0 +1,299 @@ +#include +#include +#include + +#include "mp/env.h" +#include "mp/flat/model_api_base.h" +#include "ortoolsmpbackend.h" + +extern "C" { + #include "ortoolsmp-ampls-c-api.h" // Ortools AMPLS C API +} +#include "mp/ampls-cpp-api.h" + +namespace { + + +bool InterruptOrtools(void* prob) { + //return ORTOOLS_Interrupt((ortools_prob*)prob); + return true; +} + +} // namespace {} + +std::unique_ptr CreateOrtoolsBackend() { + return std::unique_ptr{new mp::OrtoolsBackend()}; +} + + +namespace mp { + +/// Create Ortools Model Manager +/// @param gc: the Ortools common handle +/// @param e: environment +/// @param pre: presolver to be returned, +/// need it to convert solution data +/// @return OrtoolsModelMgr +std::unique_ptr +CreateOrtoolsModelMgr(OrtoolsCommon&, Env&, pre::BasicValuePresolver*&); + + +OrtoolsBackend::OrtoolsBackend() { + OpenSolver(); + + /// Create a ModelManager + pre::BasicValuePresolver* pPre; + auto data = CreateOrtoolsModelMgr(*this, *this, pPre); + SetMM( std::move( data ) ); + SetValuePresolver(pPre); + + /// Copy env/lp to ModelAPI + copy_common_info_to_other(); +} + +OrtoolsBackend::~OrtoolsBackend() { + CloseSolver(); +} + +void OrtoolsBackend::OpenSolver() { + int status = 0; + std::string solver = "SCIP"; + auto lp = operations_research::MPSolver::CreateSolver(solver); + if (!lp) + throw std::runtime_error(fmt::format( + "Failed to create solver {}", solver)); + set_lp(lp); // Assign it +} + +void OrtoolsBackend::CloseSolver() { + delete lp(); +} + +const char* OrtoolsBackend::GetBackendName() + { return "OrtoolsBackend"; } + +std::string OrtoolsBackend::GetSolverVersion() { + return lp()->SolverVersion(); +} + + +bool OrtoolsBackend::IsMIP() const { + return lp()->IsMIP(); +} + +bool OrtoolsBackend::IsQCP() const { + return false; +} + +Solution OrtoolsBackend::GetSolution() { + auto mv = GetValuePresolver().PostsolveSolution( + { PrimalSolution(), DualSolution() } ); + return { mv.GetVarValues()(), mv.GetConValues()(), + GetObjectiveValues() }; +} + +ArrayRef OrtoolsBackend::PrimalSolution() { + std::vector x(NumVars()); + for (std::size_t i = 0; i < NumVars(); i++) + x[i] = lp()->variable(i)->solution_value(); + return x; +} + +pre::ValueMapDbl OrtoolsBackend::DualSolution() { + return {{ { CG_Linear, DualSolution_LP() } }}; +} + +ArrayRef OrtoolsBackend::DualSolution_LP() { + int num_cons = NumLinCons(); + std::vector pi(num_cons); + for (std::size_t i = 0; i < num_cons; i++) + pi[i] = lp()->constraint(i)->dual_value(); + return pi; +} + +double OrtoolsBackend::ObjectiveValue() const { + return lp()->Objective().Value(); +} + +double OrtoolsBackend::NodeCount() const { + return 0; +} + +double OrtoolsBackend::SimplexIterations() const { + return 0; +} + +int OrtoolsBackend::BarrierIterations() const { + return 0; +} + +void OrtoolsBackend::ExportModel(const std::string &file) { + // TODO export proper by file extension + //ORTOOLS_CCALL(ORTOOLS_WriteLp(lp(), file.data())); +} + + +void OrtoolsBackend::SetInterrupter(mp::Interrupter *inter) { + inter->SetHandler(InterruptOrtools, lp()); +} + +void OrtoolsBackend::Solve() { + if (!storedOptions_.exportFile_.empty()) { + ExportModel(storedOptions_.exportFile_); + } + status_ = lp()->Solve(); + WindupORTOOLSSolve(); +} + +void OrtoolsBackend::WindupORTOOLSSolve() { } + +void OrtoolsBackend::ReportResults() { + ReportORTOOLSResults(); + BaseBackend::ReportResults(); +} + +void OrtoolsBackend::ReportORTOOLSResults() { + SetStatus( ConvertORTOOLSStatus() ); + AddORTOOLSMessages(); + if (need_multiple_solutions()) + ReportORTOOLSPool(); +} +std::vector OrtoolsBackend::getPoolSolution(int i) +{ + std::vector vars(NumVars()); + // ORTOOLS_CCALL(ORTOOLS_GetPoolSolution(lp(), i, NumVars(), NULL, vars.data())); + return vars; +} +double OrtoolsBackend::getPoolObjective(int i) +{ + double obj; + // ORTOOLS_CCALL(ORTOOLS_GetPoolObjVal(lp(), i, &obj)); + return obj; +} +void OrtoolsBackend::ReportORTOOLSPool() { + if (!IsMIP()) + return; + int iPoolSolution = -1; + int nsolutions; + /* + while (++iPoolSolution < getIntAttr(ORTOOLS_INTATTR_POOLSOLS)) { + ReportIntermediateSolution( + { getPoolSolution(iPoolSolution), + {}, { getPoolObjective(iPoolSolution) } }); + } + */ +} + + +void OrtoolsBackend::AddORTOOLSMessages() { + if (auto ni = SimplexIterations()) + AddToSolverMessage( + fmt::format("{} simplex iterations\n", ni)); + if (auto nbi = BarrierIterations()) + AddToSolverMessage( + fmt::format("{} barrier iterations\n", nbi)); + if (auto nnd = NodeCount()) + AddToSolverMessage( + fmt::format("{} branching nodes\n", nnd)); +} + +std::pair OrtoolsBackend::ConvertORTOOLSStatus() { + namespace sol = mp::sol; + namespace ort = operations_research; + switch (status_) + { + case ort::MPSolver::OPTIMAL: + return { sol::SOLVED, "optimal solution" }; + case ort::MPSolver::FEASIBLE: + return { sol::INTERRUPTED, "interrupted" }; + case ort::MPSolver::INFEASIBLE: + return { sol::INFEASIBLE, "infeasible problem" }; + /// proven unbounded. + case ort::MPSolver::UNBOUNDED: + return { sol::UNBOUNDED, "unbounded problem" }; + case ort::MPSolver::ABNORMAL: + case ort::MPSolver::MODEL_INVALID: + case ort::MPSolver::NOT_SOLVED: + return { sol::FAILURE, "failed" }; + default: + return { sol::UNKNOWN, "not solved" }; + } +} + + +void OrtoolsBackend::FinishOptionParsing() { + int v=-1; + set_verbose_mode(v>0); +} + + +////////////////////////////// OPTIONS ///////////////////////////////// + + +static const mp::OptionValueInfo lp_values_method[] = { + { "-1", "Automatic (default)", -1}, + { "1", "Dual simplex", 1}, + { "2", "Barrier", 2}, + { "3", "Crossover", 3}, + { "4", "Concurrent (simplex and barrier simultaneously)", 4}, +}; + + +static const mp::OptionValueInfo alg_values_level[] = { + { "-1", "Automatic (default)", -1}, + { "0", "Off", 0}, + { "1", "Fast", 1}, + { "2", "Normal", 2}, + { "3", "Aggressive", 3} +}; + +static const mp::OptionValueInfo lp_dualprices_values_[] = { + { "-1", "Choose automatically (default)", -1}, + { "0", "Use Devex pricing algorithm", 0}, + { "1", "Using dual steepest-edge pricing algorithm", 1} +}; + +static const mp::OptionValueInfo lp_barorder_values_[] = { + { "-1", "Choose automatically (default)", -1}, + { "0", "Approximate Minimum Degree (AMD)", 0}, + { "1", "Nested Dissection (ND)", 1} +}; + +void OrtoolsBackend::InitCustomOptions() { + + set_option_header( + "ORTOOLS Optimizer Options for AMPL\n" + "--------------------------------------------\n" + "\n" + "To set these options, assign a string specifying their values to the " + "AMPL option ``ortools_options``. For example::\n" + "\n" + " ampl: option ortools_options 'mipgap=1e-6';\n"); + + AddStoredOption("tech:exportfile writeprob writemodel", + "Specifies the name of a file where to export the model before " + "solving it. This file name can have extension ``.lp()``, ``.mps``, etc. " + "Default = \"\" (don't export the model).", + storedOptions_.exportFile_); + +} + +} // namespace mp + + +// AMPLs + +AMPLS_MP_Solver* AMPLSOpenOrtools( + const char* slv_opt) { + return AMPLS__internal__Open(std::unique_ptr{new mp::OrtoolsBackend()}, + slv_opt); +} + +void AMPLSCloseOrtools(AMPLS_MP_Solver* slv) { + AMPLS__internal__Close(slv); +} + +void* GetOrtoolsmodel(AMPLS_MP_Solver* slv) { + return + dynamic_cast(AMPLSGetBackend(slv))->lp(); +} diff --git a/solvers/ortoolsmp/ortoolsmpbackend.h b/solvers/ortoolsmp/ortoolsmpbackend.h new file mode 100644 index 000000000..a86ead954 --- /dev/null +++ b/solvers/ortoolsmp/ortoolsmpbackend.h @@ -0,0 +1,131 @@ +#ifndef MP_ORTOOLS_BACKEND_H_ +#define MP_ORTOOLS_BACKEND_H_ + +#if __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-parameter" +# pragma clang diagnostic ignored "-Wunused-private-field" +#elif _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4244) +#endif + +#if __clang__ +# pragma clang diagnostic pop +#elif _MSC_VER +# pragma warning(pop) +#endif + +#include + +#include "mp/backend-mip.h" +#include "mp/valcvt-base.h" +#include "ortoolsmpcommon.h" + +namespace mp { + +class OrtoolsBackend : + public MIPBackend, + public BasicValuePresolverKeeper, + public OrtoolsCommon +{ + using BaseBackend = MIPBackend; + + + //////////////////// [[ The public interface ]] ////////////////////// +public: + OrtoolsBackend(); + ~OrtoolsBackend(); + + /// Name displayed in messages + static const char* GetSolverName() { return "ortools"; } + std::string GetSolverVersion(); + + static const char* GetAMPLSolverName() { return "ortools"; } + static const char* GetAMPLSolverLongName() { return "AMPL-ortools"; } + static const char* GetBackendName(); + static const char* GetBackendLongName() { return nullptr; } + + /// Chance for the Backend to init solver environment, etc + void InitOptionParsing() override { } + /// Chance to consider options immediately (open cloud, etc) + void FinishOptionParsing() override; + + + + //////////////////////////////////////////////////////////// + /////////////// OPTIONAL STANDARD FEATURES ///////////////// + //////////////////////////////////////////////////////////// + // Use this section to declare and implement some standard features + // that may or may not need additional functions. + USING_STD_FEATURES; + + /////////////////////////// Model attributes ///////////////////////// + bool IsMIP() const override; + bool IsQCP() const override; + + //////////////////////////// SOLVING /////////////////////////////// + + /// Note the interrupt notifier + void SetInterrupter(mp::Interrupter* inter) override; + + /// Solve, no model modification any more. + /// Can report intermediate results via HandleFeasibleSolution() during this, + /// otherwise in ReportResults() + void Solve() override; + + Solution GetSolution() override; + ArrayRef GetObjectiveValues() override + { return std::vector{ObjectiveValue()}; } + + + //////////////////// [[ Implementation details ]] ////////////////////// + /////////////////////////////////////////////////////////////////////////////// +public: // public for static polymorphism + void InitCustomOptions() override; + +protected: + void OpenSolver(); + void CloseSolver(); + + void ExportModel(const std::string& file); + + double ObjectiveValue() const; + + /// Solution values. The vectors are emptied if not available + ArrayRef PrimalSolution(); + pre::ValueMapDbl DualSolution(); + ArrayRef DualSolution_LP(); + + void WindupORTOOLSSolve(); + + void ReportResults() override; + void ReportORTOOLSResults(); + void ReportORTOOLSPool(); + + std::vector getPoolSolution(int i); + double getPoolObjective(int i); + + /// Solution attributes + double NodeCount() const; + double SimplexIterations() const; + int BarrierIterations() const; + + std::pair ConvertORTOOLSStatus(); + void AddORTOOLSMessages(); + + +private: + /// These options are stored in the class + struct Options { + std::string exportFile_; + }; + Options storedOptions_; + + operations_research::MPSolver::ResultStatus status_; + +}; + +} // namespace mp + +#endif // MP_ORTOOLS_BACKEND_H_ diff --git a/solvers/ortoolsmp/ortoolsmpcommon.cc b/solvers/ortoolsmp/ortoolsmpcommon.cc new file mode 100644 index 000000000..ef9862198 --- /dev/null +++ b/solvers/ortoolsmp/ortoolsmpcommon.cc @@ -0,0 +1,70 @@ +#include "mp/format.h" +#include "ortoolsmpcommon.h" + +namespace mp { + +int OrtoolsCommon::getIntAttr(int name) const { + int value = 0; + /* TODO Utility function to get the value of an integer attribute + * from the solver API + ORTOOLS_CCALL(ORTOOLS_GetIntAttr(lp_, name, &value)); */ + return value; +} +double OrtoolsCommon::getDblAttr(const char* name) const { + double value = 0; + /* TODO Utility function to get the value of an integer attribute + * from the solver API + ORTOOLS_CCALL(ORTOOLS_GetDblAttr(lp_, name, &value)); */ + return value; +} + +int OrtoolsCommon::NumLinCons() const { + return lp()->NumConstraints(); +} + +int OrtoolsCommon::NumVars() const { + return lp()->NumVariables(); +} + +int OrtoolsCommon::NumObjs() const { + return 1; +} + +int OrtoolsCommon::NumQPCons() const { + return 0; +} + +int OrtoolsCommon::NumSOSCons() const { + return 0; +} + +int OrtoolsCommon::NumIndicatorCons() const { + return 0; +} + +void OrtoolsCommon::GetSolverOption(const char* key, int &value) const { + //ORTOOLS_CCALL( ORTOOLS_GetIntParam(lp_, key, &value) ); +} + +void OrtoolsCommon::SetSolverOption(const char* key, int value) { + //ORTOOLS_CCALL(ORTOOLS_SetIntParam(lp_, key, value)); +} + +void OrtoolsCommon::GetSolverOption(const char* key, double &value) const { + //ORTOOLS_CCALL(ORTOOLS_GetDblParam(lp_, key, &value) ); +} + +void OrtoolsCommon::SetSolverOption(const char* key, double value) { + // ORTOOLS_CCALL(ORTOOLS_SetDblParam(lp_, key, value) ); +} + +void OrtoolsCommon::GetSolverOption(const char* key, std::string &value) const { + throw std::runtime_error("Not implemented"); // TODO +} + +void OrtoolsCommon::SetSolverOption(const char* key, const std::string& value) { + throw std::runtime_error("Not implemented"); // TODO +} + + +} // namespace mp diff --git a/solvers/ortoolsmp/ortoolsmpcommon.h b/solvers/ortoolsmp/ortoolsmpcommon.h new file mode 100644 index 000000000..25d242f65 --- /dev/null +++ b/solvers/ortoolsmp/ortoolsmpcommon.h @@ -0,0 +1,72 @@ +#ifndef ORTOOLSCOMMON_H +#define ORTOOLSCOMMON_H + +#include +#include + +#include "mp/backend-to-model-api.h" + +#include "ortools/linear_solver/linear_solver.h" + + +/// The below would go into actual ...common.h: + +#include "mp/format.h" + +namespace mp { +/// Information shared by both +/// `OrtoolsBackend` and `OrtoolsModelAPI` +struct OrtoolsCommonInfo { + operations_research::MPSolver* lp() const { return lp_; } + void set_lp(operations_research::MPSolver* lp) { lp_ = lp; } +private: + operations_research::MPSolver* lp_ = NULL; +}; + + +/// Common API for Ortools classes +class OrtoolsCommon : + public Backend2ModelAPIConnector { +public: + /// These methods access Ortools options. Used by AddSolverOption() + void GetSolverOption(const char* key, int& value) const; + void SetSolverOption(const char* key, int value); + void GetSolverOption(const char* key, double& value) const; + void SetSolverOption(const char* key, double value); + void GetSolverOption(const char* key, std::string& value) const; + void SetSolverOption(const char* key, const std::string& value); + + // TODO Typically solvers define their own infinity; use them here + static constexpr double Infinity() { return std::numeric_limits::infinity(); } + static constexpr double MinusInfinity() { return -std::numeric_limits::infinity(); } + +protected: + int getIntAttr(int name) const; + double getDblAttr(const char* name) const; + + int NumLinCons() const; + int NumVars() const; + int NumObjs() const; + int NumQPCons() const; + int NumSOSCons() const; + int NumIndicatorCons() const; + +protected: + // TODO if desirable, provide function to create the solver's environment + //int (*createEnv) (solver_env**) = nullptr; + +}; + + +/// Convenience macro +// TODO This macro is useful to automatically throw an error if a function in the +// solver API does not return a valid errorcode. In this mock driver, we define it +// ourselves, normally this constant would be defined in the solver's API. +#define ORTOOLS_RETCODE_OK 0 +#define ORTOOLS_CCALL( call ) do { if (int e = (call) != ORTOOLS_RETCODE_OK) \ + throw std::runtime_error( \ + fmt::format(" Call failed: '{}' with code {}", #call, e )); } while (0) + +} // namespace mp + +#endif // ORTOOLSCOMMON_H diff --git a/solvers/ortoolsmp/ortoolsmpmodelapi.cc b/solvers/ortoolsmp/ortoolsmpmodelapi.cc new file mode 100644 index 000000000..d5ab23c2f --- /dev/null +++ b/solvers/ortoolsmp/ortoolsmpmodelapi.cc @@ -0,0 +1,77 @@ +#include "ortoolsmpmodelapi.h" + +#include "mp/model-mgr-with-std-pb.h" +#include "mp/flat/problem_flattener.h" +#include "mp/flat/redef/MIP/converter_mip.h" +#include "mp/flat/model_api_connect.h" + +namespace mp { + +/// Defining the function in ...modelapi.cc +/// for recompilation speed +std::unique_ptr +CreateOrtoolsModelMgr(OrtoolsCommon& cc, Env& e, + pre::BasicValuePresolver*& pPre) { + return CreateModelMgrWithFlatConverter< + OrtoolsModelAPI, MIPFlatConverter >(cc, e, pPre); +} + + +void OrtoolsModelAPI::InitProblemModificationPhase() { } + +void OrtoolsModelAPI::AddVariables(const VarArrayDef& v) { + for (size_t i = 0; i < v.size(); ++i) { + lp()->MakeVar(v.plb()[i], v.pub()[i], + v.ptype()[i] == var::Type::INTEGER, ""); + } +} + +void OrtoolsModelAPI::SetLinearObjective( int iobj, const LinearObjective& lo ) { + if (iobj<1) { + operations_research::MPObjective* const objective = lp()->MutableObjective(); + for (int j = 0; j < lo.num_terms(); ++j) { + objective->SetCoefficient(lp()->variable(lo.vars()[j]), lo.coefs()[j]); + } + if (lo.obj_sense() == obj::Type::MAX) + objective->SetMaximization(); + else + objective->SetMinimization(); + } else { + throw std::runtime_error("Multiple objectives not supported"); + } +} + + +void OrtoolsModelAPI::SetQuadraticObjective(int iobj, const QuadraticObjective& qo) { + throw std::runtime_error("Quadratic objective not supported"); +} + +void OrtoolsModelAPI::AddConstraint(const LinConRange& lc) { + auto c = lp()->MakeRowConstraint(lc.lb(), lc.ub()); + for (size_t i = 0; i < lc.size(); i++) + c->SetCoefficient(lp()->variable(lc.var(i)), lc.coef(i)); +} + +void OrtoolsModelAPI::AddConstraint(const LinConLE& lc) { + auto c = lp()->MakeRowConstraint(lc.lb(), lc.ub()); + for (size_t i = 0; i < lc.size(); i++) + c->SetCoefficient(lp()->variable(lc.var(i)), lc.coef(i)); +} +void OrtoolsModelAPI::AddConstraint(const LinConEQ& lc) { + auto c = lp()->MakeRowConstraint(lc.lb(), lc.ub()); + for (size_t i = 0; i < lc.size(); i++) + c->SetCoefficient(lp()->variable(lc.var(i)), lc.coef(i)); +} +void OrtoolsModelAPI::AddConstraint(const LinConGE& lc) { + auto c = lp()->MakeRowConstraint(lc.lb(), lc.ub()); + for (size_t i = 0; i < lc.size(); i++) + c->SetCoefficient(lp()->variable(lc.var(i)), lc.coef(i)); +} + + + +void OrtoolsModelAPI::FinishProblemModificationPhase() { +} + + +} // namespace mp diff --git a/solvers/ortoolsmp/ortoolsmpmodelapi.h b/solvers/ortoolsmp/ortoolsmpmodelapi.h new file mode 100644 index 000000000..c53d59d81 --- /dev/null +++ b/solvers/ortoolsmp/ortoolsmpmodelapi.h @@ -0,0 +1,71 @@ +#ifndef ORTOOLSMODELAPI_H +#define ORTOOLSMODELAPI_H + +#include + +#include "mp/env.h" +#include "ortoolsmpcommon.h" +#include "mp/flat/model_api_base.h" +#include "mp/flat/constr_std.h" + +namespace mp { + +class OrtoolsModelAPI : + public OrtoolsCommon, public EnvKeeper, + public BasicFlatModelAPI +{ + using BaseModelAPI = BasicFlatModelAPI; + +public: + /// Construct + OrtoolsModelAPI(Env& e) : EnvKeeper(e) { } + + /// Class name + static const char* GetTypeName() { return "OrtoolsModelAPI"; } + + /// Called before problem input + void InitProblemModificationPhase(); + /// After + void FinishProblemModificationPhase(); + + /// TODO Implement the following functions using the solver's API + void AddVariables(const VarArrayDef& ); + void SetLinearObjective( int iobj, const LinearObjective& lo ); + void SetQuadraticObjective(int iobj, const QuadraticObjective& qo); + + //////////////////////////// GENERAL CONSTRAINTS //////////////////////////// + USE_BASE_CONSTRAINT_HANDLERS(BaseModelAPI) + + /// TODO For each suppoted constraint type, add the ACCEPT_CONSTRAINT macro + /// and the relative AddConstraint function. + /// Below some typical constraint handlers of a MIP solver. + /// Further constraint types which could be handled natively by some solvers: + /// - IndicatorConstraint(Lin/Quad)(LE/EQ/GE) + /// - Multidirectional indicators Cond(Lin/Quad)Con(LT/LE/EQ/GE/GT), where + /// the implication direction () depends in the context + /// - Complementarity + /// - Logical, counting, piecewise-linear constraints. + /// See \a constraints_std.h and other drivers. + + + /// The linear range constraint, if fully supported with basis info etc. + ACCEPT_CONSTRAINT(LinConRange, Recommended, CG_Linear) + void AddConstraint(const LinConRange& lc); + + /// LinCon(LE/EQ/GE) should have 'Recommended' for all backends + /// and have an implementation, + /// or a conversion rule is needed in a derived FlatConverter + ACCEPT_CONSTRAINT(LinConLE, Recommended, CG_Linear) + void AddConstraint(const LinConLE& lc); + ACCEPT_CONSTRAINT(LinConEQ, Recommended, CG_Linear) + void AddConstraint(const LinConEQ& lc); + ACCEPT_CONSTRAINT(LinConGE, Recommended, CG_Linear) + void AddConstraint(const LinConGE& lc); + + + +}; + +} // namespace mp + +#endif // ORTOOLSMODELAPI_H diff --git a/solvers/visitor/visitorbackend.cc b/solvers/visitor/visitorbackend.cc index dbbb194cb..33ef1f9b0 100644 --- a/solvers/visitor/visitorbackend.cc +++ b/solvers/visitor/visitorbackend.cc @@ -35,17 +35,17 @@ namespace mp { /// need it to convert solution data /// @return VisitorModelMgr std::unique_ptr -CreateVisitorModelMgr(VisitorCommon&, Env&, pre::BasicPresolver*&); +CreateVisitorModelMgr(VisitorCommon&, Env&, pre::BasicValuePresolver*&); VisitorBackend::VisitorBackend() { OpenSolver(); /// Create a ModelManager - pre::BasicPresolver* pPre; + pre::BasicValuePresolver* pPre; auto data = CreateVisitorModelMgr(*this, *this, pPre); SetMM( std::move( data ) ); - SetPresolver(pPre); + SetValuePresolver(pPre); /// Copy env/lp to ModelAPI copy_common_info_to_other(); @@ -129,7 +129,7 @@ bool VisitorBackend::IsQCP() const { } Solution VisitorBackend::GetSolution() { - auto mv = GetPresolver().PostsolveSolution( + auto mv = GetValuePresolver().PostsolveSolution( { PrimalSolution(), DualSolution() } ); return { mv.GetVarValues()(), mv.GetConValues()(), GetObjectiveValues() }; // TODO postsolve obj values @@ -511,7 +511,7 @@ SolutionBasis VisitorBackend::GetBasis() { std::vector varstt = VarStatii(); std::vector constt = ConStatii(); if (varstt.size() && constt.size()) { - auto mv = GetPresolver().PostsolveBasis( + auto mv = GetValuePresolver().PostsolveBasis( { std::move(varstt), {{{ CG_Linear, std::move(constt) }}} }); varstt = mv.GetVarValues()(); @@ -523,7 +523,7 @@ SolutionBasis VisitorBackend::GetBasis() { } void VisitorBackend::SetBasis(SolutionBasis basis) { - auto mv = GetPresolver().PresolveBasis( + auto mv = GetValuePresolver().PresolveBasis( { basis.varstt, basis.constt }); auto varstt = mv.GetVarValues()(); auto constt = mv.GetConValues()(CG_Linear); @@ -543,7 +543,7 @@ IIS VisitorBackend::GetIIS() { auto variis = VarsIIS(); auto coniis = ConsIIS(); // TODO: This can be moved to a parent class? - auto mv = GetPresolver().PostsolveIIS( + auto mv = GetValuePresolver().PostsolveIIS( { variis, coniis }); return { mv.GetVarValues()(), mv.GetConValues()() }; } diff --git a/solvers/visitor/visitorbackend.h b/solvers/visitor/visitorbackend.h index 16c08ab74..fec699b46 100644 --- a/solvers/visitor/visitorbackend.h +++ b/solvers/visitor/visitorbackend.h @@ -19,14 +19,14 @@ #include #include "mp/backend-mip.h" -#include "mp/presolve-base.h" +#include "mp/valcvt-base.h" #include "visitorcommon.h" namespace mp { class VisitorBackend : public MIPBackend, - public BasicPresolverKeeper, + public BasicValuePresolverKeeper, public VisitorCommon { using BaseBackend = MIPBackend; diff --git a/solvers/visitor/visitormodelapi.cc b/solvers/visitor/visitormodelapi.cc index d5a0791f8..a0b78e9ba 100644 --- a/solvers/visitor/visitormodelapi.cc +++ b/solvers/visitor/visitormodelapi.cc @@ -11,7 +11,7 @@ namespace mp { /// for recompilation speed std::unique_ptr CreateVisitorModelMgr(VisitorCommon& cc, Env& e, - pre::BasicPresolver*& pPre) { + pre::BasicValuePresolver*& pPre) { return CreateModelMgrWithFlatConverter< VisitorModelAPI, MIPFlatConverter >(cc, e, pPre); } diff --git a/solvers/visitor/visitormodelapi.h b/solvers/visitor/visitormodelapi.h index a2f7f15e2..3653a2507 100644 --- a/solvers/visitor/visitormodelapi.h +++ b/solvers/visitor/visitormodelapi.h @@ -6,7 +6,7 @@ #include "mp/env.h" #include "visitorcommon.h" #include "mp/flat/model_api_base.h" -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" namespace mp { diff --git a/src/mp/flat/piecewise_linear.cpp b/src/mp/flat/piecewise_linear.cpp index 7ba130b27..f4ddb11d1 100644 --- a/src/mp/flat/piecewise_linear.cpp +++ b/src/mp/flat/piecewise_linear.cpp @@ -20,7 +20,7 @@ Author: Gleb Belov */ -#include "mp/flat/constraints_std.h" +#include "mp/flat/constr_std.h" mp::PLPoints::PLPoints(const PLSlopes &pls) { constexpr auto eps = 1.0; // works? diff --git a/src/solver.cc b/src/solver.cc index 4c07ef15f..14fb42464 100644 --- a/src/solver.cc +++ b/src/solver.cc @@ -1028,7 +1028,7 @@ typedef struct AMPLS_MP__internal_T { AMPLS_MP_Solver* AMPLS__internal__Open(std::unique_ptr p_be, const char* slv_opt) { AMPLS_MP_Solver* slv = new AMPLS_MP_Solver(); - int ret = AMPLS__internal__TryCatchWrapper( slv, [&]() { + AMPLS__internal__TryCatchWrapper( slv, [&]() { auto ii = new AMPLS_MP__internal(); slv->internal_info_ = ii; ii->p_be_ = std::move(p_be); @@ -1050,10 +1050,7 @@ AMPLS_MP_Solver* AMPLS__internal__Open(std::unique_ptr p_be, } ); return slv; } -/** Deallocate the mp-related info and the structure itself. -* Before calling this function, a solver-specific implementation should -* delete solver_info_ and user_info_ if allocated. -*/ + void AMPLS__internal__Close(AMPLS_MP_Solver* slv) { assert(slv->internal_info_); delete (AMPLS_MP__internal*)slv->internal_info_;