Skip to content

Commit bf53a63

Browse files
committed
Updated documentation
1 parent 460839a commit bf53a63

File tree

4 files changed

+213
-47
lines changed

4 files changed

+213
-47
lines changed

docs/guides/getting_started.md

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ Let's solve a simple problem: **Find two numbers where one is less than the othe
3333
### Step 1: Set Up Your Project
3434

3535
Add to your `Cargo.toml`:
36+
3637
```toml
37-
```toml
38-
selen = "0.8.0"
39-
```
38+
selen = "0.8.3"
4039
```
4140

41+
4242
### Step 2: Write Your First Solver
4343

4444
```rust
@@ -103,8 +103,8 @@ let weight = m.float(1.5, 25.0); // weight ∈ [1.5, 25.0]
103103

104104
### Custom Domains (Specific Values)
105105
```rust
106-
let day = m.ints(vec![1, 3, 5, 7]); // Only odd numbers
107-
let color = m.ints(vec![10, 20, 30]); // Only these values
106+
let day = m.intset(vec![1, 3, 5, 7]); // Only odd numbers
107+
let color = m.intset(vec![10, 20, 30]); // Only these values
108108
```
109109

110110
### Boolean Variables
@@ -141,20 +141,18 @@ post!(m, abs(x - y) <= int(3));
141141
Use method calls for runtime constraint building:
142142

143143
```rust
144-
// Basic comparisons
145-
m.post(x.lt(y));
146-
m.post(x.ge(5));
147-
m.post(y.ne(0));
144+
// Expression builder with m.new()
145+
m.new(x.lt(y)); // x < y
146+
m.new(x.ge(int(5))); // x >= 5
147+
m.new(y.ne(int(0))); // y != 0
148148

149-
// Arithmetic expressions
150-
m.post(x.add(y).eq(12));
151-
m.post(x.mul(y).le(50));
152-
m.post(x.sub(y).ge(2));
149+
// Arithmetic expressions
150+
m.new(x.add(y).eq(int(12))); // x + y == 12
151+
m.new(x.mul(y).le(int(50))); // x * y <= 50
152+
m.new(x.sub(y).ge(int(2))); // x - y >= 2
153153

154-
// Complex expressions
155-
m.post(x.add(y.mul(2)).eq(z));
156-
let abs_diff = m.abs(x.sub(y));
157-
m.post(abs_diff.le(3));
154+
// Complex chaining
155+
m.new(x.mul(int(2)).add(y).le(int(10))); // x * 2 + y <= 10
158156
```
159157

160158
**When to use each:**
@@ -215,7 +213,7 @@ post!(m, condition2 == (y < int(10)));
215213
post!(m, and([condition1, condition2])); // Both conditions must be true
216214

217215
// Alternative: Use runtime API for constraint combinations
218-
// m.post(x.gt(5).and(y.lt(10))); // (x > 5) AND (y < 10)
216+
// post!(m, x > 5 & y < 10); // (x > 5) AND (y < 10)
219217

220218
// OR logic with boolean variables
221219
let options = vec![m.bool(), m.bool(), m.bool()];
@@ -395,17 +393,17 @@ fn main() {
395393

396394
// Constraints:
397395
// 1. Task A must finish before Task B starts
398-
post!(m, task_a + int(duration_a) <= task_b);
396+
post!(m, task_a + duration_a <= task_b);
399397

400398
// 2. Task B must finish before Task C starts
401-
post!(m, task_b + int(duration_b) <= task_c);
399+
post!(m, task_b + duration_b <= task_c);
402400

403401
// 3. All tasks must complete by time 10
404-
post!(m, task_c + int(duration_c) <= int(10));
402+
post!(m, task_c + duration_c <= 10);
405403

406404
// Solve: minimize the total schedule length
407405
let makespan = m.int(0, 15);
408-
post!(m, makespan == task_c + int(duration_c));
406+
post!(m, makespan == task_c + duration_c);
409407

410408
match m.minimize(makespan) {
411409
Ok(solution) => {

docs/guides/mathematical_syntax.md

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ use selen::math_syntax::*;
1010
use selen::constraint_macros::*;
1111

1212
// Create model and variables
13-
let mut m = Model::new();
14-
let x = m.var_int(1, 10);
15-
let y = m.var_int(1, 20);
13+
let mut m = Model::default();
14+
let x = m.int(1, 10);
15+
let y = m.int(1, 20);
1616

1717
// Post constraints using mathematical syntax
1818
post!(m, x < y);
1919
post!(m, x >= int(3));
20-
post!(m, y % 3 == 1);
20+
post!(m, y % int(3) == int(1));
2121
```
2222

