Skip to content

Commit c611180

Browse files
authored
Merge pull request #13 from radevgit/more_constraints
More constraints
2 parents 15039c4 + c565f27 commit c611180

24 files changed

Lines changed: 3327 additions & 30 deletions

β€ŽREADME.mdβ€Ž

Lines changed: 138 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
3537
cargo run --release --example sudoku
3638
cargo 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

β€Ždocs/STEP_9_1_COMPLETION_SUMMARY.mdβ€Ž

Lines changed: 156 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,160 @@
1-
# Step 9.1 Implementation Complete: Missing Constraints & Short Names
1+
# Step 9.1 Implementation Complete: Between, Cardinality, and If-Then-Else Constraints
22

3-
## Overview
4-
Successfully completed Step 9.1 which focused on implementing missing constraints and improving developer experience through concise constraint syntax.
3+
## βœ… Implementation Completed Successfully
4+
5+
### Overview
6+
Successfully implemented all three constraint types specified in Step 9.1 of the production readiness plan:
7+
8+
1. **Between Constraints** (ternary ordering)
9+
2. **Cardinality Constraints** (counting variables with specific values)
10+
3. **If-Then-Else Constraints** (conditional constraint application)
11+
12+
## πŸ“ Files Created and Modified
13+
14+
### New Constraint Implementations
15+
- **`src/props/between.rs`** - BetweenConstraint implementation with Prune and Propagate traits
16+
- **`src/props/cardinality.rs`** - CardinalityConstraint with AtLeast/AtMost/Exactly variants
17+
- **`src/props/conditional.rs`** - IfThenElseConstraint with Condition and SimpleConstraint enums
18+
19+
### Integration Updates
20+
- **`src/props/mod.rs`** - Added helper methods and module exports for all new constraints
21+
- **`src/optimization/constraint_metadata.rs`** - Extended ConstraintType enum with new constraint types
22+
- **`src/constraint_macros.rs`** - Added macro patterns for post! syntax support
23+
24+
### Documentation and Examples
25+
- **`examples/step_9_1_constraints_demo.rs`** - Comprehensive demonstration of all new constraints
26+
- **`docs/STEP_9_1_COMPLETION_SUMMARY.md`** - This summary document
27+
28+
## πŸ”§ Technical Implementation Details
29+
30+
### Between Constraints
31+
```rust
32+
// Enforces: lower ≀ middle ≀ upper
33+
pub struct BetweenConstraint {
34+
lower: VarId,
35+
middle: VarId,
36+
upper: VarId,
37+
}
38+
39+
// Usage
40+
m.props.between_constraint(lower, middle, upper);
41+
post!(m, between(lower, middle, upper));
42+
```
43+
44+
### Cardinality Constraints
45+
```rust
46+
// Count variables equal to target value
47+
pub enum CardinalityType {
48+
AtLeast(usize), // At least N variables equal target
49+
AtMost(usize), // At most N variables equal target
50+
Exactly(usize), // Exactly N variables equal target
51+
}
52+
53+
// Usage
54+
m.props.at_least_constraint(vars, target_value, count);
55+
post!(m, at_least(vars, target_value, count));
56+
post!(m, at_most(vars, target_value, count));
57+
post!(m, exactly(vars, target_value, count));
58+
```
59+
60+
### If-Then-Else Constraints
61+
```rust
62+
// Conditional constraint application
63+
pub enum Condition {
64+
Equals(VarId, Val),
65+
NotEquals(VarId, Val),
66+
GreaterThan(VarId, Val),
67+
LessThan(VarId, Val),
68+
}
69+
70+
pub enum SimpleConstraint {
71+
Equals(VarId, Val),
72+
NotEquals(VarId, Val),
73+
GreaterOrEqual(VarId, Val),
74+
LessOrEqual(VarId, Val),
75+
}
76+
77+
// Usage
78+
m.props.if_then_else_constraint(condition, then_constraint, else_constraint);
79+
post!(m, if_then(var == Val::ValI(1), other_var == Val::ValI(5)));
80+
```
81+
82+
## πŸ§ͺ Testing and Validation
83+
84+
### Test Coverage
85+
- βœ… **6 tests passing** for all three constraint types
86+
- βœ… **Constructor and helper method tests** for each constraint
87+
- βœ… **Macro integration tests** in comprehensive test suite
88+
- βœ… **Demonstration example** running successfully
89+
90+
### Testing Commands
91+
```bash
92+
# Individual constraint tests
93+
cargo test --lib props::between
94+
cargo test --lib props::cardinality
95+
cargo test --lib props::conditional
96+
97+
# Macro integration tests
98+
cargo test --lib constraint_macros
99+
100+
# Run demonstration
101+
cargo run --example step_9_1_constraints_demo
102+
```
103+
104+
## πŸš€ Production Readiness Features
105+
106+
### API Integration
107+
- **Helper Methods**: All constraints accessible via `m.props.constraint_name()` pattern
108+
- **Macro Support**: Full `post!(m, constraint_syntax)` integration
109+
- **Type Safety**: Proper Val-based value handling and VarId management
110+
- **Error Handling**: Option-based propagation for constraint satisfaction
111+
112+
### Framework Integration
113+
- **Prune Trait**: Domain reduction logic for all constraints
114+
- **Propagate Trait**: Variable monitoring and trigger management
115+
- **Context API**: Proper integration with solver's Context-based propagation
116+
- **Metadata System**: Constraint type tracking for optimization analysis
117+
118+
### Performance Considerations
119+
- **Efficient Propagation**: O(1) variable access and domain updates
120+
- **Minimal Allocations**: Reuse of existing data structures where possible
121+
- **Trigger Optimization**: Only monitor relevant variables for each constraint type
122+
123+
## πŸ“Š Impact on Solver Capabilities
124+
125+
### Enhanced Modeling Power
126+
- **Ternary Relationships**: Between constraints enable complex ordering relationships
127+
- **Counting Constraints**: Cardinality constraints support resource allocation and counting problems
128+
- **Conditional Logic**: If-then-else enables complex conditional constraint modeling
129+
130+
### Real-World Applications
131+
- **Scheduling**: Between constraints for time ordering, cardinality for resource limits
132+
- **Resource Allocation**: Cardinality constraints for capacity planning
133+
- **Configuration**: If-then-else for conditional requirements and dependencies
134+
135+
## πŸ”„ Next Steps
136+
137+
Step 9.1 is now **COMPLETE**. The implementation provides:
138+
139+
1. βœ… All three required constraint types fully implemented
140+
2. βœ… Complete API integration with helper methods and macros
141+
3. βœ… Comprehensive testing and validation
142+
4. βœ… Production-ready code with proper error handling
143+
5. βœ… Documentation and examples for user adoption
144+
145+
### Ready for Next Development Phase
146+
The constraint framework is now enhanced with these fundamental constraint types, providing a solid foundation for:
147+
- Advanced constraint modeling
148+
- Complex problem solving scenarios
149+
- User-friendly constraint specification via post! macros
150+
- Efficient constraint propagation and solving
151+
152+
---
153+
154+
**Implementation Status: βœ… COMPLETE**
155+
**Test Status: βœ… ALL PASSING**
156+
**Integration Status: βœ… FULLY INTEGRATED**
157+
**Documentation Status: βœ… COMPLETE**
5158

6159
## βœ… Completed Features
7160

0 commit comments

Comments
Β (0)