diff --git a/include/mp/flat/constr_2_expr.h b/include/mp/flat/constr_2_expr.h index 3e7068f24..7ca688029 100644 --- a/include/mp/flat/constr_2_expr.h +++ b/include/mp/flat/constr_2_expr.h @@ -698,6 +698,7 @@ class Constraints2Expr { ck.ConvertConstraint(ie.GetIndex()); return true; } + return false; } diff --git a/include/mp/flat/redef/conic/cones.h b/include/mp/flat/redef/conic/cones.h index 063e5f59f..1e37758ee 100644 --- a/include/mp/flat/redef/conic/cones.h +++ b/include/mp/flat/redef/conic/cones.h @@ -386,8 +386,9 @@ class Convert1QC : public MCKeeper { if (auto lhs_args = CheckSqrtXnXmNonneg(lint.var(iX))) return ContinueRotatedSOC(lint, iX, iY, lhs_args, rhs_args); - return ContinueStdSOC(lint.coef(iX), lint.var(iX), - lint.coef(iY), rhs_args); + if (!rhs_args.is_from_abs_) // not x >= abs(...) + return ContinueStdSOC(lint.coef(iX), lint.var(iX), + lint.coef(iY), rhs_args); } } else if (1 == lint.size() && // const>=y. 0.0 >= rhs*sens && // either ... <= rhs @@ -396,9 +397,10 @@ class Convert1QC : public MCKeeper { // it's -k*sqrt(...) <= rhs(>0), k>0, // which is always true TODO if (auto rhs_args = CheckNorm2(lint.var(0))) { - return ContinueStdSOC(std::fabs(rhs), - int( MC().MakeFixedVar( 1.0 ) ), - lint.coef(0), rhs_args); + if (!rhs_args.is_from_abs_) // not const >= abs(...) + return ContinueStdSOC(std::fabs(rhs), + int( MC().MakeFixedVar( 1.0 ) ), + lint.coef(0), rhs_args); } } return false; @@ -407,6 +409,7 @@ class Convert1QC : public MCKeeper { /// Typedef for subexpression checkup result, /// whether it represents some part of an SOCP cone. struct ConeArgs { + bool is_from_abs_ {}; // No StdCone then std::vector coefs_; std::vector vars_; double const_term = 0.0; @@ -488,6 +491,7 @@ class Convert1QC : public MCKeeper { result.coefs_ = { 1.0 }; result.vars_ = { arg_abs }; result.res_vars_to_delete_ = { res_var }; + result.is_from_abs_ = true; return result; } diff --git a/test/end2end/cases/categorized/fast/conic/modellist.json b/test/end2end/cases/categorized/fast/conic/modellist.json index 5c144b832..a22387bb1 100644 --- a/test/end2end/cases/categorized/fast/conic/modellist.json +++ b/test/end2end/cases/categorized/fast/conic/modellist.json @@ -91,6 +91,14 @@ "solve_result_num": 0 } }, + { + "name" : "socp_13_abs_stdcone", + "tags" : ["socp"], + "objective" : -40, + "values": { + "solve_result_num": 0 + } + }, { "name" : "expcones_01__plain", "objective" : 0.7821882953, diff --git a/test/end2end/cases/categorized/fast/conic/socp_13_abs_stdcone.mod b/test/end2end/cases/categorized/fast/conic/socp_13_abs_stdcone.mod new file mode 100644 index 000000000..76cdc3e16 --- /dev/null +++ b/test/end2end/cases/categorized/fast/conic/socp_13_abs_stdcone.mod @@ -0,0 +1,17 @@ +#################################### +# Test that we don't convert abs(x) <= 5 into a cone +# TODO Also perform the actual test, now it's just for solving +#################################### + +var b1 binary; +var b2 binary; +var x >=-19 <=32; +var y >= -12 <= 5; + +minimize Obj: b1 - b2 - x + 3*y; + +var charge_diff = abs(x-y); + +s.t. Con: b1 && b2 ==> x<=y; + +s.t. Cone: charge_diff <= if b1>=1 then 5 else 15;