Skip to content

Commit d9233c3

Browse files
Enhance add_constraint method to return success status and implement inconsistency detection in unit tests
1 parent 157fe34 commit d9233c3

3 files changed

Lines changed: 66 additions & 7 deletions

File tree

include/linspire.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,9 @@ namespace linspire
161161
* the internal state of the solver to account for the new constraint.
162162
*
163163
* @param c The constraint to be added.
164+
* @return true if the constraint was successfully added; false if it leads to inconsistency.
164165
*/
165-
void add_constraint(const constraint &c) noexcept;
166+
[[nodiscard]] bool add_constraint(const constraint &c) noexcept;
166167

167168
/**
168169
* @brief Retracts a previously added constraint from the solver.

src/linspire.cpp

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "logging.hpp"
33
#include <algorithm>
44
#include <cassert>
5+
#include <unordered_map>
56

67
#ifdef LINSPIRE_ENABLE_LISTENERS
78
#define FIRE_ON_VALUE_CHANGED(var) \
@@ -119,12 +120,46 @@ namespace linspire
119120
}
120121
bool solver::new_gt(const utils::lin &lhs, const utils::lin &rhs, bool strict, std::optional<std::reference_wrapper<constraint>> reason) noexcept { return new_lt(rhs, lhs, strict, reason); }
121122

122-
void solver::add_constraint(const constraint &c) noexcept
123+
bool solver::add_constraint(const constraint &c) noexcept
123124
{
124-
for (const auto &[x, lb] : c.lbs)
125-
vars[x].set_lb(lb, c);
126-
for (const auto &[x, ub] : c.ubs)
127-
vars[x].set_ub(ub, c);
125+
struct staged_bounds
126+
{
127+
utils::inf_rational lb;
128+
utils::inf_rational ub;
129+
};
130+
std::unordered_map<utils::var, staged_bounds> staged;
131+
const auto ensure_entry = [this, &staged](const utils::var x) -> staged_bounds &
132+
{
133+
const auto it = staged.find(x);
134+
if (it != staged.end())
135+
return it->second;
136+
const auto [inserted_it, _] = staged.emplace(x, staged_bounds{lb(x), ub(x)});
137+
return inserted_it->second;
138+
};
139+
140+
for (const auto &[x, lb_val] : c.lbs)
141+
{
142+
auto &entry = ensure_entry(x);
143+
if (lb_val > entry.lb)
144+
entry.lb = lb_val;
145+
if (entry.lb > entry.ub)
146+
return false;
147+
}
148+
149+
for (const auto &[x, ub_val] : c.ubs)
150+
{
151+
auto &entry = ensure_entry(x);
152+
if (ub_val < entry.ub)
153+
entry.ub = ub_val;
154+
if (entry.lb > entry.ub)
155+
return false;
156+
}
157+
158+
for (const auto &[x, lb_val] : c.lbs)
159+
vars[x].set_lb(lb_val, c);
160+
for (const auto &[x, ub_val] : c.ubs)
161+
vars[x].set_ub(ub_val, c);
162+
return true;
128163
}
129164

130165
void solver::retract(const constraint &c) noexcept

tests/test_linspire.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,8 @@ void test_add_retract_readd_constraint()
215215
assert(s.ub(x) == utils::rational::positive_infinite);
216216

217217
// Add the same constraint again
218-
s.add_constraint(c0);
218+
bool added_again = s.add_constraint(c0);
219+
assert(added_again);
219220
cons = s.check();
220221
assert(cons);
221222
assert(s.lb(x) == 5);
@@ -270,6 +271,27 @@ void test_expression_bounds_and_match()
270271
assert(!s.match(expr_x, expr_far));
271272
}
272273

274+
void test_add_constraint_inconsistency_detection()
275+
{
276+
linspire::solver s;
277+
auto x = s.new_var();
278+
279+
linspire::constraint c_lb;
280+
bool lb_ok = s.new_gt({{x, 1}}, 5, false, c_lb);
281+
assert(lb_ok);
282+
s.retract(c_lb);
283+
284+
linspire::constraint c_ub;
285+
bool ub_ok = s.new_lt({{x, 1}}, 1, false, c_ub);
286+
assert(ub_ok);
287+
assert(s.check());
288+
289+
bool add_ok = s.add_constraint(c_lb);
290+
assert(!add_ok);
291+
assert(s.lb(x) == utils::rational::negative_infinite);
292+
assert(s.ub(x) == 1);
293+
}
294+
273295
int main()
274296
{
275297
test_basic_eq_and_lt();
@@ -281,6 +303,7 @@ int main()
281303
test_constant_inequality_strictness();
282304
test_slack_variable_reuse_for_duplicate_expression();
283305
test_expression_bounds_and_match();
306+
test_add_constraint_inconsistency_detection();
284307

285308
return 0;
286309
}

0 commit comments

Comments
 (0)