Skip to content

Commit

Permalink
MP2NL:logicalize alg expr #237
Browse files Browse the repository at this point in the history
When logical argument required but an algerbaic expression is given, write it as !=0
  • Loading branch information
glebbelov committed Oct 17, 2024
1 parent ea5d340 commit 9ee4223
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 45 deletions.
14 changes: 11 additions & 3 deletions include/mp/flat/constr_2_expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ class Constraints2Expr {
template <class RhsOrRange>
bool HandleLogicalArgs(
const AlgebraicConstraint<LinTerms, RhsOrRange>& con, int i) {
if (HandleLogicalArgs_SpecialCases(con, i))
if (false && HandleLogicalArgs_SpecialCases(con, i))
return true;
VisitArguments(con, MarkVarIfLogical_); // Mark as proper vars
return false; // don't remove immediately
Expand All @@ -395,10 +395,15 @@ class Constraints2Expr {
}

/// Special linear cases.
/// Not doing any more because these simplifications
/// interfere withg result variable marking.
/// These simplifications are general presolve
/// and should better have been done in normal conversion stage.
/// @todo atleast, atmost, exactly
template <class RhsOrRange>
bool HandleLogicalArgs_SpecialCases(
const AlgebraicConstraint<LinTerms, RhsOrRange>& con, int ) {
/*
const auto& body = con.GetBody();
if (!con.lb() && !con.ub() // == 0.0
&& 2==body.size()) { // 2 terms
Expand Down Expand Up @@ -433,14 +438,16 @@ class Constraints2Expr {
MPD( FixAsTrue(body.var(0)) );
return true;
}
}
} */
return false;
}

/// Convert algebraic con to a \a NLConstraint,
/// if \a NLConstraint's are accepted. Otherwise,
/// explicify the expression and convert to
/// \a LinConLE/EQ/GE/Range.
/// @return true iff the original constraint should be deleted.
/// @todo leave QCP terms here if accepted, even if other expr terms?
template <class Body, class RhsOrRange>
bool ConvertToNLCon(
const AlgebraicConstraint<Body, RhsOrRange>& con, int ) {
Expand Down Expand Up @@ -504,7 +511,8 @@ class Constraints2Expr {
LinTerms lt_varsonly;
LinTerms lt_in_expr = SplitLinTerms(qobj.GetLinTerms(), lt_varsonly);
// Have expression(s) or QP terms?
// Might need to hide them into the expression part
// Might need to hide them into the expression part.
// @todo leave QP terms here if accepted, even if other expr terms?
if (lt_in_expr.size()
|| (qobj.GetQPTerms().size()
&& (!MPCD(IfPassQuadObj()) // cannot or want not
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 @@ -32,7 +32,7 @@ class ConstraintPropagatorsDown {
Context ctx) {
MPD( NarrowVarBounds(con.GetResultVar(), lb, ub) );
con.AddContext(ctx);
PropagateResult2LinTerms(con.GetAffineExpr(),
PropagateResult2LinTerms(con.GetAffineExpr(), // @todo better in special cases
MPD( MinusInfty() ), MPD( Infty() ), +ctx);
}

Expand Down
29 changes: 26 additions & 3 deletions include/mp/flat/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,13 +374,23 @@ class FlatConverter :
}

/// Query if a constraint type
/// is natively accepted by the solver.
/// is natively accepted by the solver (and user).
/// The parameter is only needed for type.
template <class Con>
ConstraintAcceptanceLevel GetConstraintAcceptance(Con* ) const {
return GET_CONST_CONSTRAINT_KEEPER(Con).GetChosenAcceptanceLevel();
}

/// Query if an expression type
/// is natively accepted by the solver (and user).
/// The parameter is only needed for type.
template <class Con>
ExpressionAcceptanceLevel GetConstraintAcceptanceEXPR(
const ExprWrapper< Con >* ) const {
return GET_CONST_CONSTRAINT_KEEPER(Con).GetChosenAcceptanceLevelEXPR();
}


/// Query the number of addable constraints of type.
template <class Con>
int GetNumberOfAddable(Con* ) const {
Expand Down Expand Up @@ -448,19 +458,32 @@ class FlatConverter :
return false;
}

/// Check whether ModelAPI accepts and recommends the constraint
/// Check whether ModelAPI and user accept and recommend the constraint
template <class Constraint>
bool ModelAPIOk() const {
return ModelAPIAcceptsAndRecommends((const Constraint*)0);
}

/// Check whether ModelAPI accepts and recommends the constraint
/// Check whether ModelAPI and user accept and recommend the constraint
template <class Constraint>
bool ModelAPIAcceptsAndRecommends(const Constraint* pcon) const {
return ConstraintAcceptanceLevel::Recommended ==
GetConstraintAcceptance(pcon);
}

/// Check whether ModelAPI and user accept and recommend the expression
template <class Expression>
bool ModelAPIOkEXPR() const {
return ModelAPIAcceptsAndRecommendsEXPR((const Expression*)0);
}

/// Check whether ModelAPI and user accept and recommend the expression
template <class Expression>
bool ModelAPIAcceptsAndRecommendsEXPR(const Expression* pcon) const {
return ExpressionAcceptanceLevel::Recommended ==
GetConstraintAcceptanceEXPR(pcon);
}

/// Generic adapter for old non-bridged Convert() methods
///
/// New way is to use the \a i parameter for bridging
Expand Down
5 changes: 5 additions & 0 deletions include/mp/flat/nl_expr/model_api_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ class BasicExprModelAPI

/// NL model item accessors

/// @brief Is expression logical?
template <class FlatCon>
static bool IsLogical(const ExprWrapper<FlatCon>& expr)
{ return expr.GetFlatConstraint().IsLogical(); }

/// Get num linear terms
int GetLinSize(const NLConstraint& nlc) const {
return nlc.GetMainCon().size();
Expand Down
12 changes: 6 additions & 6 deletions include/mp/flat/prepro_prod.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class PreproProd
std::make_tuple< TermCmp, FlatExpr, std::pair<double, double> >(
{}, GetFlt().Visit(e), {}
);
terms_flt_.push_back(t);
terms_flt_.push_back( std::move(t) );
}

protected:
Expand Down Expand Up @@ -88,7 +88,7 @@ class PreproProd
is_int ? 2 : 3;
std::get<0>(tpl) = {category, bnds.ub()-bnds.lb() };
std::get<2>(tpl) =
{bnds.lb(), bnds.ub() };
{bnds.lb(), bnds.ub()};
}
std::sort(terms_flt_.begin(), terms_flt_.end(),
[](const auto& tpl1, const auto& tpl2) {
Expand All @@ -115,7 +115,8 @@ class PreproProd
std::get<2>(terms_flt_[i]).second -
std::get<2>(terms_flt_[i]).first );
int binvar = GetFlt().Convert2Var(std::move(std::get<1>(terms_flt_[i])));
if (-1.0 == std::get<2>(terms_flt_[i]).first) { // negated binary
auto is_lb_minus1 = (-1.0 == std::get<2>(terms_flt_[i]).first);
if (is_lb_minus1) { // negated binary
coef00 *= -1;
binvar = GetFlt().Convert2Var( { {-1.0}, {binvar} } );
} else {
Expand All @@ -124,6 +125,7 @@ class PreproProd
args_forall.push_back( binvar );
}
result = GetFlt().AssignResult2Args( AndConstraint{args_forall} );
// Context should be set when adding the top contraint
}

result *= coef00;
Expand All @@ -146,9 +148,7 @@ class PreproProd
Flattener& flt_;
/// tuple: comparator, term, bounds
std::vector<
std::tuple< TermCmp, FlatExpr, std::pair<double, double> >

>
std::tuple< TermCmp, FlatExpr, std::pair<double, double> > >
terms_flt_;
int n_terms_const_ = 0;
int n_terms_binary_ = 0;
Expand Down
75 changes: 49 additions & 26 deletions solvers/mp2nl/mp2nlmodelapi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ void MP2NLModelAPI::AddVariables(const VarArrayDef& vad) {

void MP2NLModelAPI::SetLinearObjective( int iobj, const LinearObjective& lo ) {
assert(iobj == (int)obj_info_.size());
obj_info_.push_back(MakeItemInfo(lo, StaticItemTypeID::ID_LinearObjective));
obj_info_.push_back(
MakeItemInfo(lo, StaticItemTypeID::ID_LinearObjective, false));
}

void MP2NLModelAPI::SetQuadraticObjective(int iobj, const QuadraticObjective& qo) {
Expand All @@ -52,21 +53,22 @@ void MP2NLModelAPI::SetQuadraticObjective(int iobj, const QuadraticObjective& qo

void MP2NLModelAPI::SetNLObjective( int iobj, const NLObjective& nlo ) {
assert(iobj == (int)obj_info_.size());
obj_info_.push_back(MakeItemInfo(nlo, StaticItemTypeID::ID_NLObjective));
obj_info_.push_back(MakeItemInfo(nlo, StaticItemTypeID::ID_NLObjective, false));
}


void MP2NLModelAPI::AddConstraint(const LinConRange& lc)
{ alg_con_info_.push_back(MakeItemInfo(lc, StaticItemTypeID::ID_LinConRange)); }
void MP2NLModelAPI::AddConstraint(const LinConRange& lc) {
alg_con_info_.push_back(MakeItemInfo(lc, StaticItemTypeID::ID_LinConRange, false));
}

void MP2NLModelAPI::AddConstraint(const LinConLE& lc)
{ alg_con_info_.push_back(MakeItemInfo(lc, StaticItemTypeID::ID_LinConLE)); }
{ alg_con_info_.push_back(MakeItemInfo(lc, StaticItemTypeID::ID_LinConLE, false)); }

void MP2NLModelAPI::AddConstraint(const LinConEQ& lc)
{ alg_con_info_.push_back(MakeItemInfo(lc, StaticItemTypeID::ID_LinConEQ)); }
{ alg_con_info_.push_back(MakeItemInfo(lc, StaticItemTypeID::ID_LinConEQ, false)); }

void MP2NLModelAPI::AddConstraint(const LinConGE& lc)
{ alg_con_info_.push_back(MakeItemInfo(lc, StaticItemTypeID::ID_LinConGE)); }
{ alg_con_info_.push_back(MakeItemInfo(lc, StaticItemTypeID::ID_LinConGE, false)); }


/// To access information from an NLConstraint,
Expand All @@ -76,43 +78,46 @@ void MP2NLModelAPI::AddConstraint(const LinConGE& lc)
///
/// Implementation follows partly reader_nl.cc from SCIP.
void MP2NLModelAPI::AddConstraint( const NLConstraint& nlc )
{ alg_con_info_.push_back(MakeItemInfo(nlc, StaticItemTypeID::ID_NLConstraint)); }
{ alg_con_info_.push_back(MakeItemInfo(nlc, StaticItemTypeID::ID_NLConstraint, false)); }

void MP2NLModelAPI::AddConstraint( const NLAssignEQ& nlae )
{ alg_con_info_.push_back(MakeItemInfo(nlae, StaticItemTypeID::ID_NLAssignEQ)); }
{ alg_con_info_.push_back(MakeItemInfo(nlae, StaticItemTypeID::ID_NLAssignEQ, false)); }
void MP2NLModelAPI::AddConstraint( const NLAssignLE& nlae )
{ alg_con_info_.push_back(MakeItemInfo(nlae, StaticItemTypeID::ID_NLAssignLE)); }
{ alg_con_info_.push_back(MakeItemInfo(nlae, StaticItemTypeID::ID_NLAssignLE, false)); }
void MP2NLModelAPI::AddConstraint( const NLAssignGE& nlae )
{ alg_con_info_.push_back(MakeItemInfo(nlae, StaticItemTypeID::ID_NLAssignGE)); }
{ alg_con_info_.push_back(MakeItemInfo(nlae, StaticItemTypeID::ID_NLAssignGE, false)); }

void MP2NLModelAPI::AddConstraint(const NLComplementarity& cc)
{ alg_con_info_.push_back(MakeItemInfo(cc, StaticItemTypeID::ID_NLComplementarity)); }
{ alg_con_info_.push_back(MakeItemInfo(cc, StaticItemTypeID::ID_NLComplementarity, false)); }


void MP2NLModelAPI::AddConstraint( const NLLogical& nll )
{ log_con_info_.push_back(MakeItemInfo(nll, StaticItemTypeID::ID_NLLogical)); }
{ log_con_info_.push_back(MakeItemInfo(nll, StaticItemTypeID::ID_NLLogical, true)); }

void MP2NLModelAPI::AddConstraint( const NLReifEquiv& nll )
{ log_con_info_.push_back(MakeItemInfo(nll, StaticItemTypeID::ID_NLReifEquiv)); }
{ log_con_info_.push_back(MakeItemInfo(nll, StaticItemTypeID::ID_NLReifEquiv, true)); }
void MP2NLModelAPI::AddConstraint( const NLReifImpl& nll )
{ log_con_info_.push_back(MakeItemInfo(nll, StaticItemTypeID::ID_NLReifImpl)); }
{ log_con_info_.push_back(MakeItemInfo(nll, StaticItemTypeID::ID_NLReifImpl, true)); }
void MP2NLModelAPI::AddConstraint( const NLReifRimpl& nll )
{ log_con_info_.push_back(MakeItemInfo(nll, StaticItemTypeID::ID_NLReifRimpl)); }
{ log_con_info_.push_back(MakeItemInfo(nll, StaticItemTypeID::ID_NLReifRimpl, true)); }


void MP2NLModelAPI::AddConstraint(const IndicatorConstraintLinLE &ic)
{ log_con_info_.push_back(MakeItemInfo(ic, StaticItemTypeID::ID_IndicatorConstraintLinLE)); }
{ log_con_info_.push_back(
MakeItemInfo(ic, StaticItemTypeID::ID_IndicatorConstraintLinLE, true)); }
void MP2NLModelAPI::AddConstraint(const IndicatorConstraintLinEQ &ic)
{ log_con_info_.push_back(MakeItemInfo(ic, StaticItemTypeID::ID_IndicatorConstraintLinEQ)); }
{ log_con_info_.push_back(
MakeItemInfo(ic, StaticItemTypeID::ID_IndicatorConstraintLinEQ, true)); }
void MP2NLModelAPI::AddConstraint(const IndicatorConstraintLinGE &ic)
{ log_con_info_.push_back(MakeItemInfo(ic, StaticItemTypeID::ID_IndicatorConstraintLinGE)); }
{ log_con_info_.push_back(
MakeItemInfo(ic, StaticItemTypeID::ID_IndicatorConstraintLinGE, true)); }



void MP2NLModelAPI::AddConstraint(const SOS1Constraint& sos)
{ sos_info_.push_back(MakeItemInfo(sos, StaticItemTypeID::ID_SOS1Constraint)); }
{ sos_info_.push_back(MakeItemInfo(sos, StaticItemTypeID::ID_SOS1Constraint, false)); }
void MP2NLModelAPI::AddConstraint(const SOS2Constraint& sos)
{ sos_info_.push_back(MakeItemInfo(sos, StaticItemTypeID::ID_SOS2Constraint)); }
{ sos_info_.push_back(MakeItemInfo(sos, StaticItemTypeID::ID_SOS2Constraint, false)); }


template <class Expr>
Expand All @@ -131,7 +136,12 @@ MP2NL_Expr MP2NLModelAPI::AddExpression(
template <class Expr>
MP2NL_Expr MP2NLModelAPI::StoreMP2NLExprID(
const Expr &expr, ExpressionTypeID eid) {
expr_info_.push_back(MakeItemInfo(expr, eid));
// std::printf(" Storing MP2NL_Expr[%ld]: type %s, logical = %d, @%p\n",
// expr_info_.size(),
// expr.GetFlatConstraint().GetTypeName(),
// IsLogical(expr), &expr);
expr_info_.push_back(
MakeItemInfo(expr, eid, IsLogical(expr)));
expr_counter_.push_back(0);
return MakeExprID( int(expr_info_.size()-1) );
}
Expand Down Expand Up @@ -835,6 +845,8 @@ void MP2NLModelAPI::FdArgs(
template <class MPExpr, class ArgWriter>
void MP2NLModelAPI::FdLogicArgs(
const MPExpr& e, ArgWriter ew_arg) {
// std::printf(" Feed '%s': %d args\n",
// GetItemName(e), GetNumArguments(e));
for (int i=0; i<GetNumArguments(e); ++i) {
FeedLogicalExpression(
GetArgExpression(e, i), ew_arg);
Expand All @@ -859,11 +871,22 @@ template <class ArgWriter>
void MP2NLModelAPI::FeedLogicalExpression(
MP2NL_Expr mp2nle, ArgWriter& aw) {
if (mp2nle.IsVariable()) {
auto arg2 = aw.OPut2(nl::EQ);
auto arg2 = aw.OPut2(nl::NE);
arg2.EPut(mp2nle);
arg2.NPut(1.0);
} else
aw.EPut(mp2nle);
arg2.NPut(0.0);
} else {
bool f_logical = false;
if (mp2nle.IsExpression()) {
f_logical
= expr_info_.at(mp2nle.GetExprIndex()).IsLogical();
}
if (!f_logical) {
auto argw = aw.OPut2(nl::NE);
argw.EPut(mp2nle);
argw.NPut(0.0);
} else
aw.EPut(mp2nle);
}
}

template <class ColSizeWriter>
Expand Down
18 changes: 12 additions & 6 deletions solvers/mp2nl/mp2nlmodelapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -1293,16 +1293,19 @@ class MP2NLModelAPI
class ItemInfo {
public:
/// Construct
ItemInfo (BasicItemDispatcher& disp, void* pitem
ItemInfo (BasicItemDispatcher& disp, void* pitem,
bool fLogical
//, StaticItemTypeID iid, ExpressionTypeID eid
)
: disp_(disp), p_item_(pitem)
: disp_(disp), p_item_(pitem), f_logical_(fLogical)
// no storing, itemID_(iid), exprID_(eid)
{ }
/// Get dispatcher
BasicItemDispatcher& GetDispatcher() const { return disp_; }
/// Get &item
void* GetPItem() const { return p_item_; }
/// Is logical?
bool IsLogical() const { return f_logical_; }
/// Is a static type?
bool IsItemTypeStatic() const
{ return GetDispatcher().IsItemTypeStatic(); }
Expand All @@ -1316,22 +1319,25 @@ class MP2NLModelAPI
private:
BasicItemDispatcher& disp_;
void* p_item_;
bool f_logical_ {};
// StaticItemTypeID itemID_ {StaticItemTypeID::ID_None};
// ExpressionTypeID exprID_ {ExpressionTypeID::ID_None};
};

/// Fill static item info
template <class Item>
ItemInfo MakeItemInfo(const Item& i, StaticItemTypeID ) {
return { GetItemDispatcher<Item>(), (void*)&i
ItemInfo MakeItemInfo(
const Item& i, StaticItemTypeID , bool fLogical) {
return { GetItemDispatcher<Item>(), (void*)&i, fLogical
// , sid, ExpressionTypeID::ID_None
};
}

/// Fill expression item info
template <class Item>
ItemInfo MakeItemInfo(const Item& i, ExpressionTypeID ) {
return { GetItemDispatcher<Item>(), (void*)&i
ItemInfo MakeItemInfo(
const Item& i, ExpressionTypeID , bool fLogical) {
return { GetItemDispatcher<Item>(), (void*)&i, fLogical
//, StaticItemTypeID::ID_None, eid
};
}
Expand Down

0 comments on commit 9ee4223

Please sign in to comment.