Skip to content

Commit d25ae47

Browse files
committed
Check redefinition context #248
1 parent f429c1e commit d25ae47

25 files changed

+111
-46
lines changed

include/mp/flat/constr_functional.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ class QuadraticFunctionalConstraint :
288288
/// add respective static constraint to a converter.
289289
/// Use >=< depending on context.
290290
template <class Converter>
291-
void AddQuadraticConstraint(Converter& cvt) const {
291+
Context AddQuadraticConstraint(Converter& cvt) const {
292292
auto le = GetQuadExpr().GetLinTerms();
293293
le.add_term(-1.0, FunctionalConstraint::GetResultVar());
294294
auto qt = GetQuadExpr().GetQPTerms();
@@ -303,6 +303,7 @@ class QuadraticFunctionalConstraint :
303303
-GetQuadExpr().constant_term() } );
304304
else
305305
MP_RAISE("QuadraticFuncCon: no context");
306+
return GetContext();
306307
}
307308
};
308309

include/mp/flat/constr_keeper.h

+30-5
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,24 @@ class ConstraintKeeper final
114114
int i,
115115
double lb, double ub, Context ctx) override {
116116
try {
117+
// Too strong: instead, differentiate context
118+
// in which the redefinition happened #248.
119+
// MP_ASSERT_ALWAYS(!GetContext(i).IsProperSubsetOf(ctx)
120+
// || IsBridgingToBeConsidered(i),
121+
auto ctx_redef = cons_[i].GetRedefContext();
122+
MP_ASSERT_ALWAYS(ctx_redef.IsNone()
123+
|| ctx.IsSubsetOf(ctx_redef),
124+
"Part of expression redefinition\n"
125+
"could be lost. Please contact\n"
126+
"AMPL customer support.");
117127
static_cast<Converter&>(cvt).PropagateResult(
118128
GetConstraint(i), lb, ub, ctx);
119129
} catch (const std::exception& exc) {
120130
MP_RAISE(Converter::GetTypeName() +
121131
std::string(": propagating result for constraint ") +
122132
std::to_string(i) + " of type '" +
123133
Constraint::GetTypeName() +
124-
"': " + exc.what());
134+
"':\n" + exc.what());
125135
}
126136
}
127137

@@ -328,6 +338,15 @@ class ConstraintKeeper final
328338
/// Mark as added
329339
void MarkExprAdded() { is_expr_stored_=true; }
330340

341+
/// Context used for redefinition.
342+
/// We redefine just once currently #248.
343+
Context GetRedefContext() const { return ctx_redef_; }
344+
/// Set redef context
345+
void SetRedefContext(Context ctx) {
346+
assert(!ctx.IsNone());
347+
ctx_redef_ = ctx;
348+
}
349+
331350
/// Get the flat constraint, const &
332351
const Constraint& GetCon() const { return con_.GetFlatConstraint(); }
333352
/// Get the flat constraint &
@@ -343,9 +362,10 @@ class ConstraintKeeper final
343362
// so we can send (wrapper &) to ModelAPI::AddExpression().
344363
FlatExprType con_;
345364
int depth_ = 0;
346-
bool is_bridged_ = false;
347-
bool is_unused_ = false;
348-
bool is_expr_stored_ = false;
365+
Context ctx_redef_; // Context used for redefinition, if any
366+
char is_bridged_ = false;
367+
char is_unused_ = false;
368+
char is_expr_stored_ = false;
349369
};
350370

351371
/// Convert all new constraints of this type
@@ -450,7 +470,12 @@ class ConstraintKeeper final
450470
/// @param i constraint index, needed for bridging
451471
void ConvertConstraint(Container& cnt, int i) {
452472
assert(!cnt.IsRedundant());
453-
GetConverter().RunConversion(cnt.GetCon(), i, cnt.GetDepth());
473+
assert(cnt.GetRedefContext().IsNone());
474+
auto ctx_redef
475+
= GetConverter().RunConversion(cnt.GetCon(), i, cnt.GetDepth());
476+
cnt.SetRedefContext(ctx_redef);
477+
assert(!cnt.GetCon().HasResultVar()
478+
|| cnt.GetCon().GetContext().IsSubsetOf(ctx_redef));
454479
MarkAsBridged(cnt, i);
455480
}
456481

include/mp/flat/context.h

