quantrs2_sim/automatic_parallelization/
autoparallelengine_connections.rs1use quantrs2_circuit::builder::{Circuit, Simulator};
8
9use super::types::{DependencyGraph, MLFeatures};
10
11use super::autoparallelengine_type::AutoParallelEngine;
12
13impl AutoParallelEngine {
14 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 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 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 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 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}