use super::{CliffordCircuit, Metric, PauliLike, PauliSet};
use crate::synthesis::pauli_network::greedy_pauli_network::single_synthesis_step;
use petgraph::prelude::*;
pub type Dag = DiGraph<usize, ()>;
pub fn build_dag_from_pauli_set(pauli_set: &PauliSet) -> Dag {
let mut dag = Dag::new();
let node_indices: Vec<NodeIndex> = (0..pauli_set.len()).map(|i| dag.add_node(i)).collect();
for i in 0..pauli_set.len() {
for j in 0..i {
if !pauli_set.commute(i, j) {
dag.add_edge(node_indices[j], node_indices[i], ());
}
}
}
dag
}
pub fn get_front_layer(dag: &Dag) -> Vec<NodeIndex> {
dag.node_indices()
.filter(|node| dag.neighbors(*node).collect::<Vec<_>>().is_empty())
.collect()
}
pub struct PauliDag {
pub pauli_set: PauliSet,
pub dag: Dag,
pub front_nodes: Vec<NodeIndex>,
pub in_degree: Vec<usize>,
}
impl PauliDag {
pub fn from_pauli_set(pauli_set: PauliSet) -> Self {
let dag = build_dag_from_pauli_set(&pauli_set);
let num_nodes = dag.node_count();
let mut in_degree: Vec<usize> = vec![0; num_nodes];
let mut front_nodes: Vec<NodeIndex> = Vec::new();
for node_index in dag.node_indices() {
let node_in_degree = dag.neighbors_directed(node_index, Incoming).count();
in_degree[node_index.index()] = node_in_degree;
if node_in_degree == 0 {
front_nodes.push(node_index);
}
}
Self {
pauli_set,
dag,
front_nodes,
in_degree,
}
}
pub fn from_slice(axes: &[String]) -> Self {
Self::from_pauli_set(PauliSet::from_slice(axes))
}
fn is_synthesized(&self, node_index: NodeIndex) -> bool {
self.pauli_set
.support_size(*self.dag.node_weight(node_index).unwrap())
<= 1
}
pub(crate) fn update_front_nodes(&mut self) {
let mut unprocessed = self.front_nodes.clone();
self.front_nodes = Vec::new();
while let Some(node_index) = unprocessed.pop() {
if !self.is_synthesized(node_index) {
self.front_nodes.push(node_index);
} else {
for successor in self.dag.neighbors_directed(node_index, Outgoing) {
self.in_degree[successor.index()] -= 1;
if self.in_degree[successor.index()] == 0 {
unprocessed.push(successor);
}
}
}
}
}
pub fn fully_processed(&self) -> bool {
self.front_nodes.is_empty()
}
pub fn single_step_synthesis(
&mut self,
metric: &Metric,
skip_sort: bool,
synthesized_circuit: &mut CliffordCircuit,
) {
if !skip_sort {
self.front_nodes
.sort_by_cached_key(|k| self.pauli_set.support_size(k.index()));
}
let order: Vec<usize> = self.front_nodes.iter().map(|k| k.index()).collect();
let circuit_piece = single_synthesis_step(&self.pauli_set, metric, &order);
self.pauli_set.conjugate_with_circuit(&circuit_piece);
synthesized_circuit.extend_with(&circuit_piece);
self.update_front_nodes();
}
}