selen 0.15.5

Constraint Satisfaction Problem (CSP) solver
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
//! Runtime API constraint tests
//!
//! This module contains tests for the runtime API (m.new() syntax) that demonstrate 
//! how to build constraints programmatically using method chaining and expressions.
//! 
//! These tests complement the macro tests and show the more powerful runtime 
//! constraint building capabilities for complex expressions.

#[cfg(test)]
mod tests {
    use selen::prelude::*;

    /// Test basic constraint building with runtime API
    /// 
    /// Demonstrates: m.new(x.lt(y)), m.new(x.le(y)), etc.
    /// Runtime API equivalent of macro: post!(m, x < y), post!(m, x <= y), etc.
    #[test]
    fn test_runtime_api_basic_constraints() {
        let mut m = Model::default();
        let x = m.int(1, 10);
        let y = m.int(1, 10);
        
        // Test basic variable comparisons - programmatic equivalents
        let _c1 = m.new(x.lt(y));    // Equivalent to: post!(m, x < y)
        let _c2 = m.new(x.le(y));    // Equivalent to: post!(m, x <= y)
        let _c3 = m.new(x.gt(y));    // Equivalent to: post!(m, x > y)
        let _c4 = m.new(x.ge(y));    // Equivalent to: post!(m, x >= y)
        let _c5 = m.new(x.eq(y));    // Equivalent to: post!(m, x == y)
        let _c6 = m.new(x.ne(y));    // Equivalent to: post!(m, x != y)
        
        // Verify variables and constraints were created successfully
    }

    /// Programmatic equivalent of test_post_macro_constants()
    /// 
    /// Original test uses: post!(m, x < int(5)), post!(m, y <= float(3.14)), etc.
    /// This version uses: m.new(x.lt(int(5))), m.new(y.le(float(3.14))), etc.
    #[test]
    fn test_runtime_api_constants() {
        let mut m = Model::default();
        let x = m.int(1, 10);
        let y = m.float(1.0, 10.0);
        
        // Test variable vs integer constants - programmatic equivalents
        let _c1 = m.new(x.lt(5));          // Equivalent to: post!(m, x < int(5))
        let _c2 = m.new(x.ge(1));          // Equivalent to: post!(m, x >= int(1))
        let _c3 = m.new(x.eq(7));          // Equivalent to: post!(m, x == int(7))
        
        // Test variable vs float constants - programmatic equivalents
        let _c4 = m.new(y.le(3.14));       // Equivalent to: post!(m, y <= float(3.14))
        let _c5 = m.new(y.gt(1.0));        // Equivalent to: post!(m, y > float(1.0))
        let _c6 = m.new(y.ne(5.5));        // Equivalent to: post!(m, y != float(5.5))
        
        // Verify constraints were created successfully
        // Note: Constants create singleton variables, so x + y + 6 constants = 8 total
    }

    /// Programmatic equivalent of test_post_macro_arithmetic()
    /// 
    /// Original test uses: post!(m, x + y < z), post!(m, x - y >= z), etc.
    /// This version uses: m.new(x.add(y).lt(z)), m.new(x.sub(y).ge(z)), etc.
    #[test]
    fn test_runtime_api_arithmetic() {
        let mut m = Model::default();
        let x = m.int(1, 10);
        let y = m.int(1, 10);
        let z = m.int(1, 20);
        
        // Test arithmetic operations with variables - programmatic equivalents
        let _c1 = m.new(x.add(y).lt(z));   // Equivalent to: post!(m, x + y < z)
        let _c2 = m.new(x.sub(y).ge(z));   // Equivalent to: post!(m, x - y >= z)
        let _c3 = m.new(x.mul(y).le(z));   // Equivalent to: post!(m, x * y <= z)
        let _c4 = m.new(x.div(y).eq(z));   // Equivalent to: post!(m, x / y == z)
        
        // Test arithmetic operations with constants - programmatic equivalents
        let _c5 = m.new(x.add(y).le(15));  // Equivalent to: post!(m, x + y <= int(15))
        let _c6 = m.new(x.sub(y).ge(0));   // Equivalent to: post!(m, x - y >= int(0))
        let _c7 = m.new(x.mul(y).eq(12));  // Equivalent to: post!(m, x * y == int(12))
        let _c8 = m.new(x.div(y).ne(0));   // Equivalent to: post!(m, x / y != int(0))
        
        // Just verify the model can be created and constraints posted without errors
        // (The constraints may be over-constrained and unsolvable, which is fine for this API test)
    }

