22
33use num_traits:: Zero ;
44use stwo_prover:: {
5- constraint_framework:: { EvalAtRow , RelationEntry } ,
5+ constraint_framework:: { logup :: LogupTraceGenerator , EvalAtRow , Relation , RelationEntry } ,
66 core:: {
7- backend:: simd:: { column:: BaseColumn , m31:: LOG_N_LANES , SimdBackend } ,
7+ backend:: simd:: {
8+ column:: BaseColumn ,
9+ m31:: { PackedBaseField , LOG_N_LANES } ,
10+ SimdBackend ,
11+ } ,
812 fields:: {
913 m31:: { self , BaseField } ,
1014 qm31:: SecureField ,
@@ -14,6 +18,7 @@ use stwo_prover::{
1418 } ,
1519} ;
1620
21+ use nexus_common:: constants:: WORD_SIZE_HALVED ;
1722use nexus_vm:: {
1823 emulator:: { MemoryInitializationEntry , PublicOutputEntry } ,
1924 WORD_SIZE ,
@@ -26,8 +31,9 @@ use nexus_vm_prover_trace::{
2631} ;
2732
2833use crate :: {
34+ components:: utils:: u32_to_16bit_parts_le,
2935 framework:: BuiltInComponent ,
30- lookups:: { AllLookupElements , LogupTraceBuilder , RamReadWriteLookupElements } ,
36+ lookups:: { AllLookupElements , RamReadWriteLookupElements } ,
3137 side_note:: { program:: ProgramTraceRef , SideNote } ,
3238} ;
3339
@@ -115,7 +121,8 @@ impl BuiltInComponent for ReadWriteMemoryBoundary {
115121 trace. fill_columns ( row_idx, true , Column :: RamInitFinalFlag ) ;
116122 assert ! ( * last_access < m31:: P , "Access counter overflow" ) ;
117123
118- trace. fill_columns ( row_idx, * last_access, Column :: RamTsFinal ) ;
124+ let ts_final = u32_to_16bit_parts_le ( * last_access) ;
125+ trace. fill_columns ( row_idx, ts_final, Column :: RamTsFinal ) ;
119126 trace. fill_columns ( row_idx, * last_value, Column :: RamValFinal ) ;
120127 }
121128
@@ -131,41 +138,55 @@ impl BuiltInComponent for ReadWriteMemoryBoundary {
131138 ColumnVec < CircleEvaluation < SimdBackend , BaseField , BitReversedOrder > > ,
132139 SecureField ,
133140 ) {
141+ // TODO: support non-optimized logup trace generation
142+
134143 let rel_ram_read_write: & Self :: LookupElements = lookup_elements. as_ref ( ) ;
135- let mut logup_trace_builder = LogupTraceBuilder :: new ( component_trace. log_size ( ) ) ;
144+ let log_size = component_trace. log_size ( ) ;
136145
137146 let [ ram_init_final_flag] =
138147 original_base_column ! ( component_trace, Column :: RamInitFinalFlag ) ;
139148 let ram_init_final_addr = original_base_column ! ( component_trace, Column :: RamInitFinalAddr ) ;
140149 let [ ram_val_final] = original_base_column ! ( component_trace, Column :: RamValFinal ) ;
141150 let ram_ts_final = original_base_column ! ( component_trace, Column :: RamTsFinal ) ;
151+ let ram_val_init = ReadWriteMemoryBoundary :: combine_ram_val_init ( & component_trace) ;
142152
143- // consume(rel-ram-read-write, ram-init-final-flag, (ram-init-final-addr, ram-val-final, ram-ts-final))
144- logup_trace_builder. add_to_relation_with (
145- rel_ram_read_write,
146- [ ram_init_final_flag. clone ( ) ] ,
147- |[ ram_init_final_flag] | ( -ram_init_final_flag) . into ( ) ,
148- & [
149- ram_init_final_addr. as_slice ( ) ,
150- std:: slice:: from_ref ( & ram_val_final) ,
151- & ram_ts_final,
152- ]
153- . concat ( ) ,
154- ) ;
153+ let mut logup_trace_gen = LogupTraceGenerator :: new ( log_size) ;
155154
156- let ram_val_init = ReadWriteMemoryBoundary :: combine_ram_val_init ( & component_trace) ;
155+ let final_values = [
156+ ram_init_final_addr. as_slice ( ) ,
157+ std:: slice:: from_ref ( & ram_val_final) ,
158+ & ram_ts_final,
159+ ]
160+ . concat ( ) ;
161+ // consume(rel-ram-read-write, ram-init-final-flag, (ram-init-final-addr, ram-val-final, ram-ts-final))
162+ let mut logup_col_gen = logup_trace_gen. new_col ( ) ;
163+ for vec_row in 0 ..( 1 << ( log_size - LOG_N_LANES ) ) {
164+ let tuple: Vec < PackedBaseField > =
165+ final_values. iter ( ) . map ( |col| col. at ( vec_row) ) . collect ( ) ;
166+ let denom = rel_ram_read_write. combine ( & tuple) ;
167+ let numerator = ram_init_final_flag. at ( vec_row) ;
168+ logup_col_gen. write_frac ( vec_row, ( -numerator) . into ( ) , denom) ;
169+ }
170+ logup_col_gen. finalize_col ( ) ;
171+
172+ let init_values = [
173+ ram_init_final_addr. as_slice ( ) ,
174+ std:: slice:: from_ref ( & ram_val_init) ,
175+ vec ! [ BaseField :: zero( ) . into( ) ; WORD_SIZE ] . as_slice ( ) ,
176+ ]
177+ . concat ( ) ;
157178 // provide(rel-ram-read-write, ram-init-final-flag, (ram-init-final-addr, ram-val-init, 0))
158- logup_trace_builder . add_to_relation (
159- rel_ram_read_write ,
160- ram_init_final_flag ,
161- & [
162- ram_init_final_addr . as_slice ( ) ,
163- std :: slice :: from_ref ( & ram_val_init ) ,
164- vec ! [ BaseField :: zero ( ) . into ( ) ; WORD_SIZE ] . as_slice ( ) ,
165- ]
166- . concat ( ) ,
167- ) ;
168- logup_trace_builder . finalize ( )
179+ let mut logup_col_gen = logup_trace_gen . new_col ( ) ;
180+ for vec_row in 0 .. ( 1 << ( log_size - LOG_N_LANES ) ) {
181+ let tuple : Vec < PackedBaseField > =
182+ init_values . iter ( ) . map ( |col| col . at ( vec_row ) ) . collect ( ) ;
183+ let denom = rel_ram_read_write . combine ( & tuple ) ;
184+ let numerator = ram_init_final_flag . at ( vec_row ) ;
185+ logup_col_gen . write_frac ( vec_row , numerator . into ( ) , denom ) ;
186+ }
187+ logup_col_gen . finalize_col ( ) ;
188+
189+ logup_trace_gen . finalize_last ( )
169190 }
170191
171192 fn add_constraints < E : EvalAtRow > (
@@ -225,12 +246,13 @@ impl BuiltInComponent for ReadWriteMemoryBoundary {
225246 & [
226247 ram_init_final_addr. as_slice ( ) ,
227248 std:: slice:: from_ref ( & ram_val_init) ,
228- vec ! [ E :: F :: zero( ) ; WORD_SIZE ] . as_slice ( ) ,
249+ vec ! [ E :: F :: zero( ) ; WORD_SIZE_HALVED ] . as_slice ( ) ,
229250 ]
230251 . concat ( ) ,
231252 ) ) ;
232253
233- eval. finalize_logup_in_pairs ( ) ;
254+ // avoid in-pairs optimizations to keep low degree
255+ eval. finalize_logup ( ) ;
234256 }
235257}
236258
0 commit comments