Skip to content

Commit 20fafc3

Browse files
Refactor constraint handling: replace shared pointers with references and update related methods for improved memory management and consistency.
1 parent 964f6e5 commit 20fafc3

5 files changed

Lines changed: 78 additions & 81 deletions

File tree

include/linspire.hpp

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#pragma once
22

33
#include "var.hpp"
4-
#include <set>
54
#include <unordered_map>
65

76
namespace linspire
@@ -124,10 +123,10 @@ namespace linspire
124123
* @param lhs The left-hand side linear expression of the constraint.
125124
* @param rhs The right-hand side linear expression of the constraint.
126125
* @param strict A boolean indicating whether the constraint is strict (default: false).
127-
* @param reason An optional shared pointer to a constraint object that serves as the reason for this constraint.
126+
* @param reason An optional constraint that serves as the reason for adding this new constraint.
128127
* @return true if the constraint was successfully added; false if it leads to inconsistency.
129128
*/
130-
[[nodiscard]] bool new_lt(const utils::lin &lhs, const utils::lin &rhs, bool strict = false, std::shared_ptr<constraint> reason = nullptr) noexcept;
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;
131130
/**
132131
* @brief Adds a new equality constraint to the solver.
133132
*
@@ -136,10 +135,10 @@ namespace linspire
136135
*
137136
* @param lhs The left-hand side linear expression of the equality constraint.
138137
* @param rhs The right-hand side linear expression of the equality constraint.
139-
* @param reason An optional shared pointer to a constraint object that serves as the reason for this equality constraint.
138+
* @param reason An optional constraint that serves as the reason for adding this new equality constraint.
140139
* @return true if the equality constraint was successfully added; false if it leads to inconsistency.
141140
*/
142-
[[nodiscard]] bool new_eq(const utils::lin &lhs, const utils::lin &rhs, std::shared_ptr<constraint> reason = nullptr) noexcept;
141+
[[nodiscard]] bool new_eq(const utils::lin &lhs, const utils::lin &rhs, const std::optional<std::reference_wrapper<constraint>> &reason = std::nullopt) noexcept;
143142
/**
144143
* @brief Adds a new greater-than or greater-than-or-equal-to constraint to the solver.
145144
*
@@ -150,20 +149,20 @@ namespace linspire
150149
* @param lhs The left-hand side linear expression of the constraint.
151150
* @param rhs The right-hand side linear expression of the constraint.
152151
* @param strict A boolean indicating whether the constraint is strict (default: false).
153-
* @param reason An optional shared pointer to a constraint object that serves as the reason for this constraint.
152+
* @param reason An optional constraint that serves as the reason for adding this new constraint.
154153
* @return true if the constraint was successfully added; false if it leads to inconsistency.
155154
*/
156-
[[nodiscard]] bool new_gt(const utils::lin &lhs, const utils::lin &rhs, bool strict = false, std::shared_ptr<constraint> reason = nullptr) noexcept { return new_lt(rhs, lhs, strict, reason); }
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); }
157156

158157
/**
159158
* @brief Retracts a previously added constraint from the solver.
160159
*
161160
* This function removes a previously added constraint from the solver. It updates the
162161
* internal state of the solver to reflect the removal of the constraint.
163162
*
164-
* @param c A shared pointer to the constraint object to be retracted.
163+
* @param c The constraint to be retracted.
165164
*/
166-
void retract(const std::shared_ptr<constraint> c) noexcept;
165+
void retract(constraint &c) noexcept;
167166

168167
/**
169168
* @brief Checks the consistency of the current set of constraints.
@@ -184,9 +183,9 @@ namespace linspire
184183
* The conflict explanation consists of a set of constraints that led to an inconsistency
185184
* in the solver.
186185
*
187-
* @return A constant reference to a vector of shared pointers to constraint objects representing the last conflict explanation.
186+
* @return A constant reference to the vector of constraints representing the last conflict explanation.
188187
*/
189-
[[nodiscard]] const std::vector<std::shared_ptr<const constraint>> &get_conflict() const noexcept { return cnfl; }
188+
[[nodiscard]] const std::vector<std::reference_wrapper<constraint>> &get_conflict() const noexcept { return cnfl; }
190189

