use alloc::vec;
use alloc::vec::Vec;
use p3_baby_bear::BabyBear;
use p3_field::{Field, PackedValue};
use p3_util::{log2_ceil_usize, log2_strict_usize};
use rand::rngs::SmallRng;
use rand::{RngExt, SeedableRng};
use crate::layout::Table;
use crate::{OpeningBatch, OpeningRequest, PointSchedule, TableShape, TableSpec};
pub type F = BabyBear;
pub fn table_point_schedule(width: usize, extra_points: Vec<OpeningRequest>) -> PointSchedule {
let mut point_schedule = Vec::with_capacity(extra_points.len() + 1);
point_schedule.push(OpeningBatch::new((0..width).collect(), Vec::new()));
point_schedule.extend(extra_points);
point_schedule
}
pub fn random_point_schedule(rng: &mut SmallRng, width: usize, num_points: usize) -> PointSchedule {
table_point_schedule(
width,
(1..num_points)
.map(|_| {
let direct = (0..width)
.filter(|_| rng.random_bool(0.5))
.collect::<Vec<_>>();
let successor = (0..width)
.filter(|_| rng.random_bool(0.5))
.collect::<Vec<_>>();
if direct.is_empty() && successor.is_empty() {
OpeningBatch::new(vec![0], Vec::new())
} else {
OpeningBatch::new(direct, successor)
}
})
.collect(),
)
}
pub fn random_table_specs(rng: &mut SmallRng, folding: usize) -> Vec<TableSpec> {
let packing_log = log2_strict_usize(<F as Field>::Packing::WIDTH);
loop {
let num_points = rng.random_range(1..=5);
let num_tables = rng.random_range(1..=5);
let specs = (0..num_tables)
.map(|_| {
let num_variables = rng.random_range(1..=12);
let width = rng.random_range(1..=5);
TableSpec::new(
TableShape::new(num_variables, width),
random_point_schedule(rng, width, num_points),
)
})
.collect::<Vec<_>>();
if stacked_num_variables(&specs, folding) >= folding + packing_log {
return specs;
}
}
}
pub fn stacked_num_variables(specs: &[TableSpec], folding: usize) -> usize {
let total_evals = specs
.iter()
.map(|spec| spec.shape().width() << spec.shape().num_variables().max(folding))
.sum::<usize>();
log2_ceil_usize(total_evals)
}
pub fn table_specs_to_tables(specs: &[TableSpec]) -> Vec<Table<F>> {
let mut rng = SmallRng::seed_from_u64(3);
specs
.iter()
.map(|spec| Table::rand(&mut rng, spec.shape().width(), spec.shape().num_variables()))
.collect()
}