miden_ace_codegen/dag/
ir.rs1use core::sync::atomic::{AtomicUsize, Ordering};
2
3use miden_crypto::{
4 field::TwoAdicField,
5 stark::dft::{NaiveDft, TwoAdicSubgroupDft},
6};
7
8use crate::layout::InputKey;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
11pub(crate) struct DagId(usize);
12
13impl DagId {
14 pub(crate) fn fresh() -> Self {
15 static NEXT_DAG_ID: AtomicUsize = AtomicUsize::new(0);
16
17 Self(NEXT_DAG_ID.fetch_add(1, Ordering::Relaxed))
18 }
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
23pub struct NodeId {
24 pub(super) dag_id: DagId,
25 pub(super) index: usize,
26}
27
28impl NodeId {
29 pub const fn index(self) -> usize {
31 self.index
32 }
33
34 pub(super) const fn in_dag(index: usize, dag_id: DagId) -> Self {
35 Self { dag_id, index }
36 }
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Hash)]
45pub enum NodeKind<EF> {
46 Input(InputKey),
48 Constant(EF),
50 Add(NodeId, NodeId),
52 Sub(NodeId, NodeId),
54 Mul(NodeId, NodeId),
56 Neg(NodeId),
58}
59
60#[derive(Debug, Clone)]
62pub struct PeriodicColumnData<EF> {
63 coeffs: Vec<Vec<EF>>,
65}
66
67impl<EF> PeriodicColumnData<EF> {
68 pub fn from_periodic_columns<F>(periodic_columns: Vec<Vec<F>>) -> Self
72 where
73 F: TwoAdicField,
74 EF: From<F>,
75 {
76 if periodic_columns.is_empty() {
77 return Self { coeffs: Vec::new() };
78 }
79
80 let dft = NaiveDft;
81 let mut coeffs = Vec::with_capacity(periodic_columns.len());
82 for col in periodic_columns {
83 assert!(!col.is_empty(), "periodic column must not be empty");
84 assert!(col.len().is_power_of_two(), "periodic column length must be a power of two");
85 let values = dft.idft(col);
86 let coeff_row = values.into_iter().map(EF::from).collect();
87 coeffs.push(coeff_row);
88 }
89
90 Self { coeffs }
91 }
92
93 pub fn num_columns(&self) -> usize {
95 self.coeffs.len()
96 }
97
98 pub fn max_period(&self) -> usize {
100 self.coeffs.iter().map(|c| c.len()).max().unwrap_or(0)
101 }
102
103 pub fn columns(&self) -> &[Vec<EF>] {
105 &self.coeffs
106 }
107}
108
109#[derive(Debug)]
111pub struct AceDag<EF> {
112 dag_id: DagId,
113 pub nodes: Vec<NodeKind<EF>>,
115 pub root: NodeId,
117}
118
119#[derive(Debug, Clone)]
121pub struct DagSnapshot<EF> {
122 nodes: Vec<NodeKind<EF>>,
123 root: NodeId,
124 source_dag_id: DagId,
125}
126
127impl<EF> AceDag<EF> {
128 pub(crate) fn from_parts(dag_id: DagId, nodes: Vec<NodeKind<EF>>, root: NodeId) -> Self {
129 Self { dag_id, nodes, root }
130 }
131
132 pub(crate) fn nodes(&self) -> &[NodeKind<EF>] {
133 &self.nodes
134 }
135
136 pub(crate) fn into_nodes(self) -> Vec<NodeKind<EF>> {
137 self.nodes
138 }
139
140 pub(crate) fn dag_id(&self) -> DagId {
141 self.dag_id
142 }
143
144 pub fn root(&self) -> NodeId {
145 self.root
146 }
147
148 pub fn into_snapshot(self) -> DagSnapshot<EF> {
150 DagSnapshot {
151 nodes: self.nodes,
152 root: self.root,
153 source_dag_id: self.dag_id,
154 }
155 }
156}
157
158impl<EF> DagSnapshot<EF> {
159 pub fn root(&self) -> NodeId {
161 self.root
162 }
163
164 pub(super) fn into_parts(self) -> (DagId, Vec<NodeKind<EF>>, NodeId) {
165 (self.source_dag_id, self.nodes, self.root)
166 }
167}