Skip to content

Commit

Permalink
Expr: option acc:_expr for SCIP #237
Browse files Browse the repository at this point in the history
  • Loading branch information
glebbelov committed Apr 22, 2024
1 parent 4eaab06 commit 320c0a9
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 19 deletions.
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -396,10 +396,15 @@ add_prefix(MP_FLAT_REDEF_MIP_HEADERS include/mp/flat/redef/MIP/
piecewise_linear.h
power_const.h sos2.h)

add_prefix(MP_EXPR_HEADERS include/mp/expr/
model_api_base.h)


set(MP_ALL_HEADERS ${MP_HEADERS} ${MP_FLAT_HEADERS}
${MP_FLAT_REDEF_HEADERS}
${MP_FLAT_REDEF_STD_HEADERS} ${MP_FLAT_REDEF_MIP_HEADERS})
${MP_FLAT_REDEF_STD_HEADERS} ${MP_FLAT_REDEF_MIP_HEADERS}
${MP_EXPR_HEADERS}
)


set(MP_SOURCES )
Expand Down
54 changes: 54 additions & 0 deletions include/mp/expr/model_api_base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
Basic expression-based model API definitions.
Copyright (C) 2024 AMPL Optimization Inc.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that the copyright notice and this permission notice and warranty
disclaimer appear in supporting documentation.
The author and AMPL Optimization Inc disclaim all warranties with
regard to this software, including all implied warranties of
merchantability and fitness. In no event shall the author be liable
for any special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether in an
action of contract, negligence or other tortious action, arising out
of or in connection with the use or performance of this software.
Author: Gleb Belov <[email protected]>
*/
#ifndef MODEL_API_BASE_H
#define MODEL_API_BASE_H

#include "mp/flat/model_api_base.h"

namespace mp {

/// ModelAPIs handling expression trees should derive from
template <class ExprType=void*>
class BasicExprModelAPI
:public BasicFlatModelAPI {
public:
using Expr = ExprType;
/// Placeholder for GetTypeName()
static const char* GetTypeName() { return "BasicExprModelAPI"; }

/// A ModelAPI accepting NL trees can declare this.
///
/// - NotAccepted: not compiled
/// - AcceptedButNotRecommended: compiled but off by default (option acc:_expr)
/// - Recommended: on by default
#define ACCEPT_EXPRESSION_INTERFACE(val) \
static constexpr ExpressionAcceptanceLevel \
ExpressionInterfaceAcceptanceLevel() { return ExpressionAcceptanceLevel::val; }

/// Reuse inherited names
USE_BASE_CONSTRAINT_HANDLERS(BasicFlatModelAPI)

};

} // namespace mp

