use core::sync::atomic::{AtomicUsize, Ordering};
use miden_crypto::{
field::TwoAdicField,
stark::dft::{NaiveDft, TwoAdicSubgroupDft},
};
use crate::layout::InputKey;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub(crate) struct DagId(usize);
impl DagId {
pub(crate) fn fresh() -> Self {
static NEXT_DAG_ID: AtomicUsize = AtomicUsize::new(0);
Self(NEXT_DAG_ID.fetch_add(1, Ordering::Relaxed))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct NodeId {
pub(super) dag_id: DagId,
pub(super) index: usize,
}
impl NodeId {
pub const fn index(self) -> usize {
self.index
}
pub(super) const fn in_dag(index: usize, dag_id: DagId) -> Self {
Self { dag_id, index }
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum NodeKind<EF> {
Input(InputKey),
Constant(EF),
Add(NodeId, NodeId),
Sub(NodeId, NodeId),
Mul(NodeId, NodeId),
Neg(NodeId),
}
#[derive(Debug, Clone)]
pub struct PeriodicColumnData<EF> {
coeffs: Vec<Vec<EF>>,
}
impl<EF> PeriodicColumnData<EF> {
pub fn from_periodic_columns<F>(periodic_columns: Vec<Vec<F>>) -> Self
where
F: TwoAdicField,
EF: From<F>,
{
if periodic_columns.is_empty() {
return Self { coeffs: Vec::new() };
}
let dft = NaiveDft;
let mut coeffs = Vec::with_capacity(periodic_columns.len());
for col in periodic_columns {
assert!(!col.is_empty(), "periodic column must not be empty");
assert!(col.len().is_power_of_two(), "periodic column length must be a power of two");
let values = dft.idft(col);
let coeff_row = values.into_iter().map(EF::from).collect();
coeffs.push(coeff_row);
}
Self { coeffs }
}
pub fn num_columns(&self) -> usize {
self.coeffs.len()
}
pub fn max_period(&self) -> usize {
self.coeffs.iter().map(Vec::len).max().unwrap_or(0)
}
pub fn columns(&self) -> &[Vec<EF>] {
&self.coeffs
}
}
#[derive(Debug)]
pub struct AceDag<EF> {
dag_id: DagId,
pub nodes: Vec<NodeKind<EF>>,
pub root: NodeId,
}
#[derive(Debug, Clone)]
pub struct DagSnapshot<EF> {
nodes: Vec<NodeKind<EF>>,
root: NodeId,
source_dag_id: DagId,
}
impl<EF> AceDag<EF> {
pub(crate) fn from_parts(dag_id: DagId, nodes: Vec<NodeKind<EF>>, root: NodeId) -> Self {
Self { dag_id, nodes, root }
}
pub(crate) fn nodes(&self) -> &[NodeKind<EF>] {
&self.nodes
}
pub(crate) fn into_nodes(self) -> Vec<NodeKind<EF>> {
self.nodes
}
pub(crate) fn dag_id(&self) -> DagId {
self.dag_id
}
pub fn root(&self) -> NodeId {
self.root
}
pub fn into_snapshot(self) -> DagSnapshot<EF> {
DagSnapshot {
nodes: self.nodes,
root: self.root,
source_dag_id: self.dag_id,
}
}
}
impl<EF> DagSnapshot<EF> {
pub fn root(&self) -> NodeId {
self.root
}
pub(super) fn into_parts(self) -> (DagId, Vec<NodeKind<EF>>, NodeId) {
(self.source_dag_id, self.nodes, self.root)
}
}