@@ -6,12 +6,13 @@ use std::{
6
6
7
7
use itertools:: Itertools ;
8
8
use num_traits:: Zero ;
9
- use powdr_number:: FieldElement ;
9
+ use powdr_number:: { log2_exact , FieldElement } ;
10
10
11
11
use crate :: witgen:: jit:: effect:: Assertion ;
12
12
13
13
use super :: {
14
- super :: range_constraints:: RangeConstraint , effect:: Effect ,
14
+ super :: range_constraints:: RangeConstraint ,
15
+ effect:: { BitDecomposition , BitDecompositionComponent , Effect } ,
15
16
symbolic_expression:: SymbolicExpression ,
16
17
} ;
17
18
@@ -215,23 +216,19 @@ impl<T: FieldElement, V: Ord + Clone + Display> AffineSymbolicExpression<T, V> {
215
216
}
216
217
_ => {
217
218
let r = self . solve_bit_decomposition ( ) ?;
219
+
218
220
if r. complete {
219
221
r
220
222
} else {
221
223
let negated = -self ;
222
- let r = negated. solve_bit_decomposition ( ) ?;
223
- if r. complete {
224
- r
225
- } else {
226
- let effects = self
227
- . transfer_constraints ( )
228
- . into_iter ( )
229
- . chain ( negated. transfer_constraints ( ) )
230
- . collect ( ) ;
231
- ProcessResult {
232
- effects,
233
- complete : false ,
234
- }
224
+ let effects = self
225
+ . transfer_constraints ( )
226
+ . into_iter ( )
227
+ . chain ( negated. transfer_constraints ( ) )
228
+ . collect ( ) ;
229
+ ProcessResult {
230
+ effects,
231
+ complete : false ,
235
232
}
236
233
}
237
234
}
@@ -257,41 +254,55 @@ impl<T: FieldElement, V: Ord + Clone + Display> AffineSymbolicExpression<T, V> {
257
254
258
255
// Check if they are mutually exclusive and compute assignments.
259
256
let mut covered_bits: <T as FieldElement >:: Integer = 0 . into ( ) ;
260
- let mut effects = vec ! [ ] ;
261
- for ( var, coeff, constraint) in constrained_coefficients {
262
- let mask = * constraint. multiple ( coeff) . mask ( ) ;
263
- if !( mask & covered_bits) . is_zero ( ) {
257
+ let mut components = vec ! [ ] ;
258
+ for ( variable, coeff, constraint) in constrained_coefficients {
259
+ let is_negative = !coeff. is_in_lower_half ( ) ;
260
+ let coeff_abs = if is_negative { -coeff } else { coeff } ;
261
+ let Some ( exponent) = log2_exact ( coeff_abs. to_arbitrary_integer ( ) ) else {
262
+ // We could work with non-powers of two, but it would require
263
+ // division instead of shifts.
264
+ return Ok ( ProcessResult :: empty ( ) ) ;
265
+ } ;
266
+ let bit_mask = * constraint. multiple ( coeff_abs) . mask ( ) ;
267
+ if !( bit_mask & covered_bits) . is_zero ( ) {
264
268
// Overlapping range constraints.
265
269
return Ok ( ProcessResult :: empty ( ) ) ;
266
270
} else {
267
- covered_bits |= mask ;
271
+ covered_bits |= bit_mask ;
268
272
}
269
- let masked = -& self . offset & mask;
270
- effects. push ( Effect :: Assignment (
271
- var. clone ( ) ,
272
- masked. integer_div ( & coeff. into ( ) ) ,
273
- ) ) ;
273
+ components. push ( BitDecompositionComponent {
274
+ variable,
275
+ // We negate here because we are solving
276
+ // c_1 * x_1 + c_2 * x_2 + ... + offset = 0,
277
+ // instead of
278
+ // c_1 * x_1 + c_2 * x_2 + ... = offset.
279
+ is_negative : !is_negative,
280
+ exponent : exponent as u64 ,
281
+ bit_mask,
282
+ } ) ;
274
283
}
275
284
276
285
if covered_bits >= T :: modulus ( ) {
277
286
return Ok ( ProcessResult :: empty ( ) ) ;
278
287
}
279
288
280
- // We need to assert that the masks cover "-offset",
281
- // otherwise the equation is not solvable.
282
- // We assert -offset & !masks == 0
283
- if let Some ( offset) = self . offset . try_to_number ( ) {
284
- if ( -offset) . to_integer ( ) & !covered_bits != 0 . into ( ) {
285
- return Err ( Error :: ConflictingRangeConstraints ) ;
289
+ if !components. iter ( ) . any ( |c| c. is_negative ) {
290
+ // If all coefficients are positive and the offset is known, we can check
291
+ // that all bits are covered. If not, then there is no way to extract
292
+ // the components and thus we have a conflict.
293
+ if let Some ( offset) = self . offset . try_to_number ( ) {
294
+ if offset. to_integer ( ) & !covered_bits != 0 . into ( ) {
295
+ return Err ( Error :: ConflictingRangeConstraints ) ;
296
+ }
286
297
}
287
- } else {
288
- effects. push ( Assertion :: assert_eq (
289
- -& self . offset & !covered_bits,
290
- T :: from ( 0 ) . into ( ) ,
291
- ) ) ;
292
298
}
293
299
294
- Ok ( ProcessResult :: complete ( effects) )
300
+ Ok ( ProcessResult :: complete ( vec ! [ Effect :: BitDecomposition (
301
+ BitDecomposition {
302
+ value: self . offset. clone( ) ,
303
+ components,
304
+ } ,
305
+ ) ] ) )
295
306
}
296
307
297
308
fn transfer_constraints ( & self ) -> Option < Effect < T , V > > {
@@ -521,10 +532,9 @@ mod test {
521
532
let b = Ase :: from_unknown_variable ( "b" , rc. clone ( ) ) ;
522
533
let c = Ase :: from_unknown_variable ( "c" , rc. clone ( ) ) ;
523
534
let z = Ase :: from_known_symbol ( "Z" , Default :: default ( ) ) ;
524
- // a * 0x100 + b * 0x10000 + c * 0x1000000 + 10 + Z = 0
535
+ // a * 0x100 - b * 0x10000 + c * 0x1000000 + 10 + Z = 0
525
536
let ten = from_number ( 10 ) ;
526
- let constr = mul ( & a, & from_number ( 0x100 ) )
527
- + mul ( & b, & from_number ( 0x10000 ) )
537
+ let constr = mul ( & a, & from_number ( 0x100 ) ) - mul ( & b, & from_number ( 0x10000 ) )
528
538
+ mul ( & c, & from_number ( 0x1000000 ) )
529
539
+ ten. clone ( )
530
540
+ z. clone ( ) ;
@@ -533,38 +543,39 @@ mod test {
533
543
assert ! ( !result. complete && result. effects. is_empty( ) ) ;
534
544
// Now add the range constraint on a, it should be solvable.
535
545
let a = Ase :: from_unknown_variable ( "a" , rc. clone ( ) ) ;
536
- let constr = mul ( & a, & from_number ( 0x100 ) )
537
- + mul ( & b, & from_number ( 0x10000 ) )
546
+ let constr = mul ( & a, & from_number ( 0x100 ) ) - mul ( & b, & from_number ( 0x10000 ) )
538
547
+ mul ( & c, & from_number ( 0x1000000 ) )
539
548
+ ten. clone ( )
540
549
+ z;
541
550
let result = constr. solve ( ) . unwrap ( ) ;
542
551
assert ! ( result. complete) ;
543
- let effects = result
544
- . effects
545
- . into_iter ( )
546
- . map ( |effect| match effect {
547
- Effect :: Assignment ( v, expr) => format ! ( "{v} = {expr};\n " ) ,
548
- Effect :: Assertion ( Assertion {
549
- lhs,
550
- rhs,
551
- expected_equal,
552
- } ) => {
553
- format ! (
554
- "assert {lhs} {} {rhs};\n " ,
555
- if expected_equal { "==" } else { "!=" }
556
- )
557
- }
558
- _ => panic ! ( ) ,
552
+
553
+ let [ effect] = & result. effects [ ..] else {
554
+ panic ! ( ) ;
555
+ } ;
556
+ let Effect :: BitDecomposition ( BitDecomposition { value, components } ) = effect else {
557
+ panic ! ( ) ;
558
+ } ;
559
+ assert_eq ! ( format!( "{value}" ) , "(10 + Z)" ) ;
560
+ let formatted = components
561
+ . iter ( )
562
+ . map ( |c| {
563
+ format ! (
564
+ "{} = (({value} & 0x{:0x}) >> {}){};\n " ,
565
+ c. variable,
566
+ c. bit_mask,
567
+ c. exponent,
568
+ if c. is_negative { " [negative]" } else { "" }
569
+ )
559
570
} )
560
- . format ( "" )
561
- . to_string ( ) ;
571
+ . join ( "" ) ;
572
+
562
573
assert_eq ! (
563
- effects ,
564
- "a = ((-(10 + Z) & 0xff00) // 256);
565
- b = ((- (10 + Z) & 0xff0000) // 65536) ;
566
- c = ((- (10 + Z) & 0xff000000) // 16777216 );
567
- assert (-( 10 + Z) & 0xffffffff000000ff) == 0 ;
574
+ formatted ,
575
+ "\
576
+ a = (((10 + Z) & 0xff00) >> 8) [negative] ;
577
+ b = (((10 + Z) & 0xff0000) >> 16 );
578
+ c = ((( 10 + Z) & 0xff000000) >> 24) [negative] ;
568
579
"
569
580
) ;
570
581
}
0 commit comments