Skip to content

Commit 680dad3

Browse files
Refactor constraint handling: replace std::optional<std::reference_wrapper<constraint>> with constraint* for improved clarity and consistency in method signatures.
1 parent 20fafc3 commit 680dad3

5 files changed

Lines changed: 47 additions & 47 deletions

File tree

include/linspire.hpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ namespace linspire
126126
* @param reason An optional constraint that serves as the reason for adding this new constraint.
127127
* @return true if the constraint was successfully added; false if it leads to inconsistency.
128128
*/
129-
[[nodiscard]] bool new_lt(const utils::lin &lhs, const utils::lin &rhs, bool strict = false, const std::optional<std::reference_wrapper<constraint>> &reason = std::nullopt) noexcept;
129+
[[nodiscard]] bool new_lt(const utils::lin &lhs, const utils::lin &rhs, bool strict = false, constraint *reason = nullptr) noexcept;
130130
/**
131131
* @brief Adds a new equality constraint to the solver.
132132
*
@@ -138,7 +138,7 @@ namespace linspire
138138
* @param reason An optional constraint that serves as the reason for adding this new equality constraint.
139139
* @return true if the equality constraint was successfully added; false if it leads to inconsistency.
140140
*/
141-
[[nodiscard]] bool new_eq(const utils::lin &lhs, const utils::lin &rhs, const std::optional<std::reference_wrapper<constraint>> &reason = std::nullopt) noexcept;
141+
[[nodiscard]] bool new_eq(const utils::lin &lhs, const utils::lin &rhs, constraint *reason = nullptr) noexcept;
142142
/**
143143
* @brief Adds a new greater-than or greater-than-or-equal-to constraint to the solver.
144144
*
@@ -152,7 +152,7 @@ namespace linspire
152152
* @param reason An optional constraint that serves as the reason for adding this new constraint.
153153
* @return true if the constraint was successfully added; false if it leads to inconsistency.
154154
*/
155-
[[nodiscard]] bool new_gt(const utils::lin &lhs, const utils::lin &rhs, bool strict = false, const std::optional<std::reference_wrapper<constraint>> &reason = std::nullopt) noexcept { return new_lt(rhs, lhs, strict, reason); }
155+
[[nodiscard]] bool new_gt(const utils::lin &lhs, const utils::lin &rhs, bool strict = false, constraint *reason = nullptr) noexcept { return new_lt(rhs, lhs, strict, reason); }
156156

157157
/**
158158
* @brief Retracts a previously added constraint from the solver.
@@ -185,7 +185,7 @@ namespace linspire
185185
*
186186
* @return A constant reference to the vector of constraints representing the last conflict explanation.
187187
*/
188-
[[nodiscard]] const std::vector<std::reference_wrapper<constraint>> &get_conflict() const noexcept { return cnfl; }
188+
[[nodiscard]] const std::vector<constraint *> &get_conflict() const noexcept { return cnfl; }
189189

