Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:ampl/mp into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
mapgccv committed Aug 28, 2024
2 parents dd1969c + 3132c5c commit c2c2954
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 32 deletions.
2 changes: 2 additions & 0 deletions CHANGES.mp.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Summary of recent updates to the AMPL MP Library


## unreleased
- Option tech:writemodel:index to choose the iteration
when solver model is exported.
- SCIP (and any solver with linear objective
and non-linear constraints): improve reformulation
of QP objectives.
Expand Down
2 changes: 1 addition & 1 deletion doc/source/model-guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ Ever wondered how to model logical and non-linear constraints? For example:

- Piecewise-linear approximation of *y = sin(x)*.

Moreover, MP supports :ref:`multiple-objectives`.
MP automates many of such modeling tasks by reformulating AMPL models
suitably for the given solver.
Moreover, MP supports :ref:`multiple-objectives`.
A series of small modeling tasks like these are handled in the
`MP Modeling Series <https://ampl.com/streamlit/Modeling_Tips>`_,
while below follows a comprehensive guide.
Expand Down
2 changes: 1 addition & 1 deletion include/mp/ampls-ccallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ typedef struct AMPLS_ModelTraits_T {
} AMPLS_ModelTraits;


typedef void (*Checker_AMPLS_ModeltTraits)(const AMPLS_ModelTraits*);
typedef void (*Checker_AMPLS_ModeltTraits)(AMPLS_ModelTraits*);


/// Set of callbacks provided to a driver for licensing issues
Expand Down
23 changes: 18 additions & 5 deletions include/mp/backend-std.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class StdBackend :
/// Redefine this if you want some extensions
/// to be written after solving instead.
/// This is for compatibility wiht ASL drivers
/// where 'writeprob' was used for native-format model
/// where 'writeprob' was used both for native-format model
/// and solution output #218.
virtual std::set<std::string> NativeResultExtensions() const
{ return {".sol", ".ilp", ".mst", ".hnt", ".bas", ".json"}; }
Expand Down Expand Up @@ -276,9 +276,11 @@ class StdBackend :
auto get_sol = [this]() {
return GetSolution();
};
int i=0;
int i_solve=0;
while (GetMM().PrepareSolveIteration(get_stt, get_sol)) {
// ExportModel({"/tmp/model" + std::to_string(++i) + ".lp"});
if (++i_solve==storedOptions_.writemodel_index_
&& exportFileMode() > 0)
ExportModel(export_file_names());
Solve();
}
}
Expand Down Expand Up @@ -808,6 +810,7 @@ class StdBackend :

/// For write prob
std::vector<std::string> export_files_;
int writemodel_index_ = 0;
std::vector<std::string> just_export_files_;
/// For write sol
std::vector<std::string> export_sol_files_;
Expand Down Expand Up @@ -936,12 +939,22 @@ class StdBackend :
}

