Skip to content

Commit

Permalink
Fix two presolve edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
arcondello committed Oct 19, 2022
1 parent 8a326eb commit 901e48d
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 8 deletions.
11 changes: 10 additions & 1 deletion dimod/include/dimod/presolve.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ class PreSolver {
// we haven't seen this variable before
model_.add_variable(model_.vartype(v), model_.lower_bound(v),
model_.upper_bound(v));

// equality constraint
model_.add_linear_constraint({v, out.first->second}, {1, -1}, Sense::EQ, 0);

postsolver_.add_variable(out.first->second);
}

Expand Down Expand Up @@ -230,7 +234,12 @@ void PreSolver<bias_type, index_type, assignment_type>::apply() {

if (constraint.num_variables() == 0) {
// remove after checking feasibity
throw std::logic_error("not implemented - infeasible");
if (constraint.offset() != constraint.rhs()) {
throw std::logic_error("infeasible");
}
model_.remove_constraint(c);
changes = true;
continue;
} else if (constraint.num_variables() == 1 && !constraint.is_soft()) {
index_type v = constraint.variables()[0];

Expand Down
2 changes: 1 addition & 1 deletion dimod/libcpp/presolve.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ cdef extern from "dimod/presolve.h" namespace "dimod::presolve" nogil:

PreSolver()
PreSolver(model_type)
void apply()
void apply() except+
void load_default_presolvers()

model_type& model()
Expand Down
41 changes: 35 additions & 6 deletions testscpp/tests/test_presolve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,24 +142,53 @@ SCENARIO("constrained quadratic models can be presolved") {
presolver.load_default_presolvers();
presolver.apply();

THEN("the self-loops are removed") {
THEN("the self-loops are removed and an equality is added") {
auto& model = presolver.model();

REQUIRE(model.num_variables() == 8);
REQUIRE(model.num_constraints() == 1);
REQUIRE(model.num_constraints() == 4);
CHECK(model.objective.num_interactions() == 2);
CHECK(model.objective.quadratic(0, 5) == 1.5);
CHECK(model.objective.quadratic(3, 6) == 3.5);

CHECK(model.constraint_ref(0).num_interactions() == 2);
CHECK(model.constraint_ref(0).quadratic(4, 7) == 5);
CHECK(model.constraint_ref(0).quadratic(3, 6) == 6);

// v0 == v0
CHECK(model.constraint_ref(1).num_variables() == 2);
CHECK(model.constraint_ref(1).is_linear());
CHECK(model.constraint_ref(1).variables() == std::vector<int>{0, 5});
CHECK(model.constraint_ref(1).linear(0) + model.constraint_ref(1).linear(5) == 0);
CHECK(model.constraint_ref(1).rhs() == 0);
CHECK(model.constraint_ref(1).sense() == Sense::EQ);
}

AND_WHEN("we then undo the transformation") {
auto original = presolver.postsolver().apply(std::vector<int>{1, 2, 3, 4, 5, 6, 7, 8});
CHECK(original == std::vector<int>{1, 2, 3, 4, 5});
}
AND_WHEN("we then undo the transformation") {
auto original =
presolver.postsolver().apply(std::vector<int>{1, 2, 3, 4, 5, 6, 7, 8});
CHECK(original == std::vector<int>{1, 2, 3, 4, 5});
}
}
}

GIVEN("a CQM with a constraint with no variables") {
auto cqm = ConstrainedQuadraticModel<double>();
cqm.add_variable(Vartype::BINARY);

// 5 == 5 constraint
auto& constraint = cqm.constraint_ref(cqm.add_constraint());
constraint.set_offset(5);
constraint.set_rhs(5);

WHEN("we presolve is applied") {
auto presolver = presolve::PreSolver<double>(std::move(cqm));
presolver.load_default_presolvers();
presolver.apply();

THEN("the constraint is removed") {
CHECK(cqm.num_constraints() == 0);
}
}
}

Expand Down

0 comments on commit 901e48d

Please sign in to comment.