190190
/**
191191
* @brief Checks if two linear expressions can be made equal.
@@ -226,8 +226,8 @@ namespace linspire
226226
private:
227227
[[nodiscard]] bool is_basic(const utils::var v) const noexcept { return tableau.count(v); }
228228

229-
[[nodiscard]] bool set_lb(const utils::var x_i, const utils::inf_rational &v, const std::optional<std::reference_wrapper<constraint>> &reason = std::nullopt) noexcept;
230-
[[nodiscard]] bool set_ub(const utils::var x_i, const utils::inf_rational &v, const std::optional<std::reference_wrapper<constraint>> &reason = std::nullopt) noexcept;
229+
[[nodiscard]] bool set_lb(const utils::var x_i, const utils::inf_rational &v, constraint *reason = nullptr) noexcept;
230+
[[nodiscard]] bool set_ub(const utils::var x_i, const utils::inf_rational &v, constraint *reason = nullptr) noexcept;
231231

232232
void update(const utils::var x_i, const utils::inf_rational &v) noexcept;
233233

@@ -237,11 +237,11 @@ namespace linspire
237237

238238
void new_row(const utils::var x, utils::lin &&l) noexcept;
239239

240-
std::vector<var> vars; // index is the variable id
241-
std::unordered_map<std::string, utils::var> exprs; // the expressions (string to numeric variable) for which already exist slack variables..
242-
std::map<utils::var, utils::lin> tableau; // basic variable -> expression
243-
std::vector<std::set<utils::var>> t_watches; // for each variable `v`, a set of tableau rows watching `v`..
244-
std::vector<std::reference_wrapper<constraint>> cnfl; // the last conflict explanation..
240+
std::vector<var> vars; // index is the variable id
241+
std::unordered_map<std::string, utils::var> exprs; // the expressions (string to numeric variable) for which already exist slack variables..
242+
std::map<utils::var, utils::lin> tableau; // basic variable -> expression
243+
std::vector<std::set<utils::var>> t_watches; // for each variable `v`, a set of tableau rows watching `v`..
244+
std::vector<constraint *> cnfl; // the last conflict explanation..
245245
#ifdef LINSPIRE_ENABLE_LISTENERS
246246
std::unordered_map<utils::var, std::set<listener *>> listening; // for each variable, the listeners listening to it..
247247
std::set<listener *> listeners; // the collection of listeners..

include/var.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ namespace linspire
2525
friend json::json to_json(const var &x) noexcept;
2626

2727
private:
28-
void set_lb(const utils::inf_rational &v, std::optional<constraint> reason = std::nullopt) noexcept;
28+
void set_lb(const utils::inf_rational &v, constraint *reason = nullptr) noexcept;
2929
void unset_lb(const utils::inf_rational &v, constraint &reason) noexcept;
30-
void set_ub(const utils::inf_rational &v, std::optional<constraint> reason = std::nullopt) noexcept;
30+
void set_ub(const utils::inf_rational &v, constraint *reason = nullptr) noexcept;
3131
void unset_ub(const utils::inf_rational &v, constraint &reason) noexcept;
3232

3333
private:

src/linspire.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace linspire
4141
utils::inf_rational solver::ub(const utils::var x) const noexcept { return vars[x].get_ub(); }
4242
utils::inf_rational solver::val(const utils::var x) const noexcept { return vars[x].val; }
4343

44-
bool solver::new_eq(const utils::lin &lhs, const utils::lin &rhs, const std::optional<std::reference_wrapper<constraint>> &reason) noexcept
44+
bool solver::new_eq(const utils::lin &lhs, const utils::lin &rhs, constraint *reason) noexcept
4545
{
4646
LOG_TRACE(utils::to_string(lhs) + " == " + utils::to_string(rhs));
4747
utils::lin expr = lhs - rhs;
@@ -79,7 +79,7 @@ namespace linspire
7979
}
8080
}
8181

82-
bool solver::new_lt(const utils::lin &lhs, const utils::lin &rhs, bool strict, const std::optional<std::reference_wrapper<constraint>> &reason) noexcept
82+
bool solver::new_lt(const utils::lin &lhs, const utils::lin &rhs, bool strict, constraint *reason) noexcept
8383
{
8484
LOG_TRACE(utils::to_string(lhs) + (strict ? " < " : " <= ") + utils::to_string(rhs));
8585
utils::lin expr = lhs - rhs;
@@ -152,12 +152,12 @@ namespace linspire
152152
for (const auto &[v, c] : l.vars)
153153
if (is_positive(c)) // we use the most restrictive upper bound of v
154154
for (const auto &w : vars.at(v).ubs.begin()->second)
155-
cnfl.push_back(*w);
155+
cnfl.push_back(w);
156156
else if (is_negative(c)) // we use the most restrictive lower bound of v
157157
for (const auto &w : vars.at(v).lbs.rbegin()->second)
158-
cnfl.push_back(*w);
158+
cnfl.push_back(w);
159159
for (const auto &w : vars.at(x_i).lbs.rbegin()->second) // we use the most restrictive lower bound of x_i
160-
cnfl.push_back(*w);
160+
cnfl.push_back(w);
161161
return false;
162162
}
163163
}
@@ -173,12 +173,12 @@ namespace linspire
173173
for (const auto &[v, c] : l.vars)
174174
if (is_positive(c)) // we use the most restrictive lower bound of v
175175
for (const auto &w : vars.at(v).lbs.rbegin()->second)
176-
cnfl.push_back(*w);
176+
cnfl.push_back(w);
177177
else if (is_negative(c)) // we use the most restrictive upper bound of v
178178
for (const auto &w : vars.at(v).ubs.begin()->second)
179-
cnfl.push_back(*w);
179+
cnfl.push_back(w);
180180
for (const auto &w : vars.at(x_i).ubs.begin()->second) // we use the most restrictive upper bound of x_i
181-
cnfl.push_back(*w);
181+
cnfl.push_back(w);
182182
return false;
183183
}
184184
}
@@ -187,7 +187,7 @@ namespace linspire
187187

188188
bool solver::match(const utils::lin &l0, const utils::lin &l1) const noexcept { return lb(l0) <= ub(l1) && ub(l0) >= lb(l1); }
189189

190-
bool solver::set_lb(const utils::var x, const utils::inf_rational &v, const std::optional<std::reference_wrapper<constraint>> &reason) noexcept
190+
bool solver::set_lb(const utils::var x, const utils::inf_rational &v, constraint *reason) noexcept
191191
{
192192
assert(x < vars.size());
193193
assert(v > utils::rational::negative_infinite);
@@ -196,30 +196,30 @@ namespace linspire
196196
{ // inconsistent bound..
197197
cnfl.clear();
198198
if (reason)
199-
cnfl.push_back(reason.value());
199+
cnfl.push_back(reason);
200200
for (const auto &w : vars.at(x).ubs.begin()->second) // we use the most restrictive upper bound of x
201-
cnfl.push_back(*w);
201+
cnfl.push_back(w);
202202
return false;
203203
}
204204
if (reason)
205205
{ // we have a reason for this bound..
206-
if (auto it = reason->get().lbs.find(x); it != reason->get().lbs.end())
206+
if (auto it = reason->lbs.find(x); it != reason->lbs.end())
207207
{ // we already have a lower bound for this variable in the reason..
208208
if (it->second < v)
209209
{ // we update the lower bound only if the new one is more restrictive..
210-
vars.at(x).unset_lb(it->second, reason->get());
210+
vars.at(x).unset_lb(it->second, *reason);
211211
it->second = v;
212212
}
213213
}
214214
else
215-
reason->get().lbs.emplace(x, v);
215+
reason->lbs.emplace(x, v);
216216
}
217217
vars.at(x).set_lb(v, reason);
218218
if (val(x) < v && !is_basic(x))
219219
update(x, v);
220220
return true;
221221
}
222-
bool solver::set_ub(const utils::var x, const utils::inf_rational &v, const std::optional<std::reference_wrapper<constraint>> &reason) noexcept
222+
bool solver::set_ub(const utils::var x, const utils::inf_rational &v, constraint *reason) noexcept
223223
{
224224
assert(x < vars.size());
225225
assert(v < utils::rational::positive_infinite);
@@ -228,23 +228,23 @@ namespace linspire
228228
{ // inconsistent bound..
229229
cnfl.clear();
230230
if (reason)
231-
cnfl.push_back(reason.value());
231+
cnfl.push_back(reason);
232232
for (const auto &w : vars.at(x).lbs.rbegin()->second) // we use the most restrictive lower bound of x
233-
cnfl.push_back(*w);
233+
cnfl.push_back(w);
234234
return false;
235235
}
236236
if (reason)
237237
{ // we have a reason for this bound..
238-
if (auto it = reason->get().ubs.find(x); it != reason->get().ubs.end())
238+
if (auto it = reason->ubs.find(x); it != reason->ubs.end())
239239
{ // we already have an upper bound for this variable in the reason..
240240
if (it->second > v)
241241
{ // we update the upper bound only if the new one is more restrictive..
242-
vars.at(x).unset_ub(it->second, reason->get());
242+
vars.at(x).unset_ub(it->second, *reason);
243243
it->second = v;
244244
}
245245
}
246246
else
247-
reason->get().ubs.emplace(x, v);
247+
reason->ubs.emplace(x, v);
248248
}
249249
vars.at(x).set_ub(v, reason);
250250
if (val(x) > v && !is_basic(x))

src/var.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ namespace linspire
99
utils::inf_rational var::get_lb() const noexcept { return lbs.empty() ? utils::rational::negative_infinite : lbs.rbegin()->first; }
1010
utils::inf_rational var::get_ub() const noexcept { return ubs.empty() ? utils::rational::positive_infinite : ubs.begin()->first; }
1111

12-
void var::set_lb(const utils::inf_rational &v, std::optional<constraint> reason) noexcept
12+
void var::set_lb(const utils::inf_rational &v, constraint *reason) noexcept
1313
{
1414
assert(v <= get_ub()); // we cannot set a lower bound greater than the current upper bound..
1515
if (reason)
1616
{ // we add a new lower bound `v` with the given reason..
1717
if (auto it = lbs.find(v); it != lbs.end())
18-
it->second.insert(&*reason); // we add the reason to the existing lower bound `v`..
18+
it->second.insert(reason); // we add the reason to the existing lower bound `v`..
1919
else
20-
lbs.emplace(v, std::set<constraint *>{&*reason}); // we create a new lower bound `v`..
20+
lbs.emplace(v, std::set<constraint *>{reason}); // we create a new lower bound `v`..
2121
}
2222
else
2323
{ // we remove all the lower bounds that are less than `v`..
@@ -35,15 +35,15 @@ namespace linspire
3535
lbs.erase(it);
3636
}
3737

38-
void var::set_ub(const utils::inf_rational &v, std::optional<constraint> reason) noexcept
38+
void var::set_ub(const utils::inf_rational &v, constraint *reason) noexcept
3939
{
4040
assert(v >= get_lb()); // we cannot set an upper bound less than the current lower bound..
4141
if (reason)
4242
{ // we add a new upper bound `v` with the given reason..
4343
if (auto it = ubs.find(v); it != ubs.end())
44-
it->second.insert(&*reason); // we add the reason to the existing upper bound `v`..
44+
it->second.insert(reason); // we add the reason to the existing upper bound `v`..
4545
else
46-
ubs.emplace(v, std::set<constraint *>{&*reason}); // we create a new upper bound `v`..
46+
ubs.emplace(v, std::set<constraint *>{reason}); // we create a new upper bound `v`..
4747
}
4848
else
4949
{ // we remove all the upper bounds that are greater than `v`..

tests/test_linspire.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,10 @@ void test2()
8686
linspire::constraint c0;
8787

8888
// x >= 0
89-
bool res0 = s.new_gt({{x, 1}}, 0, false, c0);
89+
bool res0 = s.new_gt({{x, 1}}, 0, false, &c0);
9090
assert(res0);
9191
// x >= 1 (we add this constraint with the same reason as the previous one)
92-
bool res1 = s.new_gt({{x, 1}}, 1, false, c0);
92+
bool res1 = s.new_gt({{x, 1}}, 1, false, &c0);
9393
assert(res1);
9494

9595
auto cons = s.check();
@@ -121,10 +121,10 @@ void test3()
121121
linspire::constraint c1;
122122

123123
// y >= x + 1
124-
bool res0 = s.new_gt({{y, 1}, {x, -1}}, 1, false, c0);
124+
bool res0 = s.new_gt({{y, 1}, {x, -1}}, 1, false, &c0);
125125
assert(res0);
126126
// z >= y + 1
127-
bool res1 = s.new_gt({{z, 1}, {y, -1}}, 1, false, c1);
127+
bool res1 = s.new_gt({{z, 1}, {y, -1}}, 1, false, &c1);
128128
assert(res1);
129129
bool cons = s.check();
130130
assert(cons);
@@ -161,22 +161,22 @@ void test4()
161161
linspire::constraint c2;
162162

163163
// x + y >= 1
164-
bool res0 = s.new_gt({{x, 1}, {y, 1}}, 1, false, c0);
164+
bool res0 = s.new_gt({{x, 1}, {y, 1}}, 1, false, &c0);
165165
assert(res0);
166166
// x >= 2
167-
bool res1 = s.new_gt({{x, 1}}, 2, false, c1);
167+
bool res1 = s.new_gt({{x, 1}}, 2, false, &c1);
168168
assert(res1);
169169
bool cons = s.check();
170170
assert(cons);
171171

172172
// x + y <= 0
173-
bool res2 = s.new_lt({{x, 1}, {y, 1}}, 0, false, c2);
173+
bool res2 = s.new_lt({{x, 1}, {y, 1}}, 0, false, &c2);
174174
assert(res2);
175175
cons = s.check();
176176
assert(!cons);
177177
auto expl = s.get_conflict();
178178
assert(expl.size() == 2);
179-
assert((&expl[0] == &c0 && &expl[1] == &c2) || (&expl[0] == &c2 && &expl[1] == &c0));
179+
assert((expl[0] == &c0 && expl[1] == &c2) || (expl[0] == &c2 && expl[1] == &c0));
180180

181181
s.retract(c0);
182182
cons = s.check();

0 commit comments

Comments
 (0)