Skip to main content

quantrs2_sim/automatic_parallelization/
autoparallelengine_connections.rs

1//! # AutoParallelEngine - connections Methods
2//!
3//! This module contains method implementations for `AutoParallelEngine`.
4//!
5//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
6
7use quantrs2_circuit::builder::{Circuit, Simulator};
8
9use super::types::{DependencyGraph, MLFeatures};
10
11use super::autoparallelengine_type::AutoParallelEngine;
12
13impl AutoParallelEngine {
14    /// Extract ML features from circuit and dependency graph
15    pub(super) fn extract_ml_features<const N: usize>(
16        &self,
17        circuit: &Circuit<N>,
18        graph: &DependencyGraph,
19    ) -> MLFeatures {
20        let gates = circuit.gates();
21        let num_gates = gates.len();
22        let num_qubits = N;
23        let circuit_depth = Self::calculate_circuit_depth(graph);
24        let avg_connectivity = Self::calculate_average_connectivity(graph);
25        let parallelism_factor = Self::calculate_parallelism_factor(graph);
26        let gate_distribution = Self::calculate_gate_distribution(gates);
27        let entanglement_score = Self::estimate_entanglement_complexity(circuit);
28        MLFeatures {
29            num_gates,
30            num_qubits,
31            circuit_depth,
32            avg_connectivity,
33            parallelism_factor,
34            gate_distribution,
35            entanglement_score,
36            dependency_density: graph.edges.len() as f64 / num_gates as f64,
37        }
38    }
39    /// Calculate circuit depth (critical path)
40    pub(super) fn calculate_circuit_depth(graph: &DependencyGraph) -> usize {
41        let mut depths = vec![0; graph.nodes.len()];
42        for (idx, node) in graph.nodes.iter().enumerate() {
43            let mut max_parent_depth = 0;
44            if let Some(parents) = graph.reverse_edges.get(&idx) {
45                for &parent in parents {
46                    max_parent_depth = max_parent_depth.max(depths[parent]);
47                }
48            }
49            depths[idx] = max_parent_depth + 1;
50        }
51        *depths.iter().max().unwrap_or(&0)
52    }
53    /// Calculate average gate connectivity
54    pub(super) fn calculate_average_connectivity(graph: &DependencyGraph) -> f64 {
55        if graph.nodes.is_empty() {
56            return 0.0;
57        }
58        let total_connections: usize = graph.nodes.iter().map(|n| n.qubits.len()).sum();
59        total_connections as f64 / graph.nodes.len() as f64
60    }
61    /// Calculate parallelism factor
62    pub(super) fn calculate_parallelism_factor(graph: &DependencyGraph) -> f64 {
63        if graph.nodes.is_empty() {
64            return 0.0;
65        }
66        let independent_gates = graph
67            .nodes
68            .iter()
69            .enumerate()
70            .filter(|(idx, _)| {
71                graph
72                    .reverse_edges
73                    .get(idx)
74                    .is_none_or(std::vec::Vec::is_empty)
75            })
76            .count();
77        independent_gates as f64 / graph.nodes.len() as f64
78    }
79    /// Estimate entanglement complexity
80    pub(super) fn estimate_entanglement_complexity<const N: usize>(circuit: &Circuit<N>) -> f64 {
81        let gates = circuit.gates();
82        let two_qubit_gates = gates.iter().filter(|g| g.qubits().len() >= 2).count();
83        if gates.is_empty() {
84            0.0
85        } else {
86            two_qubit_gates as f64 / gates.len() as f64
87        }
88    }
89}