use alloc::vec::Vec;
use miden_air::{
LOGUP_AUX_TRACE_WIDTH, LiftedAir, ProcessorAir,
logup::{BusId, MIDEN_MAX_MESSAGE_WIDTH},
lookup::{Challenges, accumulate, build_lookup_fractions, debug::collect_column_oracle_folds},
};
use miden_core::{
field::{Field, QuadFelt},
utils::Matrix,
};
use super::{Felt, build_trace_from_ops, rand_array};
use crate::operation::Operation;
fn tiny_span() -> Vec<Operation> {
vec![
Operation::Pad,
Operation::Pad,
Operation::Add,
Operation::Pad,
Operation::Mul,
Operation::Drop,
]
}
#[test]
fn build_lookup_fractions_matches_constraint_path_oracle() {
let trace = build_trace_from_ops(tiny_span(), &[]);
let main_trace = trace.main_trace().to_row_major();
let public_vals = trace.to_public_values();
let periodic = LiftedAir::<Felt, QuadFelt>::periodic_columns(&ProcessorAir);
let raw = rand_array::<Felt, 4>();
let alpha = QuadFelt::new([raw[0], raw[1]]);
let beta = QuadFelt::new([raw[2], raw[3]]);
let air = ProcessorAir;
let challenges =
Challenges::<QuadFelt>::new(alpha, beta, MIDEN_MAX_MESSAGE_WIDTH, BusId::COUNT);
let fractions = build_lookup_fractions(&air, &main_trace, &periodic, &challenges);
let num_rows = trace.main_trace().num_rows();
assert_eq!(fractions.num_rows(), num_rows);
assert_eq!(fractions.num_columns(), LOGUP_AUX_TRACE_WIDTH);
assert_eq!(fractions.counts().len(), num_rows * LOGUP_AUX_TRACE_WIDTH);
assert!(
!fractions.fractions().is_empty(),
"no fractions collected — trace is degenerate or emitters are broken",
);
let aux = accumulate(&fractions);
let aux_width = aux.width();
let aux_values = &aux.values;
assert_eq!(aux_width, LOGUP_AUX_TRACE_WIDTH);
assert_eq!(aux.height(), num_rows + 1);
let oracle_folds =
collect_column_oracle_folds(&air, &main_trace, &periodic, &public_vals, &challenges);
assert_eq!(oracle_folds.len(), num_rows);
for (r, row_folds) in oracle_folds.iter().enumerate() {
assert_eq!(row_folds.len(), LOGUP_AUX_TRACE_WIDTH);
let per_row_values: Vec<QuadFelt> = row_folds
.iter()
.enumerate()
.map(|(col, &(v_col, u_col))| {
let u_inv = u_col.try_inverse().unwrap_or_else(|| {
panic!(
"row {r} col {col}: oracle U_col is zero — bus has a zero-denominator \
product, indicating a bug in the emitter or message encoding",
)
});
v_col * u_inv
})
.collect();
let expected_delta: QuadFelt = per_row_values.iter().copied().sum();
let actual_delta = aux_values[(r + 1) * aux_width] - aux_values[r * aux_width];
assert_eq!(
actual_delta, expected_delta,
"row {r} col 0 (accumulator): prover vs constraint path mismatch",
);
for col in 1..LOGUP_AUX_TRACE_WIDTH {
let actual_value = aux_values[r * aux_width + col];
assert_eq!(
actual_value, per_row_values[col],
"row {r} col {col} (fraction): prover vs constraint path mismatch",
);
}
}
}