#endif // MODEL_API_BASE_H
47 changes: 44 additions & 3 deletions include/mp/flat/constr_keeper.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,12 @@ class BasicConstraintKeeper {
/// @return whether any converted
virtual bool ConvertAllNewWith(BasicFlatConverter& cvt) = 0;

/// Mark whether to keep result vars
virtual void MarkExprsForResultVars(BasicFlatConverter& cvt) = 0;

/// Convert to use expressions
virtual void ConvertWithExpressions(BasicFlatConverter& cvt) = 0;

/// Query (user-chosen, if sensible) constraint acceptance level
virtual ConstraintAcceptanceLevel GetChosenAcceptanceLevel()
const {
Expand Down Expand Up @@ -510,7 +516,10 @@ class BasicConstraintKeeper {

/// Set user preferred acceptance level
virtual void SetChosenAcceptanceLevel(
ConstraintAcceptanceLevel acc) { acceptance_level_ = acc;}
ConstraintAcceptanceLevel acc) {
acceptance_level_ = static_cast<
typename std::underlying_type<ConstraintAcceptanceLevel>::type >(acc);
}

/// Mark as bridged. Use index only.
virtual void MarkAsBridged(int i) = 0;
Expand Down Expand Up @@ -759,6 +768,18 @@ class ConstraintKeeper final
return false;
}

/// Mark whether to keep result vars
void MarkExprsForResultVars(BasicFlatConverter& cvt) override {
assert(&cvt == &GetConverter()); // Using the same Converter
DoMarkForResultVars();
}

/// Convert to use expressions
void ConvertWithExpressions(BasicFlatConverter& cvt) override {
assert(&cvt == &GetConverter()); // Using the same Converter
DoCvtWithExprs();
}

/// Converter's ability to convert the constraint type
bool IfConverterConverts(
BasicFlatConverter& cvt ) const override {
Expand Down Expand Up @@ -865,12 +886,12 @@ class ConstraintKeeper final
int i=i_last;
const auto acceptanceLevel =
GetChosenAcceptanceLevel();
if (NotAccepted == acceptanceLevel) {
if (ConstraintAcceptanceLevel::NotAccepted == acceptanceLevel) {
for ( ; ++i!=(int)cons_.size(); )
if (!cons_[i].IsBridged())
ConvertConstraint(cons_[i], i);
}
else if (AcceptedButNotRecommended == acceptanceLevel) {
else if (ConstraintAcceptanceLevel::AcceptedButNotRecommended == acceptanceLevel) {
for (; ++i != (int)cons_.size(); ) {
if (!cons_[i].IsBridged()) {
try { // Try to convert all but allow failure
Expand All @@ -893,6 +914,14 @@ class ConstraintKeeper final
return any_converted;
}

void DoMarkForResultVars() {
const auto acceptanceLevel =
GetChosenAcceptanceLevel();

}

void DoCvtWithExprs() { }

/// Call Converter's RunConversion() and mark as "bridged".
///
/// @param cnt the constraint container -
Expand Down Expand Up @@ -1261,6 +1290,18 @@ class ConstraintManager {
} while (any_converted);
}

/// Mark which expressions should stay as FuncCons or just have a result variable
void MarkExprsForResultVars(BasicFlatConverter& cvt) {
for (auto& ck: con_keepers_)
ck.second.MarkExprsForResultVars(cvt);
}

/// Convert to expression-based model
void ConvertWithExpressions(BasicFlatConverter& cvt) {
for (auto& ck: con_keepers_)
ck.second.ConvertWithExpressions(cvt);
}

/// Fill counters of unbridged constraints
void FillConstraintCounters(
const BasicFlatModelAPI& mapi, FlatModelInfo& fmi) const {
Expand Down
53 changes: 51 additions & 2 deletions include/mp/flat/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,13 @@ class FlatConverter :
// MP_DISPATCH( PreprocessIntermediate() ); // preprocess after each level
constr_depth_ = 1; // Workaround. TODO have maps as special constraints
MP_DISPATCH( ConvertMaps() );
MP_DISPATCH( PreprocessFinal() ); // final prepro
MP_DISPATCH( PreprocessFlatFinal() ); // final flat model prepro
if constexpr (IfAcceptingNLOutput()) {
if (IfWantNLOutput()) {
MPD( Convert2NL() );
MPD( PreprocessNLFinal() );
}
}
} catch (const ConstraintConversionFailure& cff) {
MP_RAISE(cff.message());
}
Expand All @@ -257,14 +263,34 @@ class FlatConverter :
/// Default map conversions. Currently empty
void ConvertMaps() { }

/// Option to actually use expressions if available
bool IfWantNLOutput() const { return options_.accExpr_; }

/// Whether solver CAN accept expressions
static constexpr bool IfAcceptingNLOutput()
{ return
ExpressionAcceptanceLevel::AcceptedButNotRecommended
== ModelAPI::ExpressionInterfaceAcceptanceLevel()
||
ExpressionAcceptanceLevel::Recommended
== ModelAPI::ExpressionInterfaceAcceptanceLevel(); }

/// Convert some functional constraints to expressions
void Convert2NL() {
GetModel().MarkExprsForResultVars(*this);
GetModel().ConvertWithExpressions(*this);
}

/// Finish exporting the reformulation graph
void CloseGraphExporter() {
value_presolver_.FinishExportingLinkEntries();
GetModel().GetFileAppender().Close();
}

//////////////////////// WHOLE-MODEL PREPROCESSING /////////////////////////
void PreprocessIntermediate() { }
void PreprocessFinal() { }
void PreprocessFlatFinal() { }
void PreprocessNLFinal() { }


//////////////////////////// CONSTRAINT PROPAGATORS ///////////////////////////////////
Expand Down Expand Up @@ -953,6 +979,11 @@ class FlatConverter :
int passSOCP2QC_ = 0;
int passExpCones_ = 0;

int accExpr_ = static_cast<
typename std::underlying_type_t<ExpressionAcceptanceLevel> >
(ModelAPI::ExpressionInterfaceAcceptanceLevel())
-1; // If available, 0 or 1

int relax_ = 0;

int solcheckmode_ = 1+2+512;
Expand Down Expand Up @@ -1034,6 +1065,12 @@ class FlatConverter :
"in particular if the objective is quadratic", 1},
{ "2", "Always convert", 2}
};
const mp::OptionValueInfo values_allexpr_acceptance[2] = {
{ "0", "Not accepted, all expressions will be treated as flat constraints, "
"or redefined", 0},
{ "1", "Accepted. See the individual acc:... options", 1}
};


void InitOwnOptions() {
/// Should be called after adding all constraint keepers
Expand Down Expand Up @@ -1099,9 +1136,21 @@ class FlatConverter :
socp2qc_mode_text_.c_str(),
options_.passSOCP2QC_, socp2qc_values_);
options_.passSOCP2QC_ = DefaultSOCP2QCMode();

if (IfAcceptingNLOutput())
GetEnv().AddStoredOption("acc:_expr",
fmt::format(
"Solver acceptance level for all expressions, "
"default {}:\n\n.. value-table::",
options_.accExpr_).c_str(),
options_.accExpr_, values_allexpr_acceptance);
else
GetEnv().AddStoredOption("acc:_expr", "HIDDEN", options_.accExpr_, 0, 1);

GetEnv().AddOption("alg:relax relax",
"0*/1: Whether to relax integrality of variables.",
options_.relax_, 0, 1);

GetEnv().AddStoredOption(
"sol:chk:mode solcheck checkmode chk:mode",
"Solution checking mode. "
Expand Down
29 changes: 20 additions & 9 deletions include/mp/flat/model_api_base.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
Basic flat model API definitions.
Copyright (C) 2021 AMPL Optimization Inc
Copyright (C) 2024 AMPL Optimization Inc.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
Expand All @@ -16,14 +16,12 @@
whatsoever resulting from loss of use, data or profits, whether in an
action of contract, negligence or other tortious action, arising out
of or in connection with the use or performance of this software.
Author: Gleb Belov <[email protected]>
*/
#ifndef FLAT_MODEL_API_BASE_H_
#define FLAT_MODEL_API_BASE_H_

/**
* Basic definitions for a FlatModelAPI
*/

#include <string>

#include "mp/arrayref.h"
Expand Down Expand Up @@ -72,7 +70,14 @@ class VarArrayDef {


/// Level of acceptance of a constraint by a backend
enum ConstraintAcceptanceLevel {
enum class ConstraintAcceptanceLevel {
NotAccepted=0,
AcceptedButNotRecommended=1,
Recommended=2
};

/// Level of acceptance of an expression by a backend
enum class ExpressionAcceptanceLevel {
NotAccepted=0,
AcceptedButNotRecommended=1,
Recommended=2
Expand Down Expand Up @@ -110,7 +115,7 @@ enum ConstraintGroup {
class BasicFlatModelAPI {
public:
/// Placeholder for GetTypeName()
static const char* GetTypeName() { return "BasicBackendFlatModelAPI"; }
static const char* GetTypeName() { return "BasicFlatModelAPI"; }
/// Placeholder for GetLongName()
static const char* GetLongName() { return nullptr; }

Expand Down Expand Up @@ -155,6 +160,7 @@ class BasicFlatModelAPI {
Constraint::GetTypeName() +
"'. Provide a handler or a converter method");
}

/// Derived backends have to tell C++ to use default handlers if they are needed
/// when they overload AddConstraint(), due to C++ name hiding
#define USE_BASE_CONSTRAINT_HANDLERS(BaseBackend) \
Expand All @@ -169,9 +175,14 @@ class BasicFlatModelAPI {

/// By default, we say constraint XYZ is not accepted but...
static constexpr ConstraintAcceptanceLevel AcceptanceLevel(const BasicConstraint*) {
return NotAccepted;
return ConstraintAcceptanceLevel::NotAccepted;
}

/// By default, no expressions
static constexpr ExpressionAcceptanceLevel \
ExpressionInterfaceAcceptanceLevel()
{ return ExpressionAcceptanceLevel::NotAccepted; }

/// Specifically, ask if the solver accepts non-convex quadratic constraints
static constexpr bool AcceptsNonconvexQC() { return false; }

Expand All @@ -194,7 +205,7 @@ class BasicFlatModelAPI {
#define ACCEPT_CONSTRAINT(ConstrType, level, con_grp) \
static mp::ConstraintAcceptanceLevel \
AcceptanceLevel(const ConstrType*) \
{ return (mp::ConstraintAcceptanceLevel)level; } \
{ return mp::ConstraintAcceptanceLevel::level; } \
static constexpr int \
GroupNumber(const ConstrType*) { return con_grp; }

Expand Down
10 changes: 6 additions & 4 deletions solvers/scipmp/scipmpmodelapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@

#include "mp/env.h"
#include "scipmpcommon.h"
#include "mp/flat/model_api_base.h"
#include "mp/expr/model_api_base.h"
#include "mp/flat/constr_std.h"

namespace mp {

class ScipModelAPI :
public ScipCommon, public EnvKeeper,
public BasicFlatModelAPI
public ScipCommon, public EnvKeeper,
public BasicExprModelAPI<SCIP_EXPR*>
{
using BaseModelAPI = BasicFlatModelAPI;
using BaseModelAPI = BasicExprModelAPI<SCIP_EXPR*>;

private:
void linearHelper(const int* pvars, const double* pcoefs, const size_t size, const char* name, const double lb, const double ub);
Expand Down Expand Up @@ -47,6 +47,8 @@ class ScipModelAPI :

//////////////////////////// GENERAL CONSTRAINTS ////////////////////////////
USE_BASE_CONSTRAINT_HANDLERS(BaseModelAPI)
//////////////////////////// EXPRESSION TREES ////////////////////////////
ACCEPT_EXPRESSION_INTERFACE(Recommended);

/// For each suppoted constraint type, add the ACCEPT_CONSTRAINT macro
/// and the relative AddConstraint function.
Expand Down

0 comments on commit 320c0a9

Please sign in to comment.