@@ -15,8 +15,11 @@ This library provides efficient algorithms and data structures for solving const
1515** Constraint Categories** :
1616- ** Mathematical** : ` + ` , ` - ` , ` * ` , ` / ` , ` % ` , ` abs() ` , ` min() ` , ` max() ` , ` sum() `
1717- ** Comparison** : ` == ` , ` != ` , ` < ` , ` <= ` , ` > ` , ` >= ` (natural syntax)
18- - ** Boolean Logic** : ` and() ` , ` or() ` , ` not() ` with clean function syntax
19- - ** Global** : ` alldiff() `
18+ - ** Boolean Logic** : ` and() ` , ` or() ` , ` not() ` with array syntax ` and([a,b,c]) ` and variadic syntax ` and(a,b,c,d) `
19+ - ** Global** : ` alldiff() ` , ` allequal() ` , element ` x[y] = z ` , ` count(vars, value, count) ` , ` table(vars, tuples) `
20+ - ** Ordering** : ` between(lower, middle, upper) ` for ternary ordering constraints
21+ - ** Cardinality** : ` at_least(vars, value, count) ` , ` at_most(vars, value, count) ` , ` exactly(vars, value, count) `
22+ - ** Conditional** : ` if_then(condition, constraint) ` , ` if_then_else(condition, then_constraint, else_constraint) `
2023
2124## Installation
2225
@@ -31,12 +34,11 @@ cspsolver = "0.5.11"
3134## Examples
3235
3336``` bash
34-
3537cargo run --release --example sudoku
3638cargo run --release --example n_queens
37- cargo run --release --example pc_builder
38- cargo run --release --example resource_allocation
39- cargo run --release --example portfolio_optimization
39+ cargo run --release --example count_demo # Count constraint demonstrations
40+ cargo run --release --example table_demo # Table constraint with practical examples
41+ cargo run --release --example magic_square # Magic squares with enhanced constraints
4042```
4143
4244
@@ -78,22 +80,56 @@ fn main() {
7880 // Create variables with clean syntax
7981 let x = m . int (1 , 10 ); // Integer variable
8082 let y = m . int (5 , 15 ); // Integer variable
81- let z = m . float ( 0.0 , 20.0 ); // Float variable
83+ let z = m . int ( 0 , 20 ); // Integer variable for array compatibility
8284
8385 // Mathematical constraints using post! macro
8486 post! (m , x < y ); // Comparison
8587 post! (m , x + y >= int (10 )); // Arithmetic
86- post! (m , abs (z ) <= float (15.5 )); // Math functions
88+ post! (m , abs (z ) <= int (15 )); // Math functions
8789
8890 // Enhanced constraint features
8991 post! (m , sum ([x , y ]) == int (12 )); // Sum function
90- post! (m , and (x > int (3 ), y < int (12 ))); // Boolean logic
9192 post! (m , x % int (3 ) != int (0 )); // Modulo operations
9293
9394 // Global constraints
9495 post! (m , alldiff ([x , y ])); // All different
96+ post! (m , allequal ([x , y ])); // All equal
97+
98+ // Ordering constraints - powerful ternary relationships
99+ post! (m , between (x , y , z )); // x <= y <= z (ordering constraint)
100+
101+ // Cardinality constraints - counting with fine-grained control
102+ let tasks = vec! [m . int (1 , 3 ), m . int (1 , 3 ), m . int (1 , 3 )]; // 1=low, 2=medium, 3=high priority
103+ post! (m , at_least (tasks . clone (), int (3 ), int (1 ))); // At least 1 high priority task
104+ post! (m , at_most (tasks . clone (), int (1 ), int (2 ))); // At most 2 low priority tasks
105+ post! (m , exactly (tasks , int (2 ), int (1 ))); // Exactly 1 medium priority task
106+
107+ // Conditional constraints - if-then logic
108+ post! (m , if_then (x == int (5 ), y == int (10 ))); // If x=5 then y=10
109+
110+ // Count constraint - count how many variables equal a value
111+ let workers = vec! [m . int (1 , 3 ), m . int (1 , 3 ), m . int (1 , 3 )]; // 1=day, 2=evening, 3=night
112+ let night_count = m . int (1 , 2 ); // 1-2 workers on night shift
113+ post! (m , count (workers , int (3 ), night_count )); // Count night shift workers
114+
115+ // Table constraint - specify valid combinations explicitly
116+ let cpu = m . int (1 , 2 ); // 1=Intel, 2=AMD
117+ let gpu = m . int (1 , 2 ); // 1=NVIDIA, 2=AMD
118+ let compatible_configs = vec! [
119+ vec! [int (1 ), int (1 )], // Intel CPU + NVIDIA GPU
120+ vec! [int (1 ), int (2 )], // Intel CPU + AMD GPU
121+ vec! [int (2 ), int (2 )], // AMD CPU + AMD GPU
122+ // Note: AMD CPU + NVIDIA GPU not included (incompatible)
123+ ];
124+ post! (m , table ([cpu , gpu ], compatible_configs )); // Only valid combinations allowed
125+
126+ // Element constraint (array indexing)
127+ let array = vec! [x , y , z ];
128+ let index = m . int (0 , 2 );
129+ let value = m . int (1 , 20 );
130+ post! (m , array [index ] == value ); // Natural x[y] = z syntax
95131
96- if let Some (solution ) = m . solve () {
132+ if let Ok (solution ) = m . solve () {
97133 println! (" x = {:?}" , solution [x ]);
98134 println! (" y = {:?}" , solution [y ]);
99135 println! (" z = {:?}" , solution [z ]);
@@ -112,24 +148,110 @@ fn main() {
112148
113149 // Complex mathematical expressions
114150 post! (m , sum (vars . clone ()) <= int (12 ));
115- post! (m , max ([vars [0 ]]) >= min ([vars [1 ]]));
151+ post! (m , max (vars . clone ()) >= int (3 )); // Maximum of vars >= 3
152+ post! (m , min (vars . clone ()) <= int (4 )); // Minimum of vars <= 4
116153
117154 // Boolean logic with traditional syntax
118155 let a = m . bool ();
119156 let b = m . bool ();
120- post! (m , and (a , b )); // Boolean AND
121- post! (m , or (a , not (b ))); // Boolean OR with NOT
157+ let c = m . bool ();
158+ let d = m . bool ();
159+
160+ post! (m , and (a , b )); // Traditional 2-argument AND
161+ post! (m , or (a , b )); // Boolean OR
162+ post! (m , not (b )); // Boolean NOT
163+ post! (m , and ([a , b , c , d ])); // Array syntax for multiple variables
164+ post! (m , or (a , b , c , d )); // Variadic syntax for multiple variables
165+ post! (m , not ([a , b , c ])); // Array NOT (applies to each variable)
166+
167+ // Count constraints - powerful cardinality constraints
168+ let students = vec! [m . int (1 , 3 ), m . int (1 , 3 ), m . int (1 , 3 ), m . int (1 , 3 )]; // 4 students, 3 sections
169+ let section1_count = m . int (2 , 2 ); // Exactly 2 students in section 1
170+ let section2_count = m . int (1 , 2 ); // 1-2 students in section 2
171+
172+ post! (m , count (students . clone (), int (1 ), section1_count )); // Count students in section 1
173+ post! (m , count (students , int (2 ), section2_count )); // Count students in section 2
174+
175+ // Advanced cardinality constraints with precise control
176+ let employees = vec! [m . int (1 , 4 ), m . int (1 , 4 ), m . int (1 , 4 ), m . int (1 , 4 ), m . int (1 , 4 )]; // 5 employees, 4 departments
177+ post! (m , at_least (employees . clone (), int (1 ), int (2 ))); // At least 2 in department 1
178+ post! (m , at_most (employees . clone (), int (4 ), int (1 ))); // At most 1 in department 4
179+ post! (m , exactly (employees , int (2 ), int (2 ))); // Exactly 2 in department 2
180+
181+ // Ordering constraints for complex relationships
182+ let start_time = m . int (9 , 17 ); // 9 AM to 5 PM
183+ let meeting_time = m . int (9 , 17 ); // Meeting time
184+ let end_time = m . int (9 , 17 ); // End time
185+ post! (m , between (start_time , meeting_time , end_time )); // start <= meeting <= end
186+
187+ // Conditional constraints for business logic
188+ let is_weekend = m . int (0 , 1 ); // 0=weekday, 1=weekend
189+ let hours_open = m . int (8 , 12 ); // Store hours
190+ post! (m , if_then (is_weekend == int (1 ), hours_open == int (8 ))); // Weekend stores open 8 hours
191+
192+ // Table constraints - express complex relationships with lookup tables
193+ let time = m . int (1 , 4 ); // Time slots: 1=9AM, 2=11AM, 3=1PM, 4=3PM
194+ let room = m . int (1 , 3 ); // Rooms: 1=Lab, 2=Classroom, 3=Auditorium
195+ let capacity = m . int (10 , 100 ); // Room capacity
122196
123- // Mixed type constraints
197+ // Room availability and capacity table: (time, room, capacity)
198+ let schedule_table = vec! [
199+ vec! [int (1 ), int (1 ), int (20 )], // 9AM: Lab has 20 capacity
200+ vec! [int (1 ), int (2 ), int (30 )], // 9AM: Classroom has 30 capacity
201+ vec! [int (2 ), int (2 ), int (30 )], // 11AM: Classroom has 30 capacity
202+ vec! [int (2 ), int (3 ), int (100 )], // 11AM: Auditorium has 100 capacity
203+ vec! [int (3 ), int (1 ), int (20 )], // 1PM: Lab has 20 capacity
204+ vec! [int (4 ), int (3 ), int (100 )], // 3PM: Auditorium has 100 capacity
205+ // Note: Some time/room combinations unavailable (maintenance, etc.)
206+ ];
207+ post! (m , table ([time , room , capacity ], schedule_table ));
208+
209+ // Mixed type constraints with float
124210 let float_var = m . float (1.0 , 10.0 );
125- post! (m , abs (float_var ) + vars [ 0 ] <= float (15 .0 ));
211+ post! (m , abs (float_var ) <= float (12 .0 ));
126212
127- if let Some (solution ) = m . solve () {
213+ if let Ok (solution ) = m . solve () {
128214 println! (" Solution found!" );
129215 }
130216}
131217```
132218
219+ ### New Constraint Types (v0.5.11+)
220+
221+ The latest version includes powerful new constraint types for advanced modeling:
222+
223+ #### Between Constraints
224+ Enforce ternary ordering relationships with a single constraint:
225+ ``` rust
226+ let start = m . int (1 , 10 );
227+ let middle = m . int (5 , 15 );
228+ let end = m . int (10 , 20 );
229+ post! (m , between (start , middle , end )); // start <= middle <= end
230+ ```
231+
232+ #### Cardinality Constraints
233+ Precise counting control for resource allocation and capacity planning:
234+ ``` rust
235+ let workers = vec! [m . int (1 , 3 ), m . int (1 , 3 ), m . int (1 , 3 ), m . int (1 , 3 )]; // 4 workers, 3 shifts
236+ post! (m , at_least (workers . clone (), int (3 ), int (2 ))); // At least 2 on night shift (3)
237+ post! (m , at_most (workers . clone (), int (1 ), int (1 ))); // At most 1 on day shift (1)
238+ post! (m , exactly (workers , int (2 ), int (1 ))); // Exactly 1 on evening shift (2)
239+ ```
240+
241+ #### Conditional Constraints
242+ Business logic and dependency modeling with if-then-else:
243+ ``` rust
244+ let weather = m . int (1 , 3 ); // 1=sunny, 2=cloudy, 3=rainy
245+ let activity = m . int (1 , 3 ); // 1=hiking, 2=museum, 3=shopping
246+ let backup = m . int (1 , 3 ); // Backup activity
247+
248+ // If sunny (1) then hiking (1), if rainy (3) then shopping (3)
249+ post! (m , if_then (weather == int (1 ), activity == int (1 )));
250+ post! (m , if_then (weather == int (3 ), activity == int (3 )));
251+ ```
252+
253+ These constraints work seamlessly with the existing ` post! ` macro system and provide both helper methods and natural syntax for maximum usability.
254+
133255
134256
135257## License
0 commit comments