if (IMPL_HAS_STD_FEATURE(WRITE_PROBLEM)) {
AddListOption("tech:writemodel writeprob writemodel tech:exportfile",
AddListOption("tech:writemodel tech:writeprob writeprob writemodel tech:exportfile",
"Specifies files where to export the model before "
"solving (repeat the option for several files.) "
"File name extensions can be ``.lp[.7z]``, ``.mps``, etc.",
"File name extensions can be ``.lp[.7z]``, ``.mps``, etc."
"\n"
"To write a model during iterative solve (e.g., with obj:multi=2), "
"use tech:writemodel:index.",
storedOptions_.export_files_);

AddStoredOption("tech:writemodel:index tech:writeprob:index writeprobindex writemodelindex",
"During iterative solve (e.g., with obj:multi=2), "
"the iteration before which to write solver model. "
"0 means before iteration is initialized; positive value - "
"before solving that iteration. Default 0.",
storedOptions_.writemodel_index_);

AddListOption("tech:writemodelonly justwriteprob justwritemodel",
"Specifies files where to export the model, no solving "
"(option can be repeated.) "
Expand Down
21 changes: 13 additions & 8 deletions include/mp/flat/constr_2_expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,9 @@ class Constraints2Expr {
bool ConvertWithExpressions(
const ComplementarityConstraint<Expr>& con,
int i,
ConstraintAcceptanceLevel , ExpressionAcceptanceLevel ) { // TODO check acc for NLCompl
if (1==stage_cvt2expr_
ConstraintAcceptanceLevel , ExpressionAcceptanceLevel ) {
if (false // TODO check acc for NLCompl
&& 1==stage_cvt2expr_
&& !con.GetExpression().is_variable()) { // already a variable
ConvertComplementarityExpr(con, i);
return true;
Expand Down Expand Up @@ -353,11 +354,11 @@ class Constraints2Expr {
pre::AutoLinkScope<Impl> auto_link_scope{ *(Impl*)this, obj_src };
if (qobj.GetQPTerms().empty())
exprResVar = MPD( AssignResultVar2Args(
LinearFunctionalConstraint{ {lt_in_expr, 1.0} } ) );
LinearFunctionalConstraint{ {lt_in_expr, 0.0} } ) );
else // Move QP terms into the expr
exprResVar = MPD( AssignResultVar2Args(
QuadraticFunctionalConstraint
{ {{lt_in_expr, std::move(qobj.GetQPTerms())}, 1.0} } ) );
{ {{lt_in_expr, std::move(qobj.GetQPTerms())}, 0.0} } ) );
MPD( AddInitExprContext(exprResVar, // Context is compulsory
obj::MAX==qobj.obj_sense_true() // no need to propagate
? Context::CTX_POS : Context::CTX_NEG) );
Expand Down Expand Up @@ -415,11 +416,15 @@ class Constraints2Expr {
lt_out_vars.reserve(nvars);
result.reserve(ltin.size() - nvars);
int v=0;
double c=0.0;
for (size_t i=0; i<ltin.size(); ++i) {
if (MPCD( IsProperVar(v = ltin.var(i)) )) {
lt_out_vars.add_term(ltin.coef(i), v);
} else
result.add_term(ltin.coef(i), v);
if ((c = ltin.coef(i))) { // non-0
if (MPCD( IsProperVar(v = ltin.var(i)) )) {
lt_out_vars.add_term(c, v);
} else {
result.add_term(c, v);
}
}
}
return result;
}
Expand Down
2 changes: 1 addition & 1 deletion include/mp/flat/constr_prop_down.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class ConstraintPropagatorsDown {
template <class ExprBody>
void PropagateResult(ComplementarityConstraint<ExprBody>& con,
double lb, double ub, Context ctx) {
internal::Unused(lb, ub, ctx);
internal::Unused(ctx);
MPD( PropagateResult2Args(con.GetExpression().GetBody(),
lb, ub, Context::CTX_MIX) );
MPD( PropagateResultOfInitExpr(con.GetVariable(), lb, ub, Context::CTX_MIX) );
Expand Down
4 changes: 3 additions & 1 deletion include/mp/flat/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,13 @@ class FlatConverter :
constr_depth_ = 1; // Workaround. TODO have maps as special constraints
MP_DISPATCH( ConvertMaps() );
MP_DISPATCH( PreprocessFlatFinal() ); // final flat model prepro
MP_DISPATCH( ConsiderEmulatingMultiobj() );
if constexpr (IfAcceptingNLOutput()) {
if (IfWantNLOutput()) {
MPD( Convert2NL() );
MPD( PreprocessNLFinal() );
}
}
MP_DISPATCH( ConsiderEmulatingMultiobj() ); // After NL conversion
} catch (const ConstraintConversionFailure& cff) {
MP_RAISE(cff.message());
}
Expand Down Expand Up @@ -310,6 +310,7 @@ class FlatConverter :
/// if provided (>=0)
int AcceptanceLevelCommon() const { return options_.accAll_; }

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

Expand All @@ -322,6 +323,7 @@ class FlatConverter :
ExpressionAcceptanceLevel::Recommended
== ModelAPI::ExpressionInterfaceAcceptanceLevel(); }

protected:
/// Finish exporting the reformulation graph
void CloseGraphExporter() {
value_presolver_.FinishExportingLinkEntries();
Expand Down
2 changes: 1 addition & 1 deletion include/mp/flat/converter_multiobj.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class MOManager {
const auto& i0_vec = pr_level.second;
obj_new_.push_back(obj_orig.at(i0_vec.front()));
obj_new_.back().set_sense(obj_orig.front().obj_sense()); // "Legacy" obj:multi:weight
obj_new_.back().set_sense_true(obj_orig.front().obj_sense());
obj_new_.back().set_sense_true(obj_orig.front().obj_sense_true());
obj_new_.back().GetLinTerms() *= objwgt.at(i0_vec.front()); // Use weight
obj_new_.back().GetQPTerms() *= objwgt.at(i0_vec.front());
obj_new_tola_.push_back(objtola.at(i0_vec.front()));
Expand Down
21 changes: 16 additions & 5 deletions include/mp/flat/sol_check.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class SolutionChecker {
try { // protect
std::vector<double> x_back = x;
if (MPCD( sol_check_mode() ) & (1+2+4+8+16)) {
if (MPCD( IfWantNLOutput() ))
x = RecomputeAuxVars(x, true); // Compute expressions
msgreal = DoCheckSol(x, duals, obj, {}, x_back, false);
}
if (MPCD( sol_check_mode() ) & (32+64+128+256+512)) {
Expand Down Expand Up @@ -64,8 +66,9 @@ class SolutionChecker {
// a summary in the final solve message.
// For now, do this via warnings?
if (MPCD( sol_check_fail() ))
MP_RAISE_WITH_CODE(int(sol::MP_SOLUTION_CHECK), // failure
warn);
MP_RAISE_WITH_CODE(int(sol::MP_SOLUTION_CHECK),
"Solution check failed - reporting as fatal:\n"
+ warn);
else
MPD( AddWarning(
MPD( GetEnv() ).GetSolCheckWarningKey(true),
Expand Down Expand Up @@ -108,7 +111,9 @@ class SolutionChecker {
};

/// Recompute auxiliary variables
ArrayRef<double> RecomputeAuxVars(ArrayRef<double> x) {
/// @param fExprOnly: only NL expressions
ArrayRef<double> RecomputeAuxVars(
ArrayRef<double> x, bool fExprOnly=false) {
VarInfoRecomp vir {
MPCD( sol_feas_tol() ),
true, // currently not relevant for recomputation
Expand All @@ -120,8 +125,14 @@ class SolutionChecker {
MPCD( sol_round() ), MPCD( sol_prec() )
};
vir.get_x().set_p_var_info(&vir);
for (auto i=vir.size(); i--; )
vir[i]; // touch the variable to be recomputed
if (fExprOnly) {
for (auto i=vir.size(); i--; )
if ( !MPCD( IsProperVar(i) ) )
vir[i]; // touch the variable to be recomputed
} else {
for (auto i=vir.size(); i--; )
vir[i];
}
return std::move(vir.get_x().get_x());
}

Expand Down
8 changes: 8 additions & 0 deletions solvers/scipmp/CHANGES.scipmp.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ Summary of recent updates to SCIP for AMPL
==========================================


## unreleased
- MINLP expression trees (option acc:_expr.)
- Using the expression tree API, available since SCIP v8,
to model nonlinear expressions. Earlier the expressions
were submitted to the solver in a flat form equating
an auxiliary variable to each expression.


## 20240724
- Option *acc:_all*
- Useful to disable all reformulations (acc:_all=2),
Expand Down
11 changes: 3 additions & 8 deletions solvers/scipmp/scipmpbackend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,6 @@ void ScipBackend::SetInterrupter(mp::Interrupter *inter) {
}

void ScipBackend::Solve() {
if (!storedOptions_.exportFile_.empty())
ExportModel(storedOptions_.exportFile_);
if (!storedOptions_.paramRead_.empty())
SCIP_CCALL( SCIPreadParams(getSCIP(), storedOptions_.paramRead_.c_str()) );
if (!storedOptions_.logFile_.empty())
Expand Down Expand Up @@ -368,12 +366,6 @@ void ScipBackend::InitCustomOptions() {
"0*/1/2/3/4/5: Whether to write SCIP log lines (chatter) to stdout and to file (native output level of SCIP).",
"display/verblevel", 0, 5);

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_);

AddStoredOption("tech:logfile logfile",
"Log file name.",
storedOptions_.logFile_);
Expand Down Expand Up @@ -963,6 +955,9 @@ void ScipBackend::AddMIPStart(ArrayRef<double> x0, ArrayRef<int> sparsity) {
SCIP_CCALL( SCIPaddSolFree(getSCIP(), &solution, &keep) );
}

void ScipBackend::DoWriteProblem(const std::string& name) {
ExportModel(name);
}

} // namespace mp

Expand Down
8 changes: 7 additions & 1 deletion solvers/scipmp/scipmpbackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ class ScipBackend :
void AddMIPStart(ArrayRef<double> x0,
ArrayRef<int> sparsity) override;

/**
* EXPORT PROBLEM
**/
ALLOW_STD_FEATURE(WRITE_PROBLEM, true)
void DoWriteProblem(const std::string& name) override;


/**
* Get MIP Gap
Expand Down Expand Up @@ -157,7 +163,7 @@ class ScipBackend :
private:
/// These options are stored in the class
struct Options {
std::string exportFile_, logFile_, paramRead_;
std::string logFile_, paramRead_;
int concurrent_ = 0;
int heuristics_ = 0;
int cuts_ = 0;
Expand Down
14 changes: 14 additions & 0 deletions test/end2end/cases/categorized/fast/multi_obj/modellist.json
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,20 @@
"_sobj[2]": -17
}
},
{
"name" : "obj_abs_01 obj:multi=2 writeprobindex",
"tags" : ["linear", "integer", "multiobj"],
"options": {
"ANYSOLVER_options": "multiobj=2 writeprob=obj_abs_01.lp writeprobindex=2",
"scip_options": "multiobj=2 writeprob=obj_abs_01.cip writeprobindex=2",
"gcg_options": "multiobj=2 writeprob=obj_abs_01.lp writeprobindex=2",
"mosek_options": "multiobj=2 writeprob=obj_abs_01.jtask writeprobindex=2"
},
"values": {
"_sobj[1]": 13,
"_sobj[2]": -17
}
},
{
"name" : "obj_abs_02",
"tags" : ["linear", "integer", "multiobj"],
Expand Down

0 comments on commit c2c2954

Please sign in to comment.