Skip to content

Commit 0c31533

Browse files
committed
Robust redef context #249
Restore context-unaware redef of !=, fixing redef in int_ne_05.mod Fix context check after redef
1 parent fc18c96 commit 0c31533

6 files changed

Lines changed: 47 additions & 14 deletions

File tree

include/mp/flat/constr_keeper.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,15 @@ class ConstraintKeeper final
8787
int GetConstraintDepth(int i) const
8888
{ assert(check_index(i)); return cons_[i].GetDepth(); }
8989

90-
/// Get context of contraint \a i
90+
/// Get context of constraint \a i
9191
Context GetContext(int i) const override
9292
{ assert(check_index(i)); return cons_[i].GetCon().GetContext(); }
9393

94-
/// Add context of contraint \a i
94+
/// Add context of constraint \a i
9595
void AddContext(int i, Context ctx) override
9696
{ assert(check_index(i)); cons_[i].GetCon().AddContext(ctx); }
9797

98-
/// Set context of contraint \a i
98+
/// Set context of constraint \a i
9999
void SetContext(int i, Context ctx) override
100100
{ assert(check_index(i)); cons_[i].GetCon().SetContext(ctx); }
101101

@@ -116,7 +116,7 @@ class ConstraintKeeper final
116116
try {
117117
// Too strong: instead, differentiate context
118118
// in which the redefinition happened #248.
119-
// MP_ASSERT_ALWAYS(!GetContext(i).IsProperSubsetOf(ctx)
119+
// MP_ASSERT_ALWAYS(ctx.IsSubsetOf(GetContext())
120120
// || IsBridgingToBeConsidered(i),
121121
auto ctx_redef = cons_[i].GetRedefContext();
122122
MP_ASSERT_ALWAYS(ctx_redef.IsNone()
@@ -129,7 +129,7 @@ class ConstraintKeeper final
129129
} catch (const std::exception& exc) {
130130
MP_RAISE(Converter::GetTypeName() +
131131
std::string(": propagating result for constraint ") +
132-
std::to_string(i) + " of type '" +
132+
std::to_string(i) + "\nof type '" +
133133
Constraint::GetTypeName() +
134134
"':\n" + exc.what());
135135
}

include/mp/flat/constr_prop_down.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ class ConstraintPropagatorsDown {
141141
void PropagateResult(OrConstraint& con, double lb, double ub, Context ctx) {
142142
MPD( NarrowVarBounds(con.GetResultVar(), lb, ub) );
143143
con.AddContext(ctx);
144-
if (ub<=0.5 && ctx.HasNegative()) { // Remove, arguments are fixed
144+
if (ub<0.5 && ctx.HasNegative()) { // Remove, arguments are fixed
145145
MPD( PropagateResult2Vars(con.GetArguments(), 0.0, ub, +ctx) );
146146
MPD( DecrementVarUsage(con.GetResultVar()) );
147147
} else

include/mp/flat/converter.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,10 @@ class FlatConverter :
9999
if (HasInitExpression(var)) {
100100
const auto& ckid = GetInitExpression(var);
101101
const auto ctx_old = ckid.GetCK()->GetContext(ckid.GetIndex());
102-
if (tighterBounds || ctx_old.IsProperSubsetOf(ctx))
102+
if (tighterBounds
103+
|| !ctx.IsSubsetOf(ctx_old)) { // new context
103104
ckid.GetCK()->PropagateResult(*this, ckid.GetIndex(), lb, ub, ctx);
105+
}
104106
}
105107
}
106108

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

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,16 @@ class CondEQConverter_MIP :
7676
} else if ( !GetMC().is_fixed(res) || // not fixed, or
7777
!GetMC().fixed_value(res) ) // fixed to 0
7878
{
79-
#ifndef USE_FLAT_ALGEBRA
8079
auto bNt = GetMC().ComputeBoundsAndType(con.GetBody());
8180
double cmpEps = GetMC().ComparisonEps( bNt.get_result_type() );
82-
/// res3 <==> (res || body <= rhs-eps || body >= rhs+eps)
81+
#define COND_LIN_EQ__USE_FLAT_ALGEBRA
82+
#ifndef COND_LIN_EQ__USE_FLAT_ALGEBRA
83+
// Not doing this.
84+
// Reason: the below OR propagates CTX+ into res,
85+
// which is the expression we are redefining,
86+
// but this is not necessary. See #248.
87+
// Happens on eqVarConst01.mod.
88+
/// res3 ==> (res || body <= rhs-eps || body >= rhs+eps)
8389
auto res3 = GetMC().AssignResultVar2Args(
8490
OrConstraint{ {
8591
res,
@@ -91,16 +97,19 @@ class CondEQConverter_MIP :
9197
{ { con.GetBody(), con.rhs() + cmpEps } })
9298
} });
9399
GetMC().FixAsTrue(res3);
94-
#else // USE_FLAT_ALGEBRA
95-
// Old way: straight to algebra and indicators
96-
auto con = eq0c.GetArguments();
100+
#else // COND_LIN_EQ__USE_FLAT_ALGEBRA
101+
// Old way: straight to algebra and indicators.
102+
// This could duplicate the below indicators,
103+
// but simpler as of now:
104+
// the indicators redefine conditional inequalities
105+
// which, in the above variant, could have been redefined
106+
// in CTX- before, see int_ne_05_redef_ctx.mod,
107+
// thus losing the CTX+ redefinition, see #248.
97108
auto newvars = GetMC().AddVars_returnIds(2, 0.0, 1.0, var::INTEGER);
98109
newvars.push_back( res );
99110
GetMC().AddConstraint( LinConGE( // b1+b2+resvar >= 1
100111
{{1.0, 1.0, 1.0}, newvars},
101112
1.0 ) );
102-
auto bNt = GetMC().ComputeBoundsAndType(con.GetBody());
103-
double cmpEps = GetMC().ComparisonEps( bNt.get_result_type() );
104113
{
105114
GetMC().AddConstraint(IndicatorConstraint< AlgCon<-1> >(
106115
newvars[0], 1,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# int_ne_05_ctx_redef.mod
2+
#
3+
# Test that x<=5 is redefined after all
4+
# its contexts are known
5+
6+
var x >=-3 <=11 integer;
7+
var b binary;
8+
var b1: binary;
9+
10+
minimize Obj: -10*b - 10*b1 + if x<=5 then 1;
11+
12+
s.t. ConNE_01: x != 6 <==> b;
13+
14+
s.t. ConImpl_01: b1 ==> x <= 6;

test/end2end/cases/categorized/fast/logical/modellist.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,14 @@
192192
"objective" : 1,
193193
"tags" : ["logical"]
194194
},
195+
{
196+
"name" : "int_ne_05_ctx_redef",
197+
"objective" : -19,
198+
"tags" : ["logical"],
199+
"values": {
200+
"if x<5.5 then 1": 1
201+
}
202+
},
195203
{
196204
"name" : "float_ne_01__vnec cvt:mip:eps",
197205
"options": {

0 commit comments

Comments
 (0)