2323
## Supported Features
@@ -32,17 +32,17 @@ post!(m, x == y); // Equal
3232
post!(m, x != y); // Not equal
3333
```
3434

35-
### Typed Constants
36-
Use helper functions for explicit type specification:
35+
### Constants
36+
Use int() for integer constants and float() for float constants:
3737
```rust
38-
post!(m, x >= int(5)); // Integer constant
39-
post!(m, y <= float(3.14)); // Float constant
38+
post!(m, x >= int(5)); // Integer constant
39+
post!(m, y <= float(3.14)); // Float constant
4040
```
4141

4242
### Modulo Constraints
4343
```rust
44-
post!(m, x % 3 == 1); // x mod 3 equals 1
45-
post!(m, y % 7 != int(0)); // y is not divisible by 7
44+
post!(m, x % int(3) == int(1)); // x mod 3 equals 1
45+
post!(m, y % int(7) != int(0)); // y is not divisible by 7
4646
```
4747

4848
### Logical Operations
@@ -79,7 +79,7 @@ postall!(m, [
7979
x < y,
8080
y <= int(15),
8181
x >= int(1),
82-
y % 3 == 1
82+
y % int(3) == int(1)
8383
]);
8484
```
8585

@@ -91,17 +91,17 @@ use selen::math_syntax::*;
9191
use selen::constraint_macros::*;
9292

