Skip to content

Commit 7db82a2

Browse files
Enhance Engine functionality with new variable and constraint methods
1 parent c7c8c22 commit 7db82a2

1 file changed

Lines changed: 37 additions & 0 deletions

File tree

src/lib.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,42 @@ pub struct Engine {
2727
listeners: HashMap<usize, Vec<Callback>>,
2828
}
2929
impl Engine {
30+
/// Creates a new empty constraint engine.
31+
///
32+
/// The returned engine has no variables, no constraints, and no listeners.
3033
pub fn new() -> Self {
3134
Self { values: Vec::new(), constraints: HashMap::new(), listeners: HashMap::new() }
3235
}
3336

37+
/// Adds a variable with the provided initial domain.
38+
///
39+
/// Returns the variable ID that can be used with methods like
40+
/// [`Engine::val`], [`Engine::new_eq`], and [`Engine::new_neq`].
41+
///
42+
/// All inserted values start as active (not suppressed).
3443
pub fn add_var(&mut self, values: Vec<i32>) -> usize {
3544
let id = self.values.len();
3645
self.values.push(values.into_iter().map(|v| ValueState { value: v, suppressed_by: None }).collect());
3746
id
3847
}
3948

49+
/// Returns the currently active domain values of a variable.
50+
///
51+
/// Suppressed values are excluded from the returned vector.
52+
///
53+
/// Panics if `var` is not a valid variable ID.
4054
pub fn val(&self, var: usize) -> Vec<i32> {
4155
self.values[var].iter().filter(|s| s.suppressed_by.is_none()).map(|s| s.value).collect()
4256
}
4357

58+
/// Adds an equality constraint between two variables and propagates it.
59+
///
60+
/// On success, returns the newly assigned constraint ID.
61+
///
62+
/// On failure, returns `(constraint_id, explanation)` where `explanation`
63+
/// contains IDs of constraints involved in the domain wipeout.
64+
/// The newly created constraint remains in the engine and can be removed
65+
/// with [`Engine::retract_constraint`].
4466
pub fn new_eq(&mut self, var1: usize, var2: usize) -> Result<usize, (usize, Vec<usize>)> {
4567
let id = self.constraints.len();
4668
self.constraints.insert(id, (var1, var2, ConstraintKind::Equality));
@@ -50,6 +72,14 @@ impl Engine {
5072
Ok(id)
5173
}
5274

75+
/// Adds an inequality constraint between two variables and propagates it.
76+
///
77+
/// On success, returns the newly assigned constraint ID.
78+
///
79+
/// On failure, returns `(constraint_id, explanation)` where `explanation`
80+
/// contains IDs of constraints involved in the domain wipeout.
81+
/// The newly created constraint remains in the engine and can be removed
82+
/// with [`Engine::retract_constraint`].
5383
pub fn new_neq(&mut self, var1: usize, var2: usize) -> Result<usize, (usize, Vec<usize>)> {
5484
let id = self.constraints.len();
5585
self.constraints.insert(id, (var1, var2, ConstraintKind::Inequality));
@@ -59,6 +89,13 @@ impl Engine {
5989
Ok(id)
6090
}
6191

92+
/// Retracts a constraint by ID and incrementally restores consistency.
93+
///
94+
/// If the ID is present, the constraint is removed, values suppressed by
95+
/// that exact constraint are released, and only the affected neighborhood is
96+
/// re-propagated. If the ID does not exist, this method is a no-op.
97+
///
98+
/// Panics if re-propagation unexpectedly causes a domain wipeout.
6299
pub fn retract_constraint(&mut self, id: usize) {
63100
if let Some((var1, var2, _)) = self.constraints.remove(&id) {
64101
// 1. Free only values that were killed *by this exact constraint*

0 commit comments

Comments
 (0)