11use super :: IntegrationTester ;
22use crate :: arithmetic:: CmpOp ;
3+ use crate :: csp:: Stmt ;
34use crate :: integration:: * ;
45
56struct Fuzzer {
@@ -69,13 +70,13 @@ impl Fuzzer {
6970 }
7071 }
7172
72- let mut exprs = vec ! [ ] ;
73+ let mut stmt_descs = vec ! [ ] ;
7374 for _ in 0 ..num_exprs {
74- let complexity = self . next_u32 ( max_complexity) ;
75-
76- let expr = self . random_bool_expr ( & bool_vars , & int_vars , complexity ) ;
77- exprs . push ( expr . clone ( ) ) ;
78- tester. add_expr ( expr ) ;
75+ let stmt = self . random_stmt ( & bool_vars , & int_vars , max_complexity) ;
76+ let mut buf = vec ! [ ] ;
77+ let _ = stmt . pretty_print ( & mut buf ) ;
78+ stmt_descs . push ( String :: from_utf8 ( buf ) . unwrap_or_default ( ) ) ;
79+ tester. add_constraint ( stmt ) ;
7980 }
8081
8182 if !tester. check_internal ( true ) {
@@ -85,18 +86,124 @@ impl Fuzzer {
8586 for desc in & int_var_descs {
8687 eprintln ! ( "- {}" , desc) ;
8788 }
88- eprintln ! ( "Expressions:" ) ;
89- for expr in exprs {
90- eprint ! ( "- " ) ;
91- let mut out_buf = vec ! [ ] ;
92- let _ = expr. pretty_print ( & mut out_buf) ;
93- eprint ! ( "{}" , String :: from_utf8( out_buf) . unwrap( ) ) ;
94- eprintln ! ( ) ;
89+ eprintln ! ( "Statements:" ) ;
90+ for desc in & stmt_descs {
91+ eprintln ! ( "- {}" , desc) ;
9592 }
9693 panic ! ( ) ;
9794 }
9895 }
9996
97+ fn random_stmt (
98+ & mut self ,
99+ bool_vars : & [ BoolVar ] ,
100+ int_vars : & [ IntVar ] ,
101+ max_complexity : u32 ,
102+ ) -> Stmt {
103+ // Weights: 0,1 = AllDifferent, 2 = ActiveVerticesConnected,
104+ // 3 (feature-gated) = ExtensionSupports, rest = BoolExpr
105+ #[ cfg( feature = "csp-extra-constraints" ) ]
106+ let mode = self . next_u32 ( 11 ) ;
107+ #[ cfg( not( feature = "csp-extra-constraints" ) ) ]
108+ let mode = self . next_u32 ( 10 ) ;
109+
110+ match mode {
111+ 0 | 1 => self . random_alldifferent_stmt ( bool_vars, int_vars, max_complexity) ,
112+ 2 => self . random_active_vertices_connected_stmt ( bool_vars, int_vars, max_complexity) ,
113+ #[ cfg( feature = "csp-extra-constraints" ) ]
114+ 3 => self . random_extension_supports_stmt ( bool_vars, int_vars) ,
115+ _ => {
116+ let complexity = self . next_u32 ( max_complexity) ;
117+ Stmt :: Expr ( self . random_bool_expr ( bool_vars, int_vars, complexity) )
118+ }
119+ }
120+ }
121+
122+ fn random_alldifferent_stmt (
123+ & mut self ,
124+ bool_vars : & [ BoolVar ] ,
125+ int_vars : & [ IntVar ] ,
126+ max_complexity : u32 ,
127+ ) -> Stmt {
128+ if int_vars. is_empty ( ) {
129+ let complexity = self . next_u32 ( max_complexity) ;
130+ return Stmt :: Expr ( self . random_bool_expr ( bool_vars, int_vars, complexity) ) ;
131+ }
132+ // 2 to 5 expressions
133+ let n = ( self . next_u32 ( 4 ) as usize + 2 ) . min ( 5 ) ;
134+ let exprs: Vec < IntExpr > = ( 0 ..n)
135+ . map ( |_| {
136+ let c = self . next_u32 ( max_complexity / 2 + 1 ) ;
137+ self . random_int_expr ( bool_vars, int_vars, c)
138+ } )
139+ . collect ( ) ;
140+ Stmt :: AllDifferent ( exprs)
141+ }
142+
143+ fn random_active_vertices_connected_stmt (
144+ & mut self ,
145+ bool_vars : & [ BoolVar ] ,
146+ int_vars : & [ IntVar ] ,
147+ max_complexity : u32 ,
148+ ) -> Stmt {
149+ if bool_vars. is_empty ( ) {
150+ let complexity = self . next_u32 ( max_complexity) ;
151+ return Stmt :: Expr ( self . random_bool_expr ( bool_vars, int_vars, complexity) ) ;
152+ }
153+ // 2 to 6 vertices
154+ let n = ( self . next_u32 ( 5 ) as usize + 2 ) . min ( bool_vars. len ( ) ) . max ( 2 ) ;
155+ let vertex_exprs: Vec < BoolExpr > = ( 0 ..n)
156+ . map ( |_| {
157+ let c = self . next_u32 ( max_complexity / 2 + 1 ) ;
158+ self . random_bool_expr ( bool_vars, int_vars, c)
159+ } )
160+ . collect ( ) ;
161+ let mut edges = vec ! [ ] ;
162+ for i in 0 ..n {
163+ for j in ( i + 1 ) ..n {
164+ if self . next_u32 ( 3 ) != 0 {
165+ edges. push ( ( i, j) ) ;
166+ }
167+ }
168+ }
169+ Stmt :: ActiveVerticesConnected ( vertex_exprs, edges)
170+ }
171+
172+ #[ cfg( feature = "csp-extra-constraints" ) ]
173+ fn random_extension_supports_stmt (
174+ & mut self ,
175+ _bool_vars : & [ BoolVar ] ,
176+ int_vars : & [ IntVar ] ,
177+ ) -> Stmt {
178+ if int_vars. is_empty ( ) {
179+ return Stmt :: Expr ( BoolExpr :: Const ( true ) ) ;
180+ }
181+ // 1 to 3 variables in the scope
182+ let n = ( self . next_u32 ( 3 ) as usize + 1 ) . min ( int_vars. len ( ) ) ;
183+ let exprs: Vec < IntExpr > = ( 0 ..n)
184+ . map ( |_| {
185+ let idx = self . next_u32 ( int_vars. len ( ) as u32 ) as usize ;
186+ int_vars[ idx] . expr ( )
187+ } )
188+ . collect ( ) ;
189+ // 1 to 6 support tuples; values in -3..=3 to match int var domains
190+ let n_tuples = self . next_u32 ( 6 ) as usize + 1 ;
191+ let mut supports = vec ! [ ] ;
192+ for _ in 0 ..n_tuples {
193+ let tuple: Vec < Option < i32 > > = ( 0 ..n)
194+ . map ( |_| {
195+ if self . next_u32 ( 5 ) == 0 {
196+ None // wildcard
197+ } else {
198+ Some ( self . next_i32 ( -3 , 4 ) )
199+ }
200+ } )
201+ . collect ( ) ;
202+ supports. push ( tuple) ;
203+ }
204+ Stmt :: ExtensionSupports ( exprs, supports)
205+ }
206+
100207 fn random_bool_expr (
101208 & mut self ,
102209 bool_vars : & [ BoolVar ] ,
@@ -173,7 +280,11 @@ impl Fuzzer {
173280 }
174281 }
175282
283+ #[ cfg( feature = "csp-extra-constraints" ) ]
284+ let mode = self . next_u32 ( 5 ) ;
285+ #[ cfg( not( feature = "csp-extra-constraints" ) ) ]
176286 let mode = self . next_u32 ( 4 ) ;
287+
177288 match mode {
178289 0 => {
179290 let cond_complexity = self . next_u32 ( complexity) ;
@@ -210,6 +321,16 @@ impl Fuzzer {
210321
211322 IntExpr :: Linear ( vec ! [ ( t1, scale1) , ( t2, scale2) ] )
212323 }
324+ #[ cfg( feature = "csp-extra-constraints" ) ]
325+ 4 => {
326+ let left_complexity = self . next_u32 ( complexity) ;
327+ let right_complexity = complexity - left_complexity - 1 ;
328+
329+ let lhs = Box :: new ( self . random_int_expr ( bool_vars, int_vars, left_complexity) ) ;
330+ let rhs = Box :: new ( self . random_int_expr ( bool_vars, int_vars, right_complexity) ) ;
331+
332+ IntExpr :: Mul ( lhs, rhs)
333+ }
213334 _ => unreachable ! ( ) ,
214335 }
215336 }
0 commit comments