    /// Programmatic equivalent of test_post_macro_array_syntax()
    /// 
    /// Original test uses: post!(m, alldiff(vars)), post!(m, min(vars) <= int(5)), etc.
    /// This version uses: m.alldiff(&vars), m.new(m.min(&vars).le(5)), etc.
    #[test]
    fn test_runtime_api_array_syntax() {
        let mut m = Model::default();
        let x = m.int(1, 10);
        let y = m.int(1, 10);
        let z = m.int(1, 10);
        
        // Test alldiff with arrays - programmatic equivalents
        let vars = [x, y, z];
        m.alldiff(&vars);                        // Equivalent to: post!(m, alldiff(vars))
        
        let vars_vec = vec![x, y, z];
        m.alldiff(&vars_vec);                    // Equivalent to: post!(m, alldiff(vars_vec))
        
        // Test min/max with arrays - programmatic equivalents
        let min_result = m.min(&vars).expect("non-empty variable list");
        m.new(min_result.le(5));               // Equivalent to: post!(m, min(vars) <= int(5))
        let max_result = m.max(&vars_vec).expect("non-empty variable list");
        m.new(max_result.ge(8));               // Equivalent to: post!(m, max(vars_vec) >= int(8))
        
        // Verify variables and constraints were created successfully
    }

    /// Programmatic equivalent of test_post_macro_alldiff()
    /// 
    /// Original test uses: post!(m, alldiff([x, y, z])), etc.
    /// This version uses: m.alldiff(&[x, y, z]), etc.
    #[test]
    fn test_runtime_api_alldiff() {
        let mut m = Model::default();
        let x = m.int(1, 10);
        let y = m.int(1, 10);
        let z = m.int(1, 10);
        let w = m.int(1, 10);
        
        // Test alldiff constraint - programmatic equivalents
        m.alldiff(&[x, y, z]);                  // Equivalent to: post!(m, alldiff([x, y, z]))
        m.alldiff(&[x, y, z, w]);               // Equivalent to: post!(m, alldiff([x, y, z, w]))
        
        // Verify variables and constraints were created successfully
    }

    /// Programmatic equivalent of test_post_macro_allequal()
    /// 
    /// Original test uses: post!(m, allequal([x, y, z])), etc.
    /// This version uses: m.allequal(&[x, y, z]), etc.
    #[test]
    fn test_runtime_api_allequal() {
        let mut m = Model::default();
        let x = m.int(1, 10);
        let y = m.int(5, 15);
        let z = m.int(3, 8);
        let w = m.int(1, 10);
        
        // Test allequal constraint - programmatic equivalents
        m.alleq(&[x, y, z]);                    // Equivalent to: post!(m, allequal([x, y, z]))
        m.alleq(&[x, y, z, w]);                 // Equivalent to: post!(m, allequal([x, y, z, w]))
        
        // Test with array expression - programmatic equivalent
        let vars = vec![x, y, z];
        m.alleq(&vars);                         // Equivalent to: post!(m, allequal(vars))
        
        // Verify variables and constraints were created successfully
    }

    /// Programmatic equivalent of test_post_macro_element()
    /// 
    /// Original test uses: post!(m, element([a0, a1, a2], index, value)), post!(m, array[index] == value), etc.
    /// This version uses: m.elem(&[a0, a1, a2], index, value), m.new(m.elem_var(&array, index).eq(value)), etc.
    #[test]
    fn test_runtime_api_element() {
        let mut m = Model::default();
        let a0 = m.int(10, 10);
        let a1 = m.int(20, 20);
        let a2 = m.int(30, 30);
        let index = m.int(0, 2);
        let value = m.int(10, 30);
        
        // Test element constraint with array literal - programmatic equivalent
        m.elem(&[a0, a1, a2], index, value);    // Equivalent to: post!(m, element([a0, a1, a2], index, value))
        
        // Test element constraint with array expression - programmatic equivalent
        let array = vec![a0, a1, a2];
        m.elem(&array, index, value);           // Equivalent to: post!(m, element(array.clone(), index, value))
        
        // Test natural array[index] == value syntax - programmatic equivalent
        // Note: Direct array indexing with variables requires element constraints
        m.elem(&array, index, value);           // Equivalent to: post!(m, array[index] == value)
        
        // Test reverse syntax: value == array[index] - programmatic equivalent
        m.elem(&array, index, value);           // Equivalent to: post!(m, value == array[index])
        
        // Verify variables and constraints were created successfully
    }