9393
fn main() {
94-
let mut m = Model::new();
94+
let mut m = Model::default();
9595

9696
// Variables
97-
let x = m.var_int(1, 10);
98-
let y = m.var_int(1, 20);
99-
let z = m.var_int(1, 15);
97+
let x = m.int(1, 10);
98+
let y = m.int(1, 20);
99+
let z = m.int(1, 15);
100100

101101
// Mathematical constraints
102102
post!(m, x < y);
103103
post!(m, and(y <= int(15), z >= int(5)));
104-
post!(m, x % 3 == 1);
104+
post!(m, x % int(3) == int(1));
105105
post!(m, or(x == int(1), x == int(7)));
106106

107107
// Solve
@@ -113,14 +113,6 @@ fn main() {
113113
}
114114
```
115115

116-
## Future Enhancements
117-
118-
Planned syntax extensions include:
119-
- Arithmetic expressions: `post!(m, x + 3 < y)`
120-
- Multiplication: `post!(m, x * 2 <= 10)`
121-
- Function integration: `post!(m, abs(x) >= int(1))`
122-
- Complex expressions: `post!(m, max(x, y) <= int(15))`
123-
- Nested logical operations: `post!(m, and(or(c1, c2), not(c3)))`
124116

125117
## Implementation Details
126118

docs/guides/precision_quick_reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ ctx.try_set_min(var_id, bounds.lower_bound);
6464
### Enable Precision Handling
6565

6666
```rust
67-
let mut model = Model::new();
67+
let mut model = Model::default();
6868

6969
// Add variables and constraints normally
7070
let x = model.new_var_float(0.0, 10.0);

docs/guides/programmatic_api.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
## Advanced/Complicated Examples
2+
3+
4+
# Programmatic API Guide
5+
6+
This guide explains how to use the Selen CSP solver's programmatic API for building constraints dynamically at runtime. This is useful when constraints depend on user input, data, or are not known at compile time.
7+
8+
## When to Use the Programmatic API
9+
- When you need to generate constraints based on data or user input
10+
- When constraints are not static or known in advance
11+
- For advanced use cases where mathematical syntax is not flexible enough
12+
13+
## Key Concepts
14+
- **Fluent builder pattern**: Chain methods to build complex expressions
15+
- **m.new()**: The primary method to post programmatic constraints
16+
- **int() / float()**: Always wrap constants in constraints
17+
18+
## Basic Usage
19+
20+
```rust
21+
use selen::prelude::*;
22+
23+
fn main() {
24+
let mut m = Model::default();
25+
let x = m.int(1, 10);
26+
let y = m.int(1, 10);
27+
28+
// Comparison constraint: x < y
29+
m.new(x.lt(y));
30+
31+
// Comparison with constant: x >= 5
32+
m.new(x.ge(int(5)));
33+
34+
// Arithmetic constraint: x + y == 12
35+
m.new(x.add(y).eq(int(12)));
36+
37+
// Chained arithmetic: x * 2 + y <= 10
38+
m.new(x.mul(int(2)).add(y).le(int(10)));
39+
}
40+
```
41+
42+
## Building Expressions
43+
44+
You can chain methods to build complex expressions:
45+
46+
```rust
47+
// (x * 3 + y) % 4 == 1
48+
m.new(x.mul(int(3)).add(y).modulo(int(4)).eq(int(1)));
49+
50+
// abs(x - y) <= 2
51+
m.new(x.sub(y).abs().le(int(2)));
52+
53+
// (x + y) * z >= 20
54+
m.new(x.add(y).mul(z).ge(int(20)));
55+
```
56+
57+
## Dynamic Constraint Generation
58+
59+
You can generate constraints in loops or based on data:
60+
61+
```rust
62+
let vars: Vec<_> = (0..5).map(|_| m.int(1, 10)).collect();
63+
64+
// All variables must be different
65+
m.new(alldiff(vars.clone()));
66+
67+
// Post constraints for each variable
68+
for v in &vars {
69+
m.new(v.ge(int(3)));
70+
}
71+
```
72+
73+
## Boolean Logic
74+
75+
You can build boolean expressions and combine them:
76+
77+
```rust
78+
let a = m.bool();
79+
let b = m.bool();
80+
81+
// a == (x > 5)
82+
m.new(a.eq(x.gt(int(5))));
83+
// b == (y < 7)
84+
m.new(b.eq(y.lt(int(7))));
85+
// a AND b
86+
m.new(and([a, b]));
87+
// a OR b
88+
m.new(or([a, b]));
89+
// NOT a
90+
m.new(not(a));
91+
```
92+
93+
## Global Constraints
94+
95+
```rust
96+
let vars = vec![x, y, z];
97+
// All different
98+
m.new(alldiff(vars.clone()));
99+
// All equal
100+
m.new(allequal(vars.clone()));
101+
// Sum equals 15
102+
m.new(sum(vars.clone()).eq(int(15)));
103+
```
104+
105+
## Tips
106+
- Always use `int()` or `float()` for constants in constraints
107+
- Use method chaining to build up complex expressions
108+
- Use `m.new()` to post each constraint
109+
- For static constraints, prefer the `post!` macro and mathematical syntax
110+
111+
---
112+
113+
For more details, see the [API documentation](https://docs.rs/selen) and the `examples/advanced_runtime_api.rs` file in the repository.
114+
115+
116+
## Advanced/Complicated Examples
117+
118+
Here are some advanced examples demonstrating the flexibility of the programmatic API:
119+
120+
```rust
121+
use selen::prelude::*;
122+
123+
fn main() {
124+
let mut m = Model::default();
125+
let n = 5;
126+
let vars = m.ints(1, 20, n);
127+
let z = m.int(1, 100);
128+
129+
// 1. All variables are pairwise different and their sum is even
130+
m.new(alldiff(vars.clone()));
131+
let sum_var = m.int(0, 100);
132+
m.new(sum(vars.clone()).eq(sum_var));
133+
m.new(sum_var.modulo(int(2)).eq(int(0)));
134+
135+
// 2. For each i, vars[i] * (i+1) <= z
136+
for (i, v) in vars.iter().enumerate() {
137+
m.new(v.mul(int((i+1) as i32)).le(z));
138+
}
139+
140+
// 3. At least 2 variables are greater than 10
141+
let bools = m.bools(n);
142+
for (b, v) in bools.iter().zip(vars.iter()) {
143+
m.new(b.eq(v.gt(int(10))));
144+
}
145+
m.new(sum(bools.clone()).ge(int(2)));
146+
147+
// 4. Nested boolean logic: (x > 5 && y < 7) || z == 42
148+
let x = vars[0];
149+
let y = vars[1];
150+
let cond1 = m.bool();
151+
let cond2 = m.bool();
152+
let cond3 = m.bool();
153+
m.new(cond1.eq(x.gt(int(5))));
154+
m.new(cond2.eq(y.lt(int(7))));
155+
m.new(cond3.eq(z.eq(int(42))));
156+
let and_cond = m.bool();
157+
m.new(and_cond.eq(and([cond1, cond2])));
158+
m.new(or([and_cond, cond3]));
159+
160+
// 5. Complex arithmetic: product of all variables >= 1000
161+
let mut prod = vars[0].clone();
162+
for v in vars.iter().skip(1) {
163+
prod = prod.mul(*v);
164+
}
165+
m.new(prod.ge(int(1000)));
166+
167+
// 6. Absolute difference constraints: |x - y| + |y - z| <= 15
168+
let abs_sum = x.sub(y).abs().add(y.sub(z).abs());
169+
m.new(abs_sum.le(int(15)));
170+
171+
// 7. Conditional constraint: if x > 10 then z < 50
172+
let cond = m.bool();
173+
m.new(cond.eq(x.gt(int(10))));
174+
m.new(implies(cond, z.lt(int(50))));
175+
}
176+
```

0 commit comments

Comments
 (0)