quantrs2_core/quantum_walk/
continuous.rs1use super::graph::Graph;
4use crate::complex_ext::QuantumComplexExt;
5use scirs2_core::ndarray::Array2;
6use scirs2_core::Complex64;
7use std::collections::HashMap;
8
9pub struct ContinuousQuantumWalk {
11 graph: Graph,
12 hamiltonian: Array2<Complex64>,
13 state: Vec<Complex64>,
14}
15
16impl ContinuousQuantumWalk {
17 pub fn new(graph: Graph) -> Self {
19 let adj_matrix = graph.adjacency_matrix();
20 let hamiltonian = adj_matrix.mapv(|x| Complex64::new(x, 0.0));
21 let num_vertices = graph.num_vertices;
22
23 Self {
24 graph,
25 hamiltonian,
26 state: vec![Complex64::new(0.0, 0.0); num_vertices],
27 }
28 }
29
30 pub fn initialize_vertex(&mut self, vertex: usize) {
32 self.state = vec![Complex64::new(0.0, 0.0); self.graph.num_vertices];
33 if vertex < self.graph.num_vertices {
34 self.state[vertex] = Complex64::new(1.0, 0.0);
35 }
36 }
37
38 pub fn evolve(&mut self, time: f64) {
40 let dt = 0.01; let steps = (time / dt) as usize;
45
46 for _ in 0..steps {
47 let mut new_state = self.state.clone();
48
49 for (i, ns) in new_state
51 .iter_mut()
52 .enumerate()
53 .take(self.graph.num_vertices)
54 {
55 let mut sum = Complex64::new(0.0, 0.0);
56 for j in 0..self.graph.num_vertices {
57 sum += self.hamiltonian[[i, j]] * self.state[j];
58 }
59 *ns = self.state[i] - Complex64::new(0.0, dt) * sum;
60 }
61
62 let norm: f64 = new_state.iter().map(|c| c.norm_sqr()).sum::<f64>().sqrt();
64
65 if norm > 0.0 {
66 for amp in &mut new_state {
67 *amp /= norm;
68 }
69 }
70
71 self.state = new_state;
72 }
73 }
74
75 pub fn vertex_probabilities(&self) -> Vec<f64> {
77 self.state.iter().map(|c| c.probability()).collect()
78 }
79
80 pub fn transport_probability(&mut self, from: usize, to: usize, time: f64) -> f64 {
82 self.initialize_vertex(from);
84
85 self.evolve(time);
87
88 if to < self.state.len() {
90 self.state[to].probability()
91 } else {
92 0.0
93 }
94 }
95
96 pub fn get_probabilities(&self, state: &[Complex64]) -> Vec<f64> {
98 state.iter().map(|c| c.probability()).collect()
99 }
100}
101
102pub struct SzegedyQuantumWalk {
105 graph: Graph,
106 state: HashMap<(usize, usize), Complex64>,
108 num_edges: usize,
109}
110
111impl SzegedyQuantumWalk {
112 pub fn new(graph: Graph) -> Self {
114 let mut num_edges = 0;
115 for v in 0..graph.num_vertices {
116 num_edges += graph.edges[v].len();
117 }
118
119 Self {
120 graph,
121 state: HashMap::new(),
122 num_edges,
123 }
124 }
125
126 pub fn initialize_uniform(&mut self) {
128 self.state.clear();
129
130 if self.num_edges == 0 {
131 return;
132 }
133
134 let amplitude = Complex64::new(1.0 / (self.num_edges as f64).sqrt(), 0.0);
135
136 for u in 0..self.graph.num_vertices {
137 for &v in &self.graph.edges[u] {
138 self.state.insert((u, v), amplitude);
139 }
140 }
141 }
142
143 pub fn initialize_edge(&mut self, u: usize, v: usize) {
145 self.state.clear();
146
147 if u < self.graph.num_vertices && self.graph.edges[u].contains(&v) {
148 self.state.insert((u, v), Complex64::new(1.0, 0.0));
149 }
150 }
151
152 pub fn step(&mut self) {
154 self.reflect_vertex_uniform();
158
159 self.reflect_edge_uniform();
161 }
162
163 fn reflect_vertex_uniform(&mut self) {
165 let mut vertex_sums: Vec<Complex64> =
166 vec![Complex64::new(0.0, 0.0); self.graph.num_vertices];
167
168 for (&(u, _), &litude) in &self.state {
170 vertex_sums[u] += amplitude;
171 }
172
173 let mut new_state = HashMap::new();
175
176 for (&(u, v), &old_amp) in &self.state {
177 let degree = self.graph.degree(u) as f64;
178 if degree > 0.0 {
179 let vertex_avg = vertex_sums[u] / degree;
180 let new_amp = 2.0 * vertex_avg - old_amp;
181 new_state.insert((u, v), new_amp);
182 }
183 }
184
185 self.state = new_state;
186 }
187
188 fn reflect_edge_uniform(&mut self) {
190 if self.num_edges == 0 {
191 return;
192 }
193
194 let total_amp: Complex64 = self.state.values().sum();
196 let uniform_amp = total_amp / self.num_edges as f64;
197
198 for amplitude in self.state.values_mut() {
200 *amplitude = 2.0 * uniform_amp - *amplitude;
201 }
202 }
203
204 pub fn vertex_probabilities(&self) -> Vec<f64> {
206 let mut probs = vec![0.0; self.graph.num_vertices];
207
208 for (&(u, _), &litude) in &self.state {
209 probs[u] += amplitude.norm_sqr();
210 }
211
212 probs
213 }
214
215 pub fn edge_probabilities(&self) -> Vec<((usize, usize), f64)> {
217 self.state
218 .iter()
219 .map(|(&edge, &litude)| (edge, amplitude.norm_sqr()))
220 .collect()
221 }
222
223 pub fn estimate_mixing_time(&mut self, epsilon: f64) -> usize {
225 let uniform_prob = 1.0 / self.graph.num_vertices as f64;
226
227 self.initialize_uniform();
229
230 for steps in 1..1000 {
231 self.step();
232
233 let probs = self.vertex_probabilities();
234 let max_deviation = probs
235 .iter()
236 .map(|&p| (p - uniform_prob).abs())
237 .fold(0.0, f64::max);
238
239 if max_deviation < epsilon {
240 return steps;
241 }
242 }
243
244 1000 }
246}