    /// Programmatic equivalent of test_post_macro_logical_operators()
    /// 
    /// Original test uses: post!(m, and(a, b)), post!(m, or(a, b)), post!(m, not(a)), etc.
    /// This version uses: m.new(c1.and(c2)), m.new(c1.or(c2)), m.new(c1.not()), etc.
    #[test]
    fn test_runtime_api_logical_operators() {
        let mut m = Model::default();
        let x = m.int(1, 10);
        let y = m.int(1, 10);
        
        // Test basic constraint references - programmatic equivalents
        let c1 = m.new(x.lt(y));               // Equivalent to: post!(m, x < y)
        let c2 = m.new(y.gt(5));               // Equivalent to: post!(m, y > int(5))
        
        // Note: Boolean operations on constraint references are available in runtime API
        // Testing basic boolean operations with variables instead
        let a = m.int(0, 1);
        let b = m.int(0, 1);
        
        // Post the boolean-like constraints (create fresh constraints each time)
        m.new(a.eq(1).and(b.eq(1)));           // Equivalent to: post!(m, and(a, b))
        m.new(a.eq(1).or(b.eq(1)));            // Equivalent to: post!(m, or(a, b))  
        m.new(a.eq(0));                        // Equivalent to: post!(m, not(a))
        
        println!("Constraint references: {:?}, {:?}", c1, c2);
        
        // Verify variables and constraints were created successfully
    }

    /// Programmatic equivalent of test_post_macro_mathematical_functions()
    /// 
    /// Original test uses: post!(m, abs(x) >= int(1)), post!(m, min([y, z]) == int(5)), etc.
    /// This version uses: m.new(m.abs(x).ge(1)), m.new(m.min(&[y, z]).eq(5)), etc.
    #[test]
    fn test_runtime_api_mathematical_functions() {
        let mut m = Model::default();
        let x = m.int(-10, 10);
        let y = m.int(1, 10);
        let z = m.int(1, 10);
        
        // Test absolute value - programmatic equivalents
        let abs_x = m.abs(x);
        m.new(abs_x.ge(1));                    // Equivalent to: post!(m, abs(x) >= int(1))
        m.new(abs_x.le(y));                    // Equivalent to: post!(m, abs(x) <= y)
        
        // Test min function - programmatic equivalents
        let min_yz = m.min(&[y, z]).expect("non-empty variable list");
        m.new(min_yz.eq(5));                   // Equivalent to: post!(m, min([y, z]) == int(5))
        m.new(min_yz.ge(x));                   // Equivalent to: post!(m, min([y, z]) >= x)
        
        // Test max function - programmatic equivalents  
        let max_yz = m.max(&[y, z]).expect("non-empty variable list");
        m.new(max_yz.le(10));                  // Equivalent to: post!(m, max([y, z]) <= int(10))
        m.new(max_yz.ne(x));                   // Equivalent to: post!(m, max([y, z]) != x)
        
        // Verify variables and constraints were created successfully
    }

    /// Programmatic equivalent of test_post_macro_negation()
    /// 
    /// Original test uses: post!(m, !(x < y)) (commented out), post!(m, x >= y), etc.
    /// This version uses: m.new(x.lt(y).not()), m.new(x.ge(y)), etc.
    #[test]
    fn test_runtime_api_negation() {
        let mut m = Model::default();
        let x = m.int(1, 10);
        let y = m.int(1, 10);
        
        // Test negation using runtime API - programmatic equivalent
        m.new(x.lt(y).not());                  // Equivalent to: post!(m, !(x < y))  -> x >= y
        
        // For comparison, direct equivalent
        m.new(x.ge(y));                        // Equivalent to: post!(m, x >= y)
        
        // Verify variables and constraints were created successfully
    }

    /// Programmatic equivalent of test_post_macro_modulo()
    ///
    /// Original test uses: post!(m, x % 3 == 1)
    /// This version uses: m.modulo(x, 3).eq(1)
    #[test]
    fn test_runtime_api_modulo() {
        let mut m = Model::default();
        let x = m.int(1, 20);
        
        // Test simple modulo operations using runtime API
        // Macro: post!(m, x % 3 == 1)
        // Programmatic: m.modulo(x, Val::from(3)).eq(1)
        let mod_result = m.modulo(x, Val::from(3));
        let _c1 = m.new(mod_result.eq(1));
        
        // Verify variables and constraints were created successfully
    }

