diff --git a/CMakeLists.txt b/CMakeLists.txt index 577049484..30f7af961 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 - valcvt-base.h valcvt-node.h valcvt-link.h valcvt.h + presolve-base.h presolve-node.h presolve-bridge.h presolve.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/ - constr_base.h constr_keeper.h constr_hash.h - constr_std.h constr_static.h constr_functional.h - constr_algebraic.h constr_general.h + constraint_base.h constraint_keeper.h constraint_hash.h + constraints_std.h constraints_static.h constraints_functional.h + constraints_algebraic.h constraints_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 f6b67ecc5..ef7804bf9 100644 --- a/doc/rst/components.rst +++ b/doc/rst/components.rst @@ -156,20 +156,8 @@ 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. - -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. +for model and solution I/O. See the classes' documentation +for details. .. _solver-classes: @@ -260,19 +248,6 @@ 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. @@ -283,7 +258,7 @@ via the solver's modeling API wrapper: Value Presolver ~~~~~~~~~~~~~~~ -Class `mp::pre::ValuePresolver` manages transformations of solutions and suffixes +Class `mp::pre::Presolver` 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 0b61bc03e..bfe9d8fa8 100644 --- a/doc/rst/details.rst +++ b/doc/rst/details.rst @@ -17,13 +17,6 @@ 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 178ab4501..0b87360d7 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 constraints and non-contiguous variable domains -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +SOS 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,11 +218,8 @@ 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 .sos(no) and .(sos)ref, +explicitly using AMPL suffixes .sosno and .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 @@ -246,8 +243,6 @@ 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 a8ad3f54f..273b42c74 100644 --- a/include/mp/ampls-c-api.h +++ b/include/mp/ampls-c-api.h @@ -1,14 +1,9 @@ #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 @@ -50,18 +45,4 @@ 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 eaaa7807c..dc3473a70 100644 --- a/include/mp/ampls-cpp-api.h +++ b/include/mp/ampls-cpp-api.h @@ -28,9 +28,6 @@ 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 01f5cd817..95d8b774a 100644 --- a/include/mp/backend-base.h +++ b/include/mp/backend-base.h @@ -2,10 +2,7 @@ #define BACKEND_BASE_H #include - -extern "C" { - #include "mp/ampls-c-api.h" // for CCallbacks -} +#include #include "mp/solver-base.h" @@ -79,13 +76,26 @@ class BasicBackend : public BasicSolver { /// Chance to consider options immediately (open cloud, etc) virtual void FinishOptionParsing() { } - /// Callbacks typedef - using Callbacks = CCallbacks; + /// 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_; + }; /// Obtain callbacks Callbacks& GetCallbacks() { return callbacks_; } - private: Callbacks callbacks_; }; diff --git a/include/mp/backend-mip.h b/include/mp/backend-mip.h index a1437b04a..17a361670 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 (returns unpresolved basis) + /// Getter (unpresolved) virtual SolutionBasis GetBasis() { return {}; } - /// Setter (takes unpresolved basis) + /// Setter (unpresolved) virtual void SetBasis(SolutionBasis ) { MP_UNSUPPORTED("MIPBackend::SetBasis"); } /** diff --git a/include/mp/backend.h b/include/mp/backend.h index 222337125..872017676 100644 --- a/include/mp/backend.h +++ b/include/mp/backend.h @@ -57,7 +57,7 @@ DEFAULT_STD_FEATURES_TO( false ) namespace mp { -/// Solution (normally unpresolved) +/// Basis status values of a solution (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().check); + GetCallbacks().cb_checkmodel_); } /// 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().additionalText; + auto lic_cb = GetCallbacks().cb_license_text_; if (lic_cb) this->set_license_info(lic_cb()); } diff --git a/include/mp/flat/constr_base.h b/include/mp/flat/constraint_base.h similarity index 100% rename from include/mp/flat/constr_base.h rename to include/mp/flat/constraint_base.h diff --git a/include/mp/flat/constr_hash.h b/include/mp/flat/constraint_hash.h similarity index 99% rename from include/mp/flat/constr_hash.h rename to include/mp/flat/constraint_hash.h index f32fff9eb..f12e93f13 100644 --- a/include/mp/flat/constr_hash.h +++ b/include/mp/flat/constraint_hash.h @@ -8,7 +8,7 @@ #include #include "mp/utils-hash-stream.h" -#include "mp/flat/constr_std.h" +#include "mp/flat/constraints_std.h" #include "mp/flat/expr_affine.h" namespace std { diff --git a/include/mp/flat/constr_keeper.h b/include/mp/flat/constraint_keeper.h similarity index 98% rename from include/mp/flat/constr_keeper.h rename to include/mp/flat/constraint_keeper.h index 74332cac8..d9eca33f0 100644 --- a/include/mp/flat/constr_keeper.h +++ b/include/mp/flat/constraint_keeper.h @@ -9,9 +9,9 @@ #include "mp/common.h" #include "mp/flat/model_api_base.h" -#include "mp/flat/constr_hash.h" +#include "mp/flat/constraint_hash.h" #include "mp/flat/redef/redef_base.h" -#include "mp/valcvt-node.h" +#include "mp/presolve-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().GetCopyLink(). + GetConverter().GetCopyBridge(). AddEntry({ GetValueNode().Select(con_index), - GetConverter().GetValuePresolver().GetTargetNodes(). + GetConverter().GetPresolver().GetTargetNodes(). GetConValues()(con_group).Add() }); } diff --git a/include/mp/flat/constr_algebraic.h b/include/mp/flat/constraints_algebraic.h similarity index 99% rename from include/mp/flat/constr_algebraic.h rename to include/mp/flat/constraints_algebraic.h index b41ed399f..1d403cfae 100644 --- a/include/mp/flat/constr_algebraic.h +++ b/include/mp/flat/constraints_algebraic.h @@ -8,7 +8,7 @@ #include #include -#include "mp/flat/constr_base.h" +#include "mp/flat/constraint_base.h" #include "mp/flat/expr_quadratic.h" diff --git a/include/mp/flat/constr_functional.h b/include/mp/flat/constraints_functional.h similarity index 99% rename from include/mp/flat/constr_functional.h rename to include/mp/flat/constraints_functional.h index 4b7186847..b2786375c 100644 --- a/include/mp/flat/constr_functional.h +++ b/include/mp/flat/constraints_functional.h @@ -5,7 +5,7 @@ * Functional flat constraints */ -#include "mp/flat/constr_static.h" +#include "mp/flat/constraints_static.h" namespace mp { diff --git a/include/mp/flat/constr_general.h b/include/mp/flat/constraints_general.h similarity index 98% rename from include/mp/flat/constr_general.h rename to include/mp/flat/constraints_general.h index 18fa40549..732254097 100644 --- a/include/mp/flat/constr_general.h +++ b/include/mp/flat/constraints_general.h @@ -8,7 +8,7 @@ #include #include -#include "mp/flat/constr_algebraic.h" +#include "mp/flat/constraints_algebraic.h" namespace mp { diff --git a/include/mp/flat/constr_static.h b/include/mp/flat/constraints_static.h similarity index 63% rename from include/mp/flat/constr_static.h rename to include/mp/flat/constraints_static.h index 4e4780ced..fc639fd66 100644 --- a/include/mp/flat/constr_static.h +++ b/include/mp/flat/constraints_static.h @@ -5,7 +5,7 @@ * Static (non-functional) flat constraints */ -#include "mp/flat/constr_algebraic.h" -#include "mp/flat/constr_general.h" +#include "mp/flat/constraints_algebraic.h" +#include "mp/flat/constraints_general.h" #endif // CONSTRAINTS_STATIC_H diff --git a/include/mp/flat/constr_std.h b/include/mp/flat/constraints_std.h similarity index 63% rename from include/mp/flat/constr_std.h rename to include/mp/flat/constraints_std.h index 50ab5b54c..726affdca 100644 --- a/include/mp/flat/constr_std.h +++ b/include/mp/flat/constraints_std.h @@ -6,7 +6,7 @@ * flat constraints */ -#include "mp/flat/constr_static.h" -#include "mp/flat/constr_functional.h" +#include "mp/flat/constraints_static.h" +#include "mp/flat/constraints_functional.h" #endif // STD_CONSTR_H diff --git a/include/mp/flat/converter.h b/include/mp/flat/converter.h index b97708f5c..fd9b481b9 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/constr_keeper.h" -#include "mp/flat/constr_std.h" -#include "mp/valcvt.h" +#include "mp/flat/constraint_keeper.h" +#include "mp/flat/constraints_std.h" +#include "mp/presolve.h" #include "mp/flat/redef/std/range_con.h" namespace mp { @@ -881,7 +881,7 @@ class FlatConverter : void FinishModelInput() { MPD( ConvertModel() ); - if (relax()) // TODO value presolve link? + if (relax()) // TODO bridge? GetModel().RelaxIntegrality(); GetModel().PushModelTo(GetModelAPI()); } @@ -909,9 +909,9 @@ class FlatConverter : const ModelAPI& GetModelAPI() const { return modelapi_; } ModelAPI& GetModelAPI() { return modelapi_; } - /// Expose ValuePresolver - const pre::ValuePresolver& GetValuePresolver() const { return value_presolver_; } - pre::ValuePresolver& GetValuePresolver() { return value_presolver_; } + /// Expose Presolver + const pre::Presolver& GetPresolver() const { return presolver_; } + pre::Presolver& GetPresolver() { return 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 GetValuePresolver().GetTargetNodes().GetVarValues().MakeSingleKey(); } + { return GetPresolver().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 most presolve in the flat converter.", + "0/1*: Set to 0 to disable all 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::ValuePresolver value_presolver_; - pre::CopyLink copy_link_ { GetValuePresolver() }; + pre::Presolver presolver_; + pre::CopyBridge copy_bridge_ { GetPresolver() }; protected: @@ -1232,8 +1232,8 @@ class FlatConverter : INSTALL_ITEM_CONVERTER(RangeQuadraticConstraintConverter) public: - /// Presolve link copying values between model items - pre::CopyLink& GetCopyLink() { return copy_link_; } + /// Presolve bridge copying values between model items + pre::CopyBridge& GetCopyBridge() { return copy_bridge_; } }; diff --git a/include/mp/flat/converter_model.h b/include/mp/flat/converter_model.h index d2fbf7416..4ed9ba3ac 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/constr_std.h" -#include "mp/flat/constr_keeper.h" +#include "mp/flat/constraints_std.h" +#include "mp/flat/constraint_keeper.h" namespace mp { diff --git a/include/mp/flat/model_api_base.h b/include/mp/flat/model_api_base.h index dd2a29895..d1ad83e8e 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/constr_base.h" +#include "mp/flat/constraint_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 36a0f3edd..878b02efb 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::BasicValuePresolver*& pPre) { + pre::BasicPresolver*& 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().GetValuePresolver(); + pPre = &pcvt->GetFlatCvt().GetPresolver(); return res; } diff --git a/include/mp/flat/problem_flattener.h b/include/mp/flat/problem_flattener.h index 737d4f855..8a05c6da9 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/constr_std.h" +#include "mp/flat/constraints_std.h" #include "mp/flat/obj_std.h" -#include "mp/valcvt.h" +#include "mp/presolve.h" namespace mp { @@ -109,7 +109,6 @@ class ProblemFlattener : } protected: - /// Convert problem items void ConvertStandardItems() { ////////////////////////// Variables ConvertVars(); @@ -150,18 +149,16 @@ class ProblemFlattener : types[i] = mpvar.type(); } auto vnr = GetFlatCvt().AddVars(lbs, ubs, types); - GetCopyLink().AddEntry({ - GetValuePresolver().GetSourceNodes().GetVarValues().MakeSingleKey(). + GetCopyBridge().AddEntry({ + GetPresolver().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(); @@ -190,11 +187,10 @@ class ProblemFlattener : std::move(eexpr.GetQPTerms())}); } - /// Convert an algebraic constraint void ConvertAlgCon(int i) { auto pr = PrepareAlgConstraint(i); auto nr = AddAlgebraicConstraint(pr); - AddCopyLinkFromSource(nr); + AddCopyBridgeFromSource(nr); } /// Preparation info @@ -239,7 +235,7 @@ class ProblemFlattener : /// Add algebraic constraint to FlatCvt pre::NodeRange AddAlgebraicConstraint(const AlgConPrepare& pr) { - pre::NodeRange nr; // value presolve link + pre::NodeRange nr; // presolve bridge if (pr.qt.empty()) { if (pr.compl_var<0) nr = AddConstraint( LinConRange{ std::move(pr.lt), @@ -263,15 +259,13 @@ class ProblemFlattener : return nr; } - /// Add a copy link from a source item - void AddCopyLinkFromSource(pre::NodeRange nr) { - GetCopyLink().AddEntry( { - GetValuePresolver().GetSourceNodes().GetConValues()(0).Add(), + void AddCopyBridgeFromSource(pre::NodeRange nr) { + GetCopyBridge().AddEntry( { + GetPresolver().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()) ); @@ -279,7 +273,7 @@ class ProblemFlattener : assert(GetFlatCvt().HasInitExpression(resvar)); const auto& ie = GetFlatCvt().GetInitExpression(resvar); /// TODO check that logical cons' values come after algebraic ones - AddCopyLinkFromSource( + AddCopyBridgeFromSource( ie.GetCK()->GetValueNode().Select( ie.GetIndex() )); } @@ -633,7 +627,7 @@ class ProblemFlattener : return VisitFunctionalExpression({ e.arg() }); } - /// TODO how to link them if they are no real items in NL? + /// TODO how to bridge them if they are no real items in NL? void ConvertSOSConstraints() { if (sos()) { auto sosno = GetModel(). @@ -743,8 +737,7 @@ class ProblemFlattener : //////////////////////////// UTILITIES ///////////////////////////////// /// protected: - pre::ValuePresolver& GetValuePresolver() - { return GetFlatCvt().GetValuePresolver(); } + pre::Presolver& GetPresolver() { return GetFlatCvt().GetPresolver(); } private: std::unordered_map map_fixed_vars_; @@ -757,8 +750,8 @@ class ProblemFlattener : int MakeFixedVar(double value) // TODO use proper const term in obj { return GetFlatCvt().MakeFixedVar(value); } - /// Presolve link just copying values between model items - pre::CopyLink& GetCopyLink() { return GetFlatCvt().GetCopyLink(); } + /// Presolve bridge copying values between model items + pre::CopyBridge& GetCopyBridge() { return GetFlatCvt().GetCopyBridge(); } /////////////////////////////////////////////////////////////////////// /////////////////////// OPTIONS ///////////////////////// diff --git a/include/mp/flat/redef/MIP/abs.h b/include/mp/flat/redef/MIP/abs.h index e352b66d5..1dfb25e89 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/constr_std.h" +#include "mp/flat/constraints_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/alldiff.h b/include/mp/flat/redef/MIP/alldiff.h index c08d98330..3a8a0a2d1 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/constr_std.h" +#include "mp/flat/constraints_std.h" namespace mp { @@ -25,7 +25,7 @@ class AllDiffConverter_MIP : using ItemType = AllDiffConstraint; /// Convert in positive context - /// TODO add presolve link? + /// TODO add presolve bridge? 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 a8335f250..4c901bcaa 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/constr_std.h" +#include "mp/flat/constraints_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 1b3f95f1c..179a3d081 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/constr_std.h" +#include "mp/flat/constraints_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 78e2d51ca..88211a515 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/constr_std.h" +#include "mp/flat/constraints_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/count.h b/include/mp/flat/redef/MIP/count.h index 6aed9aad4..5f3bc2c80 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/constr_std.h" +#include "mp/flat/constraints_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/div.h b/include/mp/flat/redef/MIP/div.h index 501d29b32..f641b97b3 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/constr_std.h" +#include "mp/flat/constraints_std.h" namespace mp { diff --git a/include/mp/flat/redef/MIP/ifthenelse.h b/include/mp/flat/redef/MIP/ifthenelse.h index cbd7b9bc9..7bdf1933a 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/constr_std.h" +#include "mp/flat/constraints_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 4b72769fe..dab1f9dad 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/constr_std.h" +#include "mp/flat/constraints_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 f751a44ee..3aa8a33c9 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/constr_std.h" +#include "mp/flat/constraints_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 8525364c4..b1ec3d65c 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/constr_std.h" +#include "mp/flat/constraints_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 f08d649d4..6eab87f01 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/constr_std.h" +#include "mp/flat/constraints_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 2acac9029..f92cc6b47 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/constr_std.h" +#include "mp/flat/constraints_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 3380e8064..4ecf41774 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/constr_std.h" +#include "mp/flat/constraints_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 92efaeb04..41cecaa5f 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/constr_std.h" +#include "mp/flat/constraints_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 3c18b3dbd..503cde945 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/constr_std.h" +#include "mp/flat/constraints_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 3b8cea148..fd3fe3d69 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/constr_std.h" +#include "mp/flat/constraints_std.h" namespace mp { diff --git a/include/mp/flat/redef/redef_base.h b/include/mp/flat/redef/redef_base.h index cc05a53f2..ac79a2c8a 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/valcvt.h" +#include "mp/presolve.h" namespace mp { @@ -19,7 +19,7 @@ class BasicItemConverter { /// Access ModelConverter ModelConverter& GetMC() { return mdl_cvt_; } /// Access Presolver - pre::ValuePresolver& GetPre() { return GetMC().GetPresolver(); } + pre::Presolver& 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 links, if any + /// Responsible for adding presolve bridges, if any /// @param item: the item to be converted - /// @param i: item index, used to create a presolve link + /// @param i: item index, used to create a presolve bridge /// /// 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 f1d2f5f54..8f2fedd38 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/valcvt-link.h" -#include "mp/flat/constr_std.h" +#include "mp/presolve-bridge.h" +#include "mp/flat/constraints_std.h" namespace mp { namespace pre { -/// Presolve link between RangeCon and Con(LE/EQ/GE)+Slack. +/// Presolve bridge between RangeCon and Con(LE/EQ/GE)+Slack. /// TODO dependency inversion #164 -/// (FlatConverter needs just a BasicLink*? Entry type?) +/// (FlatConverter needs just a BasicBridge*? Entry type?) template class RangeCon2Slack : - public BasicStaticIndivEntryLink< + public BasicStaticIndivEntryBridge< RangeCon2Slack, 3, 3> { public: /// Base class - using Base = BasicStaticIndivEntryLink< + using Base = BasicStaticIndivEntryBridge< RangeCon2Slack, 3, 3>; /// Constructor RangeCon2Slack(ModelConverter& cvt, const typename Base::NodeList& ndl) : - Base(cvt.GetValuePresolver(), ndl), cvt_(cvt) { } + Base(cvt.GetPresolver(), ndl), cvt_(cvt) { } - /// Define pre- / postsolve methods for individual link entries. - /// Typedef LinkEntry is created in Base as std::array + /// Define pre- / postsolve methods for individual bridge entries. + /// Typedef BridgeEntry 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::LinkEntry& be) { + void PresolveSolutionEntry(const typename Base::BridgeEntry& 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::LinkEntry& be) { + void PostsolveSolutionEntry(const typename Base::BridgeEntry& 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::LinkEntry& be) { + void PresolveBasisEntry(const typename Base::BridgeEntry& 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::LinkEntry& be) { + void PostsolveBasisEntry(const typename Base::BridgeEntry& be) { SetInt(be, 0, GetInt(be, 2)); } /// Presolve IIS - void PresolveIISEntry(const typename Base::LinkEntry& ) { + void PresolveIISEntry(const typename Base::BridgeEntry& ) { /// Should not need } /// Postsolve IIS /// /// Take slack's if set, otherwise the constraint's - void PostsolveIISEntry(const typename Base::LinkEntry& be) { + void PostsolveIISEntry(const typename Base::BridgeEntry& 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::LinkEntry& be) { + void PresolveLazyUserCutFlagsEntry(const typename Base::BridgeEntry& be) { SetInt(be, 1, GetInt(be, 0)); } - void PostsolveLazyUserCutFlagsEntry(const typename Base::LinkEntry& ) { + void PostsolveLazyUserCutFlagsEntry(const typename Base::BridgeEntry& ) { /// Should not need } @@ -142,9 +142,9 @@ class RangeConstraintConverter : /// Conversion /// - /// Responsible for adding presolve links + /// Responsible for adding presolve bridges /// @param item: the item to be converted - /// @param i: item index, used to create a presolve link + /// @param i: item index, used to create a presolve bridge 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)); - GetSlackLink().AddEntry({i, i1, slk}); + GetSlackBridge().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().GetCopyLink().AddEntry( + GetMC().GetCopyBridge().AddEntry( { GET_CONSTRAINT_VALUE_NODE(ItemType).Select(i), nr }); } - using SlackLink = pre::RangeLinCon2Slack; - SlackLink& GetSlackLink() { return link_rng2slk_; } + using SlackBridge = pre::RangeLinCon2Slack; + SlackBridge& GetSlackBridge() { return bridge_rng2slk_; } private: - SlackLink link_rng2slk_ { + SlackBridge bridge_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 6f59eb179..248098bc6 100644 --- a/include/mp/model-mgr-base.h +++ b/include/mp/model-mgr-base.h @@ -32,7 +32,8 @@ class BasicModelManager { /// Read NL model virtual void ReadNLModel(const std::string& nl_filename, const std::string& filename_no_ext, - void (*cb_checkmodel)(size_t, size_t, size_t)) = 0; + std::function + cb_checkmodel) = 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 798242f65..fb1848400 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, - void (*cb_checkmodel)(size_t, size_t, size_t)) - override { + std::function + cb_checkmodel) override { steady_clock::time_point start = steady_clock::now(); ReadNLFile(nl_filename); diff --git a/include/mp/valcvt-base.h b/include/mp/presolve-base.h similarity index 89% rename from include/mp/valcvt-base.h rename to include/mp/presolve-base.h index 21da43116..72c5d35f0 100644 --- a/include/mp/valcvt-base.h +++ b/include/mp/presolve-base.h @@ -1,8 +1,9 @@ -#ifndef VALUE_PRESOLVE_BASE_H -#define VALUE_PRESOLVE_BASE_H +#ifndef PRESOLVE_BASE_H +#define PRESOLVE_BASE_H /** - Interface for value presolver: + Interface for value presolver: transforms solutions etc. + between original and presolved model */ #include @@ -13,10 +14,6 @@ namespace mp { - -/// Namespace mp::pre: value presolve methods. -/// They transform solutions, etc., -/// between the original and presolved models namespace pre { /// Debugging template @@ -182,12 +179,12 @@ using ModelValuesInt = ModelValues< ValueMapInt >; using ModelValuesDbl = ModelValues< ValueMapDbl >; -/// ValuePresolver interface. -/// Addresses value pre- / postsolve (solutions, basis, etc) -class BasicValuePresolver { +/// Presolver interface +/// Currently only addresses value pre- / postsolve (solutions, basis, ...) +class BasicPresolver { public: /// Virtual destructor - virtual ~BasicValuePresolver() = default; + virtual ~BasicPresolver() = default; /// Presolve solution (primal + dual) virtual ModelValuesDbl PresolveSolution(const ModelValuesDbl& ) = 0; @@ -209,7 +206,7 @@ class BasicValuePresolver { }; -/// index range for some link or node +/// index range for some bridge 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) { } @@ -234,22 +231,22 @@ struct IndexRange { /// Some backends need presolver /// for pre- / postsolving of suffix values etc -class BasicValuePresolverKeeper { +class BasicPresolverKeeper { protected: - void SetValuePresolver(pre::BasicValuePresolver* pPre) { + void SetPresolver(pre::BasicPresolver* pPre) { pPresolver_ = pPre; } - const pre::BasicValuePresolver& GetValuePresolver() const + const pre::BasicPresolver& GetPresolver() const { assert(pPresolver_); return *pPresolver_; } - pre::BasicValuePresolver& GetValuePresolver() + pre::BasicPresolver& GetPresolver() { assert(pPresolver_); return *pPresolver_; } private: - pre::BasicValuePresolver* pPresolver_ = nullptr; + pre::BasicPresolver* pPresolver_ = nullptr; }; } // namespace mp -#endif // VALUE_PRESOLVE_BASE_H +#endif // PRESOLVE_BASE_H diff --git a/include/mp/valcvt-link.h b/include/mp/presolve-bridge.h similarity index 52% rename from include/mp/valcvt-link.h rename to include/mp/presolve-bridge.h index 5e519721d..f70507b65 100644 --- a/include/mp/valcvt-link.h +++ b/include/mp/presolve-bridge.h @@ -1,25 +1,25 @@ -#ifndef VALUE_PRESOLVE_LINK_H -#define VALUE_PRESOLVE_LINK_H +#ifndef PRESOLVE_BRIDGE_H +#define PRESOLVE_BRIDGE_H #include #include #include "mp/common.h" -#include "valcvt-node.h" +#include "presolve-node.h" namespace mp { namespace pre { -/// Index range in a link -using ValcvtLinkIndexRange = IndexRange; +/// Index range in a bridge +using BridgeIndexRange = IndexRange; -/// Declare ValuePresolver -class ValuePresolver; +/// Declare Presolver +class Presolver; /// Macro for a list of pre- / postsolve method definitions -/// in a link. +/// in a bridge. /// Requires PRESOLVE_KIND defined to declare / define corr. methods #define LIST_PRESOLVE_METHODS \ PRESOLVE_KIND(Solution) \ @@ -28,53 +28,49 @@ class ValuePresolver; PRESOLVE_KIND(LazyUserCutFlags) // ... - -/// ValuePresolveLink interface +/// Bridge interface /// -/// A link is an array of value converters between nodes. +/// A bridge is an array of value converters between nodes. /// All converters are of the same type -class BasicValcvtLink { +class BasicBridge { public: /// Constructor - BasicValcvtLink(ValuePresolver& pre) : vsalue_presolver_(pre) { } + BasicBridge(Presolver& pre) : presolver_(pre) { } /// Virtual destructor - virtual ~BasicValcvtLink() = default; + virtual ~BasicBridge() = default; - /// The below pre- / postsolve methods - /// work on a range of link entries + /// The below pre- / postsolves work on a range of bridge entries /// Postsolves should usually loop the range backwards #define PRESOLVE_KIND(name) \ - virtual void Presolve ## name (ValcvtLinkIndexRange ) = 0; \ - virtual void Postsolve ## name(ValcvtLinkIndexRange ) = 0; + virtual void Presolve ## name (BridgeIndexRange ) = 0; \ + virtual void Postsolve ## name(BridgeIndexRange ) = 0; LIST_PRESOLVE_METHODS protected: - /// 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 ); + /// 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 ); private: - ValuePresolver& vsalue_presolver_; + Presolver& presolver_; }; -/// Link range: range of conversion specifiers of certain type. -/// The link is specified as well -struct LinkRange { +/// Bridge range: range of conversion specifiers of certain type +/// The bridge is specified as well +struct BridgeRange { /// Try & extend the range /// @return true iff extension worked, /// otherwise the caller would have to add the new range /// separately - bool ExtendRange(LinkRange br) { - if (&b_ == &br.b_) { // same link? - if (ir_.end == br.ir_.beg) { // and consecutive ranges? + bool ExtendRange(BridgeRange br) { + if (&b_ == &br.b_) { // same bridge + if (ir_.end == br.ir_.beg) { // and consecutive ranges ir_.end = br.ir_.end; return true; } @@ -82,35 +78,35 @@ struct LinkRange { return false; } - BasicValcvtLink& b_; - ValcvtLinkIndexRange ir_; + BasicBridge& b_; + BridgeIndexRange ir_; }; -/// A specific link: each entry just copies a range of values/ +/// A specific bridge: 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 CopyLink : public BasicValcvtLink { +class CopyBridge : public BasicBridge { public: /// Constructor - CopyLink(ValuePresolver& pre) : BasicValcvtLink(pre) { } + CopyBridge(Presolver& pre) : BasicBridge(pre) { } - /// Single link entry - using LinkEntry = std::pair; + /// Single bridge entry + using BridgeEntry = 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(LinkEntry be) { + void AddEntry(BridgeEntry be) { if (entries_.empty() || !entries_.back().first.ExtendableBy(be.first) || !entries_.back().second.ExtendableBy(be.second)) { entries_.push_back(be); // Add new entry - RegisterLinkIndex(entries_.size()-1); + RegisterBridgeIndex(entries_.size()-1); } else { // Extend last entry entries_.back().first.ExtendBy(be.first); entries_.back().second.ExtendBy(be.second); @@ -122,23 +118,23 @@ class CopyLink : public BasicValcvtLink { #undef PRESOLVE_KIND #define PRESOLVE_KIND(name) \ - void Presolve ## name (ValcvtLinkIndexRange ir) override \ + void Presolve ## name (BridgeIndexRange ir) override \ { CopySrcDest(ir); } \ - void Postsolve ## name(ValcvtLinkIndexRange ir) override \ + void Postsolve ## name(BridgeIndexRange ir) override \ { CopyDestSrc(ir); } LIST_PRESOLVE_METHODS protected: /// Copy src -> dest for index range ir - void CopySrcDest(ValcvtLinkIndexRange ir) { + void CopySrcDest(BridgeIndexRange 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(ValcvtLinkIndexRange ir) { + void CopyDestSrc(BridgeIndexRange ir) { for (int i=ir.end; (i--)!=ir.beg; ) { const auto& br = entries_[i]; Copy(br.second, br.first); @@ -150,42 +146,40 @@ class CopyLink : public BasicValcvtLink { }; -/// A stub for links which process each entry individually, -/// in contrast to Presolve...(ValcvtLinkIndexRange ...). -/// Some of such links could be optimized to store +/// A stub for bridges which process each entry individually, +/// in contrast to Presolve...(BridgeIndexRange ...) +/// Some of such bridges 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&). /// -/// TODO: we could default as follows: -/// Those methods which are not defined, just copy values +/// 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 /// (which might be correct in _some_ cases). -/// Then, need a "default copy" method. +/// Need a "default copy" method. /// /// Using CRTP: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern -template -class BasicIndivEntryLink : public BasicValcvtLink { +template +class BasicIndivEntryBridge : public BasicBridge { public: /// Constructor - BasicIndivEntryLink(ValuePresolver& pre) : - BasicValcvtLink(pre) { } + BasicIndivEntryBridge(Presolver& pre) : + BasicBridge(pre) { } /// Add entry /// Instead of a new entry, tries to extend the last one /// if exists - void AddEntry(LinkEntry be) { + void AddEntry(BridgeEntry be) { entries_.push_back(be); // Add new entry - RegisterLinkIndex(entries_.size()-1); + RegisterBridgeIndex(entries_.size()-1); } #undef PRESOLVE_KIND #define PRESOLVE_KIND(name) \ - void Presolve ## name (ValcvtLinkIndexRange ir) override { \ + void Presolve ## name (BridgeIndexRange ir) override { \ for (int i=ir.beg; i!=ir.end; ++i) \ MPD( Presolve ## name ## Entry(entries_.at(i)) ); } \ - void Postsolve ## name(ValcvtLinkIndexRange ir) override { \ + void Postsolve ## name(BridgeIndexRange ir) override { \ for (int i=ir.end; i--!=ir.beg; ) \ MPD( Postsolve ## name ## Entry(entries_.at(i)) ); } @@ -193,26 +187,26 @@ class BasicIndivEntryLink : public BasicValcvtLink { private: - std::vector entries_; + std::vector entries_; }; -/// A static indiv entry link has a fixed number of ValueNodes +/// A static indiv entry bridge has a fixed number of ValueNodes /// and indexes into them. /// Generally NNodes==NIndexes template -class BasicStaticIndivEntryLink : - public BasicIndivEntryLink > { +class BasicStaticIndivEntryBridge : + public BasicIndivEntryBridge > { public: /// Base class - using Base = BasicIndivEntryLink >; + using Base = BasicIndivEntryBridge >; /// Typedef NodeList using NodeList = std::array; - /// Typedef: LinkEntry is just an array if node indexes - using LinkEntry = std::array; + /// Typedef: BridgeEntry is just an array if node indexes + using BridgeEntry = std::array; /// Constructor - BasicStaticIndivEntryLink(ValuePresolver& pre, const NodeList& ndl) : + BasicStaticIndivEntryBridge(Presolver& pre, const NodeList& ndl) : Base(pre), ndl_(ndl) { } protected: @@ -224,23 +218,23 @@ class BasicStaticIndivEntryLink : /// Access int value at the node \a pos at the index /// stored in \a be[pos] /// - /// @param be: a LinkEntry + /// @param be: a BridgeEntry /// @param pos: node number from 0..NNodes-1 - int GetInt(const LinkEntry& be, size_t pos) const + int GetInt(const BridgeEntry& be, size_t pos) const { return GetNode(pos).GetInt(be[pos]); } /// SetInt - void SetInt(const LinkEntry& be, size_t pos, int i) + void SetInt(const BridgeEntry& 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 LinkEntry + /// @param be: a BridgeEntry /// @param pos: node number from 0..NNodes-1 - double GetDbl(const LinkEntry& be, size_t pos) const + double GetDbl(const BridgeEntry& be, size_t pos) const { return GetNode(pos).GetDbl(be[pos]); } /// SetDbl - void SetDbl(const LinkEntry& be, size_t pos, double i) + void SetDbl(const BridgeEntry& be, size_t pos, double i) { GetNode(pos).SetDbl(be[pos], i); } private: @@ -251,4 +245,4 @@ class BasicStaticIndivEntryLink : } // namespace mp -#endif // VALUE_PRESOLVE_LINK_H +#endif // PRESOLVE_BRIDGE_H diff --git a/include/mp/valcvt-node.h b/include/mp/presolve-node.h similarity index 95% rename from include/mp/valcvt-node.h rename to include/mp/presolve-node.h index bffdcd3ab..daeaa0c4f 100644 --- a/include/mp/valcvt-node.h +++ b/include/mp/presolve-node.h @@ -1,7 +1,7 @@ -#ifndef VALUE_PRESOLVE_NODE_H -#define VALUE_PRESOLVE_NODE_H +#ifndef PRESOLVE_NODE_H +#define PRESOLVE_NODE_H -#include "valcvt-base.h" +#include "presolve-base.h" namespace mp { @@ -71,7 +71,7 @@ class ValueNode { /// Constructor ValueNode(std::string nm) : name_(nm) { } - /// Declared size (what is being used by links) + /// Declared size (what is being used by bridges) 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 // VALUE_PRESOLVE_NODE_H +#endif // PRESOLVE_NODE_H diff --git a/include/mp/valcvt.h b/include/mp/presolve.h similarity index 61% rename from include/mp/valcvt.h rename to include/mp/presolve.h index b7f13321e..8d2b933d5 100644 --- a/include/mp/valcvt.h +++ b/include/mp/presolve.h @@ -1,15 +1,15 @@ -#ifndef VALUE_PRESOLVE_H -#define VALUE_PRESOLVE_H +#ifndef PRESOLVE_H +#define PRESOLVE_H /** - @file valcvt.h. + @file presolve.h Implementation of value presolver */ #include -#include "valcvt-node.h" -#include "valcvt-link.h" +#include "presolve-node.h" +#include "presolve-bridge.h" namespace mp { @@ -17,17 +17,17 @@ namespace mp { namespace pre { -/// Array of link ranges +/// Array of bridge ranges /// /// This defines a chain of transformations -class LinkRangeList : private std::deque { +class BridgeRangeList : 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(LinkRange br) { + void Add(BridgeRange br) { if (empty() || !back().ExtendRange(br)) push_back(br); } @@ -49,10 +49,8 @@ class LinkRangeList : private std::deque { }; -/// Value presolver implementation. -/// A ValuePresolver converts solutions and suffixes -/// between the original model and the presolved one. -class ValuePresolver : public BasicValuePresolver { +/// Value presolver implementation +class Presolver : public BasicPresolver { public: /// Source nodes for model items const ModelValuesTerminal& GetSourceNodes() const { return src_; } @@ -62,43 +60,43 @@ class ValuePresolver : public BasicValuePresolver { const ModelValuesTerminal& GetTargetNodes() const { return dest_; } ModelValuesTerminal& GetTargetNodes() { return dest_; } - /// Add (register) a link range - /// This is normally called automatically from a link + /// Add (register) a bridge range + /// This is normally called automatically from a bridge /// when an entry is added - void Add(LinkRange br) { brl_.Add(br); } + void Add(BridgeRange br) { brl_.Add(br); } /// Presolve solution (primal + dual) ModelValuesDbl PresolveSolution(const ModelValuesDbl& mvd) override - { return RunPresolve(&BasicValcvtLink::PresolveSolution, mvd); } + { return RunPresolve(&BasicBridge::PresolveSolution, mvd); } /// Postsolve solution (primal + dual) ModelValuesDbl PostsolveSolution(const ModelValuesDbl& mvd) override - { return RunPostsolve(&BasicValcvtLink::PostsolveSolution, mvd); } + { return RunPostsolve(&BasicBridge::PostsolveSolution, mvd); } /// Presolve basis (vars + cons) ModelValuesInt PresolveBasis(const ModelValuesInt& mvi) override - { return RunPresolve(&BasicValcvtLink::PresolveBasis, mvi); } + { return RunPresolve(&BasicBridge::PresolveBasis, mvi); } /// Postsolve solution (vars + cons) ModelValuesInt PostsolveBasis(const ModelValuesInt& mvi) override - { return RunPostsolve(&BasicValcvtLink::PostsolveBasis, mvi); } + { return RunPostsolve(&BasicBridge::PostsolveBasis, mvi); } /// Presolve IIS (vars + cons) ModelValuesInt PresolveIIS(const ModelValuesInt& mvi) override - { return RunPresolve(&BasicValcvtLink::PresolveIIS, mvi); } + { return RunPresolve(&BasicBridge::PresolveIIS, mvi); } /// Postsolve IIS (vars + cons) ModelValuesInt PostsolveIIS(const ModelValuesInt& mvi) override - { return RunPostsolve(&BasicValcvtLink::PostsolveIIS, mvi); } + { return RunPostsolve(&BasicBridge::PostsolveIIS, mvi); } /// Presolve LazyUserCutFlags (vars + cons) ModelValuesInt PresolveLazyUserCutFlags(const ModelValuesInt& mvi) override - { return RunPresolve(&BasicValcvtLink::PresolveLazyUserCutFlags, mvi); } + { return RunPresolve(&BasicBridge::PresolveLazyUserCutFlags, mvi); } protected: /// Helper type: virtual member function pointer - using LinkFn = void (BasicValcvtLink::*)(ValcvtLinkIndexRange); + using BridgeFn = void (BasicBridge::*)(BridgeIndexRange); /// Generic value presolve loop: forward template - ModelValues RunPresolve(LinkFn fn, const ModelValues& mv) const { + ModelValues RunPresolve(BridgeFn fn, const ModelValues& mv) const { src_ = mv; for (const auto& br: brl_) (br.b_.*fn)(br.ir_); @@ -107,7 +105,7 @@ class ValuePresolver : public BasicValuePresolver { /// Generic value postsolve loop: backward template - ModelValues RunPostsolve(LinkFn fn, const ModelValues& mv) const { + ModelValues RunPostsolve(BridgeFn fn, const ModelValues& mv) const { dest_ = mv; for (auto rit=brl_.rbegin(); rit!=brl_.rend(); ++rit) (rit->b_.*fn)(rit->ir_); @@ -117,17 +115,17 @@ class ValuePresolver : public BasicValuePresolver { private: mutable ModelValuesTerminal src_{std::string("src")}, dest_{std::string("dest")}; - LinkRangeList brl_; + BridgeRangeList brl_; }; -/// Implement link range registration in global Presolver +/// Implement bridge range registration in global Presolver inline void -BasicValcvtLink::RegisterLinkIndexRange(ValcvtLinkIndexRange bir) -{ vsalue_presolver_.Add( { *this, bir } ); } +BasicBridge::RegisterBridgeIndexRange(BridgeIndexRange bir) +{ presolver_.Add( { *this, bir } ); } } // namespace pre } // namespace mp -#endif // VALUE_PRESOLVE_H +#endif // PRESOLVE_H diff --git a/solvers/CMakeLists.txt b/solvers/CMakeLists.txt index 03cd93756..29f903533 100644 --- a/solvers/CMakeLists.txt +++ b/solvers/CMakeLists.txt @@ -233,10 +233,6 @@ 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 fec59fdca..c5ec1031d 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 b9cf10df3..59f955bb3 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::BasicValuePresolver*&); +CreateCoptModelMgr(CoptCommon&, Env&, pre::BasicPresolver*&); void CoptBackend::OpenSolver() { int status = 0; - const auto create_fn = GetCallbacks().init; + const auto& create_fn = GetCallbacks().cb_initsolver_; if (create_fn) set_env((copt_env*)create_fn()); else @@ -71,10 +71,10 @@ void CoptBackend::CloseSolver() { CoptBackend::CoptBackend() { /// Create a ModelManager - pre::BasicValuePresolver* pPre; + pre::BasicPresolver* pPre; auto data = CreateCoptModelMgr(*this, *this, pPre); SetMM( std::move( data ) ); - SetValuePresolver(pPre); + SetPresolver(pPre); } CoptBackend::~CoptBackend() { @@ -102,7 +102,7 @@ void CoptBackend::InitOptionParsing() { } Solution CoptBackend::GetSolution() { - auto mv = GetValuePresolver().PostsolveSolution( + auto mv = GetPresolver().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 = GetValuePresolver().PostsolveBasis( + auto mv = GetPresolver().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 = GetValuePresolver().PresolveBasis( + auto mv = GetPresolver().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 = GetValuePresolver().PostsolveIIS( + auto mv = GetPresolver().PostsolveIIS( { variis, coniis }); return { mv.GetVarValues()(), mv.GetConValues()() }; } diff --git a/solvers/copt/coptbackend.h b/solvers/copt/coptbackend.h index f6749a545..1be53c6a5 100644 --- a/solvers/copt/coptbackend.h +++ b/solvers/copt/coptbackend.h @@ -19,14 +19,14 @@ #include #include "mp/backend-mip.h" -#include "mp/valcvt-base.h" +#include "mp/presolve-base.h" #include "coptcommon.h" namespace mp { class CoptBackend : public MIPBackend, - public BasicValuePresolverKeeper, + public BasicPresolverKeeper, public CoptCommon { using BaseBackend = MIPBackend; diff --git a/solvers/copt/coptmodelapi.cc b/solvers/copt/coptmodelapi.cc index e0ad6835c..853dd38ee 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::BasicValuePresolver*& pPre) { + pre::BasicPresolver*& pPre) { return CreateModelMgrWithFlatConverter< CoptModelAPI, MIPFlatConverter >(cc, e, pPre); } diff --git a/solvers/copt/coptmodelapi.h b/solvers/copt/coptmodelapi.h index c99848066..8616f9859 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/constr_std.h" +#include "mp/flat/constraints_std.h" namespace mp { diff --git a/solvers/copt/main.cc b/solvers/copt/main.cc index 00150c58d..99e820e24 100644 --- a/solvers/copt/main.cc +++ b/solvers/copt/main.cc @@ -8,6 +8,9 @@ extern "C" int main1(int, char **argv) { mp::RunBackendApp(argv, CreateCoptBackend); } -extern "C" int main2(int, char** argv, CCallbacks cb) { - return mp::RunBackendApp(argv, CreateCoptBackend, cb); -} +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 diff --git a/solvers/cplexdirect/cplexbackend.cc b/solvers/cplexdirect/cplexbackend.cc index 4c8de092f..bf499a8d9 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::BasicValuePresolver*&); +CreateCplexModelMgr(CplexCommon&, Env&, pre::BasicPresolver*&); CplexBackend::CplexBackend() { OpenSolver(); - pre::BasicValuePresolver* pPre; + pre::BasicPresolver* pPre; auto data = CreateCplexModelMgr(*this, *this, pPre); SetMM( std::move( data ) ); - SetValuePresolver(pPre); + SetPresolver(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().init; + const auto& create_fn = GetCallbacks().cb_initsolver_; if (create_fn) set_env((CPXENVptr)create_fn()); else @@ -115,7 +115,7 @@ bool CplexBackend::IsQCP() const { Solution CplexBackend::GetSolution() { - auto mv = GetValuePresolver().PostsolveSolution( + auto mv = GetPresolver().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 4f5a5e8a4..94c9870fc 100644 --- a/solvers/cplexdirect/cplexbackend.h +++ b/solvers/cplexdirect/cplexbackend.h @@ -19,14 +19,14 @@ #include #include "mp/backend-mip.h" -#include "mp/valcvt-base.h" +#include "mp/presolve-base.h" #include "cplexcommon.h" namespace mp { class CplexBackend : public MIPBackend, - public BasicValuePresolverKeeper, + public BasicPresolverKeeper, public CplexCommon { using BaseBackend = MIPBackend; diff --git a/solvers/cplexdirect/cplexdirect-lib.c b/solvers/cplexdirect/cplexdirect-lib.c index 260384d8d..688274a4a 100644 --- a/solvers/cplexdirect/cplexdirect-lib.c +++ b/solvers/cplexdirect/cplexdirect-lib.c @@ -10,16 +10,17 @@ 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); - AMPLSLoadNLModel(slv, nl_filename); + int ret = -1; + ret = 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); -} + AMPLSCloseCPLEX(&slv); +} \ No newline at end of file diff --git a/solvers/cplexdirect/cplexmodelapi.cc b/solvers/cplexdirect/cplexmodelapi.cc index d89e507aa..f4af65b2c 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::BasicValuePresolver*& pPre) { + pre::BasicPresolver*& pPre) { return CreateModelMgrWithFlatConverter< CplexModelAPI, MIPFlatConverter >(cc, e, pPre); } diff --git a/solvers/cplexdirect/cplexmodelapi.h b/solvers/cplexdirect/cplexmodelapi.h index 0de9884f4..890600703 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/constr_std.h" +#include "mp/flat/constraints_std.h" namespace mp { diff --git a/solvers/cplexdirect/main.cc b/solvers/cplexdirect/main.cc index a7800d617..c7cced9ff 100644 --- a/solvers/cplexdirect/main.cc +++ b/solvers/cplexdirect/main.cc @@ -8,6 +8,9 @@ extern "C" int main1(int, char **argv) { mp::RunBackendApp(argv, CreateCplexBackend); } -extern "C" int main2(int, char** argv, CCallbacks cb) { - return mp::RunBackendApp(argv, CreateCplexBackend, cb); -} +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 diff --git a/solvers/gurobi/gurobi-lib.c b/solvers/gurobi/gurobi-lib.c index 872a1744a..1ff5af312 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; - AMPLSLoadNLModel(slv, nl_filename); + int ret = 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 324c73465..59872b12b 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::BasicValuePresolver*& pPre); + Env& e, pre::BasicPresolver*& pPre); GurobiBackend::GurobiBackend() { - pre::BasicValuePresolver* pPre; + pre::BasicPresolver* pPre; auto data = CreateGurobiModelMgr(*this, *this, pPre); SetMM( std::move( data ) ); - SetValuePresolver(pPre); + SetPresolver(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().init; + const auto& create_fn = GetCallbacks().cb_initsolver_; 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().init) + if (!GetCallbacks().cb_initsolver_) { int res = GRBstartenv(env_ref()); if (res) { - const auto diag = GetCallbacks().diagnostics; + const auto& diag = GetCallbacks().cb_diagnostics_; if (diag) diag(); else { @@ -218,7 +218,7 @@ std::vector GurobiBackend::PrimalSolution() { } Solution GurobiBackend::GetSolution() { - auto mv = GetValuePresolver().PostsolveSolution( + auto mv = GetPresolver().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 = GetValuePresolver().PresolveLazyUserCutFlags({ + auto vm = GetPresolver().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 = GetValuePresolver().PostsolveBasis( + auto mv = GetPresolver().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 = GetValuePresolver().PresolveBasis( + auto mv = GetPresolver().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 = GetValuePresolver().PresolveSolution( + auto mv = GetPresolver().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 = GetValuePresolver().PostsolveSolution({ + auto vm = GetPresolver().PostsolveSolution({ {}, {{{CG_Linear, std::move(fd)}}} }); @@ -512,7 +512,7 @@ IIS GurobiBackend::GetIIS() { auto variis = VarsIIS(); auto coniis = ConsIIS(); - auto mv = GetValuePresolver().PostsolveIIS( + auto mv = GetPresolver().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 = GetValuePresolver().PresolveSolution({ + auto mv = GetPresolver().PresolveSolution({ {}, feasrelax().rhspen() }); diff --git a/solvers/gurobi/gurobibackend.h b/solvers/gurobi/gurobibackend.h index ab4f3819a..6a7f510d5 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/valcvt-base.h" +#include "mp/presolve-base.h" namespace mp { class GurobiBackend : public MIPBackend, - public BasicValuePresolverKeeper, + public BasicPresolverKeeper, public GurobiCommon { using BaseBackend = MIPBackend; diff --git a/solvers/gurobi/gurobimodelapi.cc b/solvers/gurobi/gurobimodelapi.cc index b5cb1a5c4..77b0abfc1 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::BasicValuePresolver*& pPre) { + pre::BasicPresolver*& pPre) { return CreateModelMgrWithFlatConverter< GurobiModelAPI, MIPFlatConverter >(gc, e, pPre); } diff --git a/solvers/gurobi/gurobimodelapi.h b/solvers/gurobi/gurobimodelapi.h index 9bfae4165..e247c5728 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/constr_std.h" +#include "mp/flat/constraints_std.h" #include "gurobicommon.h" diff --git a/solvers/gurobi/main.cc b/solvers/gurobi/main.cc index 056324c3c..c3ca66d58 100644 --- a/solvers/gurobi/main.cc +++ b/solvers/gurobi/main.cc @@ -7,6 +7,9 @@ extern "C" int main1(int, char **argv) { return mp::RunBackendApp(argv, CreateGurobiBackend); } -extern "C" int main2(int, char** argv, CCallbacks cb) { - return mp::RunBackendApp(argv, CreateGurobiBackend, cb); +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); } diff --git a/solvers/highsdirect/highsdirectbackend.cc b/solvers/highsdirect/highsdirectbackend.cc index 05c7d0492..a558b88a7 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::BasicValuePresolver*&); +CreateHighsModelMgr(HighsCommon&, Env&, pre::BasicPresolver*&); HighsBackend::HighsBackend() { OpenSolver(); - pre::BasicValuePresolver* pPre; + pre::BasicPresolver* pPre; auto data = CreateHighsModelMgr(*this, *this, pPre); SetMM( std::move( data ) ); - SetValuePresolver(pPre); + SetPresolver(pPre); /// Copy env/lp to ModelAPI copy_common_info_to_other(); @@ -72,7 +72,7 @@ bool HighsBackend::IsQCP() const { } Solution HighsBackend::GetSolution() { - auto mv = GetValuePresolver().PostsolveSolution( + auto mv = GetPresolver().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 = GetValuePresolver().PostsolveBasis( + auto mv = GetPresolver().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 = GetValuePresolver().PresolveBasis( + auto mv = GetPresolver().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 f881b4c87..299faa949 100644 --- a/solvers/highsdirect/highsdirectbackend.h +++ b/solvers/highsdirect/highsdirectbackend.h @@ -19,14 +19,14 @@ #include #include "mp/backend-mip.h" -#include "mp/valcvt-base.h" +#include "mp/presolve-base.h" #include "highsdirectcommon.h" namespace mp { class HighsBackend : public MIPBackend, - public BasicValuePresolverKeeper, + public BasicPresolverKeeper, public HighsCommon { using BaseBackend = MIPBackend; diff --git a/solvers/highsdirect/highsdirectmodelapi.cc b/solvers/highsdirect/highsdirectmodelapi.cc index 0586a92e6..92e62ba53 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::BasicValuePresolver*& pPre) { + pre::BasicPresolver*& 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 (int i = 0; i < v.size(); i++) { + for (size_t 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 (size_t i = 0; i < qt.size(); i++) + for (int 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 b29f0c214..32e8aa674 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/constr_std.h" +#include "mp/flat/constraints_std.h" namespace mp { diff --git a/solvers/ortoolsmp/CHANGES.ortoolsmp.md b/solvers/ortoolsmp/CHANGES.ortoolsmp.md deleted file mode 100644 index 7e0a10590..000000000 --- a/solvers/ortoolsmp/CHANGES.ortoolsmp.md +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 137398179..000000000 --- a/solvers/ortoolsmp/README.ortoolsmp.txt +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 291daede8..000000000 --- a/solvers/ortoolsmp/main.cc +++ /dev/null @@ -1,10 +0,0 @@ -#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 deleted file mode 100644 index 2ffcce081..000000000 --- a/solvers/ortoolsmp/model-mgr-with-std-pb.cc +++ /dev/null @@ -1,8 +0,0 @@ -/** - * 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 deleted file mode 100644 index 5b2379f3d..000000000 --- a/solvers/ortoolsmp/ortoolsmp-ampls-c-api.h +++ /dev/null @@ -1,29 +0,0 @@ -#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 deleted file mode 100644 index 89fd58085..000000000 --- a/solvers/ortoolsmp/ortoolsmp-lib.c +++ /dev/null @@ -1,27 +0,0 @@ -#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 deleted file mode 100644 index 651ca132d..000000000 --- a/solvers/ortoolsmp/ortoolsmpbackend.cc +++ /dev/null @@ -1,299 +0,0 @@ -#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 deleted file mode 100644 index a86ead954..000000000 --- a/solvers/ortoolsmp/ortoolsmpbackend.h +++ /dev/null @@ -1,131 +0,0 @@ -#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 deleted file mode 100644 index ef9862198..000000000 --- a/solvers/ortoolsmp/ortoolsmpcommon.cc +++ /dev/null @@ -1,70 +0,0 @@ -#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 deleted file mode 100644 index 25d242f65..000000000 --- a/solvers/ortoolsmp/ortoolsmpcommon.h +++ /dev/null @@ -1,72 +0,0 @@ -#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 deleted file mode 100644 index d5ab23c2f..000000000 --- a/solvers/ortoolsmp/ortoolsmpmodelapi.cc +++ /dev/null @@ -1,77 +0,0 @@ -#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 deleted file mode 100644 index c53d59d81..000000000 --- a/solvers/ortoolsmp/ortoolsmpmodelapi.h +++ /dev/null @@ -1,71 +0,0 @@ -#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 33ef1f9b0..dbbb194cb 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::BasicValuePresolver*&); +CreateVisitorModelMgr(VisitorCommon&, Env&, pre::BasicPresolver*&); VisitorBackend::VisitorBackend() { OpenSolver(); /// Create a ModelManager - pre::BasicValuePresolver* pPre; + pre::BasicPresolver* pPre; auto data = CreateVisitorModelMgr(*this, *this, pPre); SetMM( std::move( data ) ); - SetValuePresolver(pPre); + SetPresolver(pPre); /// Copy env/lp to ModelAPI copy_common_info_to_other(); @@ -129,7 +129,7 @@ bool VisitorBackend::IsQCP() const { } Solution VisitorBackend::GetSolution() { - auto mv = GetValuePresolver().PostsolveSolution( + auto mv = GetPresolver().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 = GetValuePresolver().PostsolveBasis( + auto mv = GetPresolver().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 = GetValuePresolver().PresolveBasis( + auto mv = GetPresolver().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 = GetValuePresolver().PostsolveIIS( + auto mv = GetPresolver().PostsolveIIS( { variis, coniis }); return { mv.GetVarValues()(), mv.GetConValues()() }; } diff --git a/solvers/visitor/visitorbackend.h b/solvers/visitor/visitorbackend.h index fec699b46..16c08ab74 100644 --- a/solvers/visitor/visitorbackend.h +++ b/solvers/visitor/visitorbackend.h @@ -19,14 +19,14 @@ #include #include "mp/backend-mip.h" -#include "mp/valcvt-base.h" +#include "mp/presolve-base.h" #include "visitorcommon.h" namespace mp { class VisitorBackend : public MIPBackend, - public BasicValuePresolverKeeper, + public BasicPresolverKeeper, public VisitorCommon { using BaseBackend = MIPBackend; diff --git a/solvers/visitor/visitormodelapi.cc b/solvers/visitor/visitormodelapi.cc index a0b78e9ba..d5a0791f8 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::BasicValuePresolver*& pPre) { + pre::BasicPresolver*& pPre) { return CreateModelMgrWithFlatConverter< VisitorModelAPI, MIPFlatConverter >(cc, e, pPre); } diff --git a/solvers/visitor/visitormodelapi.h b/solvers/visitor/visitormodelapi.h index 3653a2507..a2f7f15e2 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/constr_std.h" +#include "mp/flat/constraints_std.h" namespace mp { diff --git a/src/mp/flat/piecewise_linear.cpp b/src/mp/flat/piecewise_linear.cpp index f4ddb11d1..7ba130b27 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/constr_std.h" +#include "mp/flat/constraints_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 14fb42464..4c07ef15f 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(); - AMPLS__internal__TryCatchWrapper( slv, [&]() { + int ret = AMPLS__internal__TryCatchWrapper( slv, [&]() { auto ii = new AMPLS_MP__internal(); slv->internal_info_ = ii; ii->p_be_ = std::move(p_be); @@ -1050,7 +1050,10 @@ 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_;