1
1
use std:: collections:: { BTreeMap , HashMap } ;
2
2
3
3
use powdr_ast:: {
4
- analyzed:: { AlgebraicExpression , PolynomialType , SelectedExpressions } ,
4
+ analyzed:: { AlgebraicExpression , PolyID , PolynomialType , SelectedExpressions } ,
5
5
parsed:: visitor:: AllChildren ,
6
6
} ;
7
7
use powdr_executor_utils:: expression_evaluator:: { ExpressionEvaluator , OwnedTerminalValues } ;
8
8
use powdr_number:: FieldElement ;
9
9
use rayon:: iter:: { IntoParallelIterator , ParallelIterator } ;
10
10
11
11
use crate :: witgen:: {
12
- data_structures:: identity:: convert_identities,
13
- machines:: {
14
- profiling:: { record_end, record_start} ,
15
- Connection ,
16
- } ,
12
+ data_structures:: identity:: { convert_identities, Identity } ,
13
+ machines:: profiling:: { record_end, record_start} ,
17
14
} ;
18
15
19
- use super :: FixedData ;
16
+ use super :: { util :: try_to_simple_poly , FixedData } ;
20
17
21
18
static MULTIPLICITY_WITGEN_NAME : & str = "multiplicity witgen" ;
22
19
@@ -30,28 +27,18 @@ impl<'a, T: FieldElement> MultiplicityColumnGenerator<'a, T> {
30
27
}
31
28
32
29
/// Takes a map of witness columns and extends it with the multiplicity columns
33
- /// reference in the phantom lookups .
30
+ /// referenced by bus sends with a non-binary multiplicity .
34
31
pub fn generate (
35
32
& self ,
36
33
witness_columns : HashMap < String , Vec < T > > ,
37
34
publics : BTreeMap < String , Option < T > > ,
38
35
) -> HashMap < String , Vec < T > > {
39
36
record_start ( MULTIPLICITY_WITGEN_NAME ) ;
40
37
41
- log:: trace!( "Starting multiplicity witness generation." ) ;
42
- let start = std:: time:: Instant :: now ( ) ;
43
-
44
- // Several range constraints might point to the same target
38
+ // A map from multiplicity column ID to the vector of multiplicities.
45
39
let mut multiplicity_columns = BTreeMap :: new ( ) ;
46
40
47
41
let ( identities, _) = convert_identities ( self . fixed . analyzed ) ;
48
- let phantom_lookups = identities
49
- . iter ( )
50
- . filter_map ( |identity| {
51
- Connection :: try_new ( identity, & self . fixed . bus_receives )
52
- . and_then ( |connection| connection. multiplicity_column . map ( |_| connection) )
53
- } )
54
- . collect :: < Vec < _ > > ( ) ;
55
42
56
43
let all_columns = witness_columns
57
44
. into_iter ( )
@@ -78,64 +65,65 @@ impl<'a, T: FieldElement> MultiplicityColumnGenerator<'a, T> {
78
65
challenge_values : self . fixed . challenges . clone ( ) ,
79
66
} ;
80
67
81
- log:: trace!(
82
- " Done building trace values, took: {}s" ,
83
- start. elapsed( ) . as_secs_f64( )
84
- ) ;
85
-
86
- for lookup in phantom_lookups {
87
- log:: trace!( " Updating multiplicity for phantom lookup: {lookup}" ) ;
88
- let start = std:: time:: Instant :: now ( ) ;
89
-
90
- let ( rhs_machine_size, rhs_tuples) = self . get_tuples ( & terminal_values, lookup. right ) ;
91
-
92
- log:: trace!(
93
- " Done collecting RHS tuples, took {}s" ,
94
- start. elapsed( ) . as_secs_f64( )
95
- ) ;
96
- let start = std:: time:: Instant :: now ( ) ;
97
-
98
- let index = rhs_tuples
99
- . iter ( )
100
- . map ( |( i, tuple) | {
101
- // There might be multiple identical rows, but it's fine, we can pick any.
102
- ( tuple, * i)
103
- } )
104
- . collect :: < HashMap < _ , _ > > ( ) ;
105
-
106
- log:: trace!(
107
- " Done building index, took {}s" ,
108
- start. elapsed( ) . as_secs_f64( )
109
- ) ;
110
- let start = std:: time:: Instant :: now ( ) ;
68
+ // Index all bus receives with arbitrary multiplicity.
69
+ let receive_infos = self
70
+ . fixed
71
+ . bus_receives
72
+ . iter ( )
73
+ . filter ( |( _, bus_receive) | {
74
+ bus_receive. has_arbitrary_multiplicity ( ) && bus_receive. multiplicity . is_some ( )
75
+ } )
76
+ . map ( |( bus_id, bus_receive) | {
77
+ let ( size, rhs_tuples) =
78
+ self . get_tuples ( & terminal_values, & bus_receive. selected_payload ) ;
111
79
112
- let ( _, lhs_tuples) = self . get_tuples ( & terminal_values, lookup. left ) ;
80
+ let index = rhs_tuples
81
+ . into_iter ( )
82
+ . map ( |( i, tuple) | {
83
+ // There might be multiple identical rows, but it's fine, we can pick any.
84
+ ( tuple, i)
85
+ } )
86
+ . collect :: < HashMap < _ , _ > > ( ) ;
87
+
88
+ let multiplicity = bus_receive. multiplicity . as_ref ( ) . unwrap ( ) ;
89
+ (
90
+ * bus_id,
91
+ ReceiveInfo {
92
+ multiplicity_column : try_to_simple_poly ( multiplicity)
93
+ . unwrap_or_else ( || {
94
+ panic ! ( "Expected simple reference, got: {multiplicity}" )
95
+ } )
96
+ . poly_id ,
97
+ size,
98
+ index,
99
+ } ,
100
+ )
101
+ } )
102
+ . collect :: < BTreeMap < _ , _ > > ( ) ;
113
103
114
- log:: trace!(
115
- " Done collecting LHS tuples, took: {}s" ,
116
- start. elapsed( ) . as_secs_f64( )
117
- ) ;
118
- let start = std:: time:: Instant :: now ( ) ;
104
+ // Increment multiplicities for all bus sends.
105
+ for ( bus_send, bus_receive) in identities. iter ( ) . filter_map ( |i| match i {
106
+ Identity :: BusSend ( bus_send) => receive_infos
107
+ . get ( & bus_send. bus_id ( ) . unwrap ( ) )
108
+ . map ( |bus_receive| ( bus_send, bus_receive) ) ,
109
+ _ => None ,
110
+ } ) {
111
+ let ( _, lhs_tuples) = self . get_tuples ( & terminal_values, & bus_send. selected_payload ) ;
119
112
120
- let multiplicity_column_id = lookup. multiplicity_column . unwrap ( ) ;
121
113
let multiplicities = multiplicity_columns
122
- . entry ( multiplicity_column_id )
123
- . or_insert_with ( || vec ! [ 0 ; rhs_machine_size ] ) ;
124
- assert_eq ! ( multiplicities. len( ) , rhs_machine_size ) ;
114
+ . entry ( bus_receive . multiplicity_column )
115
+ . or_insert_with ( || vec ! [ 0 ; bus_receive . size ] ) ;
116
+ assert_eq ! ( multiplicities. len( ) , bus_receive . size ) ;
125
117
126
118
// Looking up the index is slow, so we do it in parallel.
127
119
let indices = lhs_tuples
128
120
. into_par_iter ( )
129
- . map ( |( _, tuple) | index[ & tuple] )
121
+ . map ( |( _, tuple) | bus_receive . index [ & tuple] )
130
122
. collect :: < Vec < _ > > ( ) ;
131
123
132
124
for index in indices {
133
125
multiplicities[ index] += 1 ;
134
126
}
135
- log:: trace!(
136
- " Done updating multiplicities, took: {}s" ,
137
- start. elapsed( ) . as_secs_f64( )
138
- ) ;
139
127
}
140
128
141
129
let columns = terminal_values
@@ -206,3 +194,10 @@ impl<'a, T: FieldElement> MultiplicityColumnGenerator<'a, T> {
206
194
( machine_size, tuples)
207
195
}
208
196
}
197
+
198
+ struct ReceiveInfo < T > {
199
+ multiplicity_column : PolyID ,
200
+ size : usize ,
201
+ /// Maps a tuple of values to its index in the trace.
202
+ index : HashMap < Vec < T > , usize > ,
203
+ }
0 commit comments