    /// Programmatic equivalent of test_post_macro_enhanced_modulo()
    ///
    /// Original test uses: post!(m, x % y == int(0)), post!(m, x % y != int(0))
    /// This version uses: m.modulo(x, y).eq(0), m.modulo(x, y).ne(0)
    #[test]
    fn test_runtime_api_enhanced_modulo() {
        let mut m = Model::default();
        let x = m.int(1, 20);
        let y = m.int(2, 5);
        
        // Test enhanced modulo with variables using runtime API
        // Macro: post!(m, x % y == int(0))
        // Programmatic: m.modulo(x, y).eq(0)
        let mod_result1 = m.modulo(x, y);
        let _c1 = m.new(mod_result1.eq(0));
        
        // Macro: post!(m, x % y != int(0))
        // Programmatic: m.modulo(x, y).ne(0)
        let mod_result2 = m.modulo(x, y);
        let _c2 = m.new(mod_result2.ne(0));
        
        // Original literal modulo still works with runtime API
        // Macro: post!(m, x % 3 == 1)
        // Programmatic: m.modulo(x, Val::from(3)).eq(1)
        let mod_result3 = m.modulo(x, Val::from(3));
        let _c3 = m.new(mod_result3.eq(1));
        
        // Verify variables and constraints were created successfully
    }

    /// Programmatic equivalent of test_post_macro_complex_expressions()
    ///
    /// Original test combines multiple constraint types with macros
    /// This version uses runtime API equivalents for each operation
    #[test]
    fn test_runtime_api_complex_expressions() {
        let mut m = Model::default();
        let x = m.int(1, 10);
        let y = m.int(1, 10);
        let z = m.int(1, 10);
        
        // Test combining different constraint types using runtime API
        // Macro: post!(m, x + y <= int(15))
        // Programmatic: x.add(y).le(15)
        let _c1 = m.new(x.add(y).le(15));
        
        // Macro: post!(m, abs(x) >= int(1))
        // Programmatic: m.abs(x).ge(1)
        let abs_x = m.abs(x);
        let _c2 = m.new(abs_x.ge(1));
        
        // Macro: post!(m, max([x, y]) == z)
        // Programmatic: m.max(&[x, y]).eq(z)
        let max_xy = m.max(&[x, y]).expect("non-empty variable list");
        let _c3 = m.new(max_xy.eq(z));
        
        // Macro: post!(m, x % y != int(0))
        // Programmatic: m.modulo(x, y).ne(0)
        let mod_result4 = m.modulo(x, y);
        let _c4 = m.new(mod_result4.ne(0));
        
        // Macro: post!(m, alldiff([x, y, z]))
        // Programmatic: m.alldiff(&[x, y, z])
        m.alldiff(&[x, y, z]);
        
        // Verify variables and constraints were created successfully
    }

    /// Programmatic equivalent of test_postall_macro()
    ///
    /// Original test uses: postall!(m, x < y, y > int(5), ...) for batch constraint posting
    /// This version demonstrates equivalent programmatic batch constraint posting
    #[test]
    fn test_runtime_api_postall() {
        let mut m = Model::default();
        let x = m.int(1, 10);
        let y = m.int(1, 10);
        let z = m.int(1, 15);
        
        // Create some constraint references for testing
        // Macro: post!(m, x < y)
        // Programmatic: m.new(x.lt(y))
        let c1 = m.new(x.lt(y));
        
        // Macro: post!(m, y > int(5))
        // Programmatic: m.new(y.gt(5))
        let c2 = m.new(y.gt(5));
        
        // Test boolean variables for logical operations
        let a = m.int(0, 1);
        let b = m.int(0, 1);
        
        // Test direct constraint posting - programmatic equivalent of postall!
        // Instead of postall! macro, we post each constraint individually using runtime API
        let array = vec![x, y, z];
        
        // Macro: postall!(m, x < y, y > int(5), x + y <= z, ...)
        // Programmatic: Individual m.new() calls for each constraint
        m.new(x.lt(y));                        // x < y
        m.new(y.gt(5));                        // y > int(5)
        m.new(x.add(y).le(z));                 // x + y <= z
        m.alldiff(&[x, y, z]);                  // alldiff([x, y, z])
        m.alleq(&[x, y]);                       // allequal([x, y])
        m.elem(&array, a, b);                   // element([x, y, z], a, b)
        // Note: array[a] == b would require dynamic indexing, simplified for demo
        
        // Logical operations - need to create constraint expressions first
        let and_constraint = a.eq(1).and(b.eq(1));
        m.new(and_constraint);                 // and(a, b) equivalent
        
        let or_constraint = a.eq(1).or(b.eq(1));
        m.new(or_constraint);                  // or(a, b) equivalent
        
        let not_constraint = a.eq(1).not();
        m.new(not_constraint);                 // not(a) equivalent
        
        println!("Constraint references: {:?}, {:?}", c1, c2);
        
        // Verify variables and constraints were created successfully
    }