+9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ class Context {
2323
/// Is CTX_NONE?
2424
bool IsNone() const { return CTX_NONE==value_; }
2525

26+
/// Is a subset of or equal to \a other?
27+
bool IsSubsetOf(Context other) const {
28+
return
29+
IsProperSubsetOf(other) || *this==other;
30+
}
31+
2632
/// Is a proper subset of \a other?
2733
bool IsProperSubsetOf(Context other) const {
2834
return
@@ -55,6 +61,9 @@ class Context {
5561
/// Get value
5662
CtxVal GetValue() const { return value_; }
5763

64+
/// Equal
65+
bool operator==(Context ctx) const { return value_==ctx.value_; }
66+
5867
/// Positivize
5968
Context operator+() {
6069
switch (value_) {

include/mp/flat/converter.h

+16-11
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ class FlatConverter :
216216
MP_ASSERT_ALWAYS(!IsUnused(GetInitExpression(v))
217217
|| IsBridgingToBeConsidered(GetInitExpression(v)),
218218
"An expression's redefinition\n"
219-
"is about to be lost. Contact\n"
219+
"could be lost. Please contact\n"
220220
"AMPL customer support.");
221221
}
222222

@@ -365,10 +365,11 @@ class FlatConverter :
365365
public: // for ConstraintKeeper
366366
/// RunConversion() of a constraint in the flat phase:
367367
/// Assume mixed context if not set.
368+
/// @return Context used for redefinition
368369
/// @note Do not use directly. Call via
369370
/// ConstraintKeeper.ConvertConstraint().
370371
template <class Constraint>
371-
void RunConversion(const Constraint& con, int i, int depth) {
372+
Context RunConversion(const Constraint& con, int i, int depth) {
372373
assert(
373374
!GET_CONSTRAINT_KEEPER(Constraint).IsRedundant(i));
374375
constr_depth_ = depth+1;
@@ -379,7 +380,7 @@ class FlatConverter :
379380
*static_cast<Impl*>(this),
380381
GET_CONSTRAINT_KEEPER(Constraint).SelectValueNodeRange(i)
381382
};
382-
MP_DISPATCH(Convert(con, i));
383+
return MP_DISPATCH(Convert(con, i));
383384
}
384385

385386
/// Query if a constraint type
@@ -528,36 +529,39 @@ class FlatConverter :
528529
///
529530
/// New way is to use the \a i parameter for bridging
530531
template <class Constraint>
531-
void Convert(const Constraint& con, int ) {
532-
MPD( Convert(con) );
532+
Context Convert(const Constraint& con, int ) {
533+
return MPD( Convert(con) );
533534
}
534535

535-
/// By default, we complain about someone trying to convert an unknown constraint
536+
/// By default, we complain about someone trying to
537+
/// convert an unknown constraint
536538
template <class Constraint>
537-
void Convert(const Constraint& ) {
539+
Context Convert(const Constraint& ) {
538540
MP_RAISE(
539541
std::string("Constraint type '") +
540542
Constraint::GetTypeName() +
541543
"' is neither accepted by '" +
542544
ModelAPI::GetTypeName() +
543545
"', nor is conversion implemented");
546+
return Context::CTX_NONE;
544547
}
545548

546549
//////////////////////////// SOME SPECIFIC CONSTRAINT CONVERTERS
547550
/// ///////////////////////////////////// ///////////////////////////
548551

549552
/// If backend does not like LFC, we redefine it here
550-
void Convert(const LinearFunctionalConstraint& ldc) {
553+
Context Convert(const LinearFunctionalConstraint& ldc) {
551554
MPD( AddConstraint(ldc.to_linear_constraint()) );
555+
return Context::CTX_MIX;
552556
}
553557
/// Say we can (for acc:_all=0)
554558
bool IfHasCvt_impl(const LinearFunctionalConstraint* ) {
555559
return true;
556560
}
557561

558562
/// If backend does not like QFC, we redefine it
559-
void Convert(const QuadraticFunctionalConstraint& qdc) {
560-
qdc.AddQuadraticConstraint(*(Impl*)this);
563+
Context Convert(const QuadraticFunctionalConstraint& qdc) {
564+
return qdc.AddQuadraticConstraint(*(Impl*)this);
561565
}
562566
/// Say we can
563567
bool IfHasCvt_impl(const QuadraticFunctionalConstraint* ) {
@@ -1738,7 +1742,8 @@ class FlatConverter :
17381742
STORE_CONSTRAINT_TYPE__NO_MAP(
17391743
UnaryEncodingConstraint, "acc:uenc")
17401744
/// Dummy conversion for UEncConstr
1741-
void Convert(const UnaryEncodingConstraint& ) { }
1745+
Context Convert(const UnaryEncodingConstraint& )
1746+
{ return Context::CTX_ROOT; }
17421747
/// Say we can (for acc:_all=0)
17431748
bool IfHasCvt_impl(const UnaryEncodingConstraint* ) {
17441749
return true;

include/mp/flat/redef/MIP/complement.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class ComplementarityConverter_MIP :
2727
using ItemType = ComplCon;
2828

2929
/// Convert in any context
30-
void Convert(const ItemType& cc, int ) {
30+
Context Convert(const ItemType& cc, int ) {
3131
const auto& expr = cc.GetExpression();
3232
auto compl_var = cc.GetVariable();
3333

@@ -100,6 +100,7 @@ class ComplementarityConverter_MIP :
100100
GetMC().FixAsTrue(res4);
101101
/// Not adding any static algebraic constraint
102102
}
103+
return Context::CTX_ROOT;
103104
}
104105

105106
/// Reuse the stored ModelConverter

include/mp/flat/redef/MIP/count.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class CountConverter_MIP :
2121
using ItemType = CountConstraint;
2222

2323
/// Convert in any context
24-
void Convert(const ItemType& cc, int ) {
24+
Context Convert(const ItemType& cc, int ) {
2525
const auto& args = cc.GetArguments();
2626
std::vector<double> coefs(args.size()+1, 1.0);
2727
coefs.back() = -1.0;
@@ -37,6 +37,7 @@ class CountConverter_MIP :
3737
}
3838
}
3939
GetMC().AddConstraint_AS_ROOT( LinConEQ( {coefs, flags}, 0.0 ) );
40+
return Context::CTX_MIX;
4041
}
4142

4243
/// Reuse the stored ModelConverter

include/mp/flat/redef/MIP/div.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ class DivConverter_MIP :
2828
}
2929

3030
/// Convert in both contexts (full reification)
31-
void Convert(const ItemType& dc, int ) {
31+
Context Convert(const ItemType& dc, int ) {
3232
if (GetMC().is_fixed(dc.GetResultVar()))
3333
ConvertWithConstResult(dc);
3434
else if (GetMC().is_fixed(dc.GetArguments()[1]))
3535
ConvertWithConstDivisor(dc);
3636
else
3737
ConvertWithNonConstDivisor(dc);
38+
return Context::CTX_MIX;
3839
}
3940

4041

include/mp/flat/redef/MIP/ifthenelse.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ class IfThenElseConverter_MIP :
2121
using ItemType = IfThenConstraint;
2222

2323
/// Convert in any context
24-
void Convert(const ItemType& itc, int ) {
24+
Context Convert(const ItemType& itc, int ) {
2525
assert(!itc.GetContext().IsNone());
2626
const auto& args = itc.GetArguments();
2727
if (!GetMC().is_fixed(args[1]) || !GetMC().is_fixed(args[2]))
2828
ConvertIfThen_variableThenElse(itc);
2929
else
3030
ConvertIfThen_constantThenElse(itc);
31+
return Context::CTX_MIX;
3132
}
3233

3334
protected:

include/mp/flat/redef/MIP/impl.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class ImplicationConverter_MIP :
2626
using ItemType = ImplicationConstraint;
2727

2828
/// Convert in any context
29-
void Convert(const ItemType& cc, int ) {
29+
Context Convert(const ItemType& cc, int ) {
3030
const auto& args = cc.GetArguments();
3131
auto compl_arg0 = GetMC().MakeComplementVar(args[0]);
3232
/// args[0] ==> args[1]
@@ -45,6 +45,7 @@ class ImplicationConverter_MIP :
4545
GetMC().PropagateResultOfInitExpr(
4646
cc.GetResultVar(), cc.GetContext());
4747
}
48+
return Context::CTX_MIX;
4849
}
4950

5051

include/mp/flat/redef/MIP/indicator_eq.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class IndicatorLinEQConverter_MIP :
1919
using ItemType = IndicatorConstraintLinEQ;
2020

2121
/// Conversion
22-
void Convert(const ItemType& indc, int ) {
22+
Context Convert(const ItemType& indc, int ) {
2323
auto binvar=indc.get_binary_var();
2424
auto bnds = GetMC().ComputeBoundsAndType(
2525
indc.get_constraint().GetBody());
@@ -34,6 +34,7 @@ class IndicatorLinEQConverter_MIP :
3434
bnds.NegateBounds();
3535
ConvertImplicationLE(binvar, indc.get_binary_value(),
3636
bnds.ub(), std::move(con));
37+
return Context::CTX_ROOT;
3738
}
3839

3940
protected:

include/mp/flat/redef/MIP/indicator_ge.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ class IndicatorLinGEConverter_MIP :
2020
using ItemType = IndicatorConstraintLinGE;
2121

2222
/// Conversion
23-
void Convert(const ItemType& indc, int ) {
23+
Context Convert(const ItemType& indc, int ) {
2424
auto binvar=indc.get_binary_var();
2525
auto bnds = GetMC().ComputeBoundsAndType(
2626
indc.get_constraint().GetBody());
2727
ConvertImplicationGE(binvar, indc.get_binary_value(),
2828
bnds.lb(), indc.get_constraint());
29+
return Context::CTX_ROOT;
2930
}
3031

3132
protected:

include/mp/flat/redef/MIP/indicator_le.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ class IndicatorLinLEConverter_MIP :
2020
using ItemType = IndicatorConstraintLinLE;
2121

2222
/// Conversion
23-
void Convert(const ItemType& indc, int ) {
23+
Context Convert(const ItemType& indc, int ) {
2424
auto binvar=indc.get_binary_var();
2525
auto bnds = GetMC().ComputeBoundsAndType(
2626
indc.get_constraint().GetBody());
2727
ConvertImplicationLE(binvar, indc.get_binary_value(),
2828
bnds.ub(), indc.get_constraint());
29+
return Context::CTX_ROOT;
2930
}
3031

3132
protected:

include/mp/flat/redef/MIP/indicator_quad.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class IndicatorQuadConverter_MIP :
3333

3434
/// Conversion.
3535
/// Substitute constraint body by a new variable.
36-
void Convert(const ItemType& indc, int ) {
36+
Context Convert(const ItemType& indc, int ) {
3737
auto binvar=indc.get_binary_var();
3838
const auto& body = indc.get_constraint().GetBody();
3939
assert(body.is_quadratic());
@@ -42,6 +42,7 @@ class IndicatorQuadConverter_MIP :
4242
GetMC().AddConstraint( IndicatorLin{binvar, indc.get_binary_value(),
4343
LinCon{ { {1.0}, {auxvar} },
4444
indc.get_constraint().rhs() }} );
45+
return Context::CTX_ROOT;
4546
}
4647

4748
protected:

include/mp/flat/redef/MIP/lin_approx.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class FuncConConverter_MIP_CRTP :
4242
using ItemType = FuncCon;
4343

4444
/// Convert in any context
45-
void Convert(const ItemType& con, int ) {
45+
Context Convert(const ItemType& con, int ) {
4646
assert(!con.GetContext().IsNone());
4747
assert(1==con.GetArguments().size()); // 1 argument var
4848
auto x = con.GetArguments()[0];
@@ -103,6 +103,7 @@ class FuncConConverter_MIP_CRTP :
103103
{int(factor), int(rmd), x} },
104104
{0.0} } );
105105
}
106+
return Context::CTX_MIX;
106107
}
107108

108109

include/mp/flat/redef/MIP/logical_not.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@ class NotConverter_MIP :
2121
using ItemType = NotConstraint;
2222

2323
/// Convert in both contexts (full reification)
24-
void Convert(const ItemType& nc, int ) {
24+
Context Convert(const ItemType& nc, int ) {
2525
if (GetMC().is_fixed(nc.GetResultVar())) { // fixed result?
2626
assert(GetMC().is_fixed(nc.GetArguments()[0])); // propagated down
2727
assert(GetMC().fixed_value(nc.GetResultVar())
2828
== 1.0 - GetMC().fixed_value(nc.GetArguments()[0]));
29-
return;
29+
return Context::CTX_MIX;
3030
}
3131
if (GetMC().is_fixed(nc.GetArguments()[0])) {
3232
auto resval = 1.0 - GetMC().fixed_value(nc.GetArguments()[0]);
3333
GetMC().NarrowVarBounds(nc.GetResultVar(), resval, resval);
34-
return;
34+
return Context::CTX_MIX;
3535
}
3636
LinearFunctionalConstraint funccon {{{{-1.0}, {nc.GetArguments()[0]}}, 1.0}};
3737
funccon.SetContext( GetMC().GetInitExprContext(nc.GetResultVar()) );
@@ -44,6 +44,7 @@ class NotConverter_MIP :
4444
// { {-1.0, 1.0},
4545
// {nc.GetResultVar(), var_res_lin} },
4646
// {0.0}});
47+
return Context::CTX_MIX;
4748
}
4849

4950
/// Reuse the stored ModelConverter

0 commit comments

Comments
 (0)