191190
/**
192191
* @brief Checks if two linear expressions can be made equal.
@@ -204,21 +203,21 @@ namespace linspire
204203
/**
205204
* @brief Adds a listener to the solver.
206205
*
207-
* This function registers a listener that will be notified of variable value changes
206+
* This function registers a listener that will be notified of changes to variable values
208207
* within the solver. The listener must implement the `listener` interface.
209208
*
210-
* @param l A shared pointer to the listener to be added.
209+
* @param l A reference to the listener to be added.
211210
*/
212-
void add_listener(std::shared_ptr<listener> l) noexcept;
211+
void add_listener(listener &l) noexcept;
213212
/**
214213
* @brief Removes a listener from the solver.
215214
*
216-
* This function unregisters a previously added listener from the solver. The listener
217-
* will no longer receive notifications of variable value changes.
215+
* This function unregisters a previously added listener from the solver. The listener will
216+
* no longer receive notifications of variable value changes.
218217
*
219-
* @param l A shared pointer to the listener to be removed.
218+
* @param l A reference to the listener to be removed.
220219
*/
221-
void remove_listener(std::shared_ptr<listener> l) noexcept;
220+
void remove_listener(listener &l) noexcept;
222221
#endif
223222

224223
friend std::string to_string(const solver &s) noexcept;
@@ -227,8 +226,8 @@ namespace linspire
227226
private:
228227
[[nodiscard]] bool is_basic(const utils::var v) const noexcept { return tableau.count(v); }
229228

230-
[[nodiscard]] bool set_lb(const utils::var x_i, const utils::inf_rational &v, std::shared_ptr<constraint> reason = nullptr) noexcept;
231-
[[nodiscard]] bool set_ub(const utils::var x_i, const utils::inf_rational &v, std::shared_ptr<constraint> reason = nullptr) noexcept;
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;
232231

233232
void update(const utils::var x_i, const utils::inf_rational &v) noexcept;
234233

@@ -238,14 +237,14 @@ namespace linspire
238237

239238
void new_row(const utils::var x, utils::lin &&l) noexcept;
240239

241-
std::vector<var> vars; // index is the variable id
242-
std::unordered_map<std::string, utils::var> exprs; // the expressions (string to numeric variable) for which already exist slack variables..
243-
std::map<utils::var, utils::lin> tableau; // basic variable -> expression
244-
std::vector<std::set<utils::var>> t_watches; // for each variable `v`, a set of tableau rows watching `v`..
245-
std::vector<std::shared_ptr<const 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<std::reference_wrapper<constraint>> cnfl; // the last conflict explanation..
246245
#ifdef LINSPIRE_ENABLE_LISTENERS
247246
std::unordered_map<utils::var, std::set<listener *>> listening; // for each variable, the listeners listening to it..
248-
std::set<std::shared_ptr<listener>> listeners; // the collection of listeners..
247+
std::set<listener *> listeners; // the collection of listeners..
249248
#endif
250249
};
251250

include/var.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "inf_rational.hpp"
55
#include "json.hpp"
66
#include <set>
7-
#include <memory>
7+
#include <optional>
88

99
namespace linspire
1010
{
@@ -25,14 +25,14 @@ 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::shared_ptr<const constraint> reason = nullptr) noexcept;
29-
void unset_lb(const utils::inf_rational &v, std::shared_ptr<const constraint> reason) noexcept;
30-
void set_ub(const utils::inf_rational &v, std::shared_ptr<const constraint> reason = nullptr) noexcept;
31-
void unset_ub(const utils::inf_rational &v, std::shared_ptr<const constraint> reason) noexcept;
28+
void set_lb(const utils::inf_rational &v, std::optional<constraint> reason = std::nullopt) noexcept;
29+
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;
31+
void unset_ub(const utils::inf_rational &v, constraint &reason) noexcept;
3232