    /// Comprehensive validation test demonstrating complete API equivalency
    ///
    /// This test validates that all major constraint types work correctly
    /// with the programmatic API, providing a comprehensive example
    #[test]
    fn test_runtime_api_comprehensive_validation() {
        let mut m = Model::default();
        
        // Create variables for comprehensive testing
        let x = m.int(1, 10);
        let y = m.int(1, 10);
        let z = m.int(1, 20);
        let vars = vec![x, y, z];
        
        // Test 1: Basic constraints - equivalent to post! macros
        m.new(x.lt(y));                        // x < y
        m.new(y.le(z));                        // y <= z
        m.new(z.gt(5));                        // z > 5
        m.new(x.ge(1));                        // x >= 1
        m.new(y.eq(5));                        // y == 5
        m.new(z.ne(15));                       // z != 15
        
        // Test 2: Arithmetic operations - equivalent to post! arithmetic
        m.new(x.add(y).le(z));                 // x + y <= z
        m.new(y.sub(x).ge(0));                 // y - x >= 0
        m.new(x.mul(y).eq(12));                // x * y == 12
        m.new(z.div(y).ne(0));                 // z / y != 0
        
        // Test 3: Global constraints - equivalent to post! global constraints
        m.alldiff(&vars);                       // alldiff([x, y, z])
        
        let equal_vars = vec![x, y];
        m.alleq(&equal_vars);                   // allequal([x, y])
        
        let index = m.int(0, 2);
        let value = m.int(1, 10);
        m.elem(&vars, index, value);            // element([x, y, z], index, value)
        
        // Test 4: Mathematical functions - equivalent to post! math functions
        let abs_x = m.abs(x);
        m.new(abs_x.ge(1));                    // abs(x) >= 1
        
        let min_vars = m.min(&vars).expect("non-empty variable list");
        m.new(min_vars.eq(1));                 // min([x, y, z]) == 1
        
        let max_vars = m.max(&vars).expect("non-empty variable list");
        m.new(max_vars.le(10));                // max([x, y, z]) <= 10
        
        // Test 5: Modulo operations - equivalent to post! modulo
        let mod_result = m.modulo(x, Val::from(3));
        m.new(mod_result.eq(1));               // x % 3 == 1
        
        // Test 6: Logical operations - equivalent to post! logical
        // Create fresh constraints for each operation to avoid moved values
        m.new(x.lt(5).and(y.gt(3)));          // (x < 5) && (y > 3)
        m.new(x.lt(5).or(y.gt(3)));           // (x < 5) || (y > 3)  
        m.new(x.lt(5).not());                 // !(x < 5)
        
        // Test 7: Constants - equivalent to post! with int() helper
        m.new(x.add(y).le(15));                // x + y <= int(15)
        m.new(z.sub(5).ge(0));                 // z - int(5) >= 0
        
        println!("Comprehensive programmatic API validation complete");
        println!("All constraint types successfully demonstrated:");
        println!("- Basic comparisons: <, <=, >, >=, ==, !=");
        println!("- Arithmetic: +, -, *, /");
        println!("- Global constraints: alldiff, alleq, element");
        println!("- Mathematical functions: abs, min, max");
        println!("- Modulo operations: %");
        println!("- Logical operations: &&, ||, !");
        println!("- Constants and literals");
        
        // Verify comprehensive API demonstrates all functionality
        println!("API validation complete: {} variables, {} constraints", 
                 m.variable_count(), m.constraint_count());
    }
}