3333
private:
34-
std::map<utils::inf_rational, std::set<std::shared_ptr<const constraint>>> lbs, ubs; // the lower and upper bounds with their reasons..
35-
utils::inf_rational val; // the current value of this variable..
34+
std::map<utils::inf_rational, std::set<constraint *>> lbs, ubs; // the lower and upper bounds with their reasons..
35+
utils::inf_rational val; // the current value of this variable..
3636
};
3737

3838
[[nodiscard]] std::string to_string(const var &x) noexcept;

src/linspire.cpp

Lines changed: 27 additions & 27 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, std::shared_ptr<constraint> reason) noexcept
44+
bool solver::new_eq(const utils::lin &lhs, const utils::lin &rhs, const std::optional<std::reference_wrapper<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, std::shared_ptr<constraint> reason) noexcept
82+
bool solver::new_lt(const utils::lin &lhs, const utils::lin &rhs, bool strict, const std::optional<std::reference_wrapper<constraint>> &reason) noexcept
8383
{
8484
LOG_TRACE(utils::to_string(lhs) + (strict ? " < " : " <= ") + utils::to_string(rhs));
8585
utils::lin expr = lhs - rhs;
@@ -119,14 +119,14 @@ namespace linspire
119119
}
120120
}
121121

122-
void solver::retract(const std::shared_ptr<constraint> c) noexcept
122+
void solver::retract(constraint &c) noexcept
123123
{
124-
for (const auto &[x, lb] : c->lbs)
124+
for (const auto &[x, lb] : c.lbs)
125125
vars[x].unset_lb(lb, c);
126-
c->lbs.clear();
127-
for (const auto &[x, ub] : c->ubs)
126+
c.lbs.clear();
127+
for (const auto &[x, ub] : c.ubs)
128128
vars[x].unset_ub(ub, c);
129-
c->ubs.clear();
129+
c.ubs.clear();
130130
}
131131

132132
bool solver::check() noexcept
@@ -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, std::shared_ptr<constraint> reason) noexcept
190+
bool solver::set_lb(const utils::var x, const utils::inf_rational &v, const std::optional<std::reference_wrapper<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);
199+
cnfl.push_back(reason.value());
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->lbs.find(x); it != reason->lbs.end())
206+
if (auto it = reason->get().lbs.find(x); it != reason->get().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);
210+
vars.at(x).unset_lb(it->second, reason->get());
211211
it->second = v;
212212
}
213213
}
214214
else
215-
reason->lbs.emplace(x, v);
215+
reason->get().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, std::shared_ptr<constraint> reason) noexcept
222+
bool solver::set_ub(const utils::var x, const utils::inf_rational &v, const std::optional<std::reference_wrapper<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);
231+
cnfl.push_back(reason.value());
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->ubs.find(x); it != reason->ubs.end())
238+
if (auto it = reason->get().ubs.find(x); it != reason->get().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);
242+
vars.at(x).unset_ub(it->second, reason->get());
243243
it->second = v;
244244
}
245245
}
246246
else
247-
reason->ubs.emplace(x, v);
247+
reason->get().ubs.emplace(x, v);
248248
}
249249
vars.at(x).set_ub(v, reason);
250250
if (val(x) > v && !is_basic(x))
@@ -367,8 +367,8 @@ namespace linspire
367367
}
368368

369369
#ifdef LINSPIRE_ENABLE_LISTENERS
370-
void solver::add_listener(std::shared_ptr<listener> l) noexcept { listeners.insert(l); }
371-
void solver::remove_listener(std::shared_ptr<listener> l) noexcept { listeners.erase(l); }
370+
void solver::add_listener(listener &l) noexcept { listeners.insert(&l); }
371+
void solver::remove_listener(listener &l) noexcept { listeners.erase(&l); }
372372
#endif
373373

374374
std::string to_string(const solver &s) noexcept

0 commit comments

Comments
 (0)