quant_iron/components/state.rs
1use crate::components::{
2 measurement::{MeasurementBasis, MeasurementResult},
3 operator::{
4 CNOT, Hadamard, Identity, Matchgate, Operator, Pauli, PhaseS, PhaseSdag, PhaseShift,
5 PhaseT, PhaseTdag, RotateX, RotateY, RotateZ, SWAP, Toffoli, Unitary2,
6 },
7};
8use crate::errors::Error;
9use num_complex::Complex;
10use rand::Rng;
11use rayon::prelude::*;
12use std::ops::{Add, Mul, Sub};
13
14// Helper function to calculate the adjoint (conjugate transpose) of a 2x2 matrix
15fn calculate_adjoint(matrix: &[[Complex<f64>; 2]; 2]) -> [[Complex<f64>; 2]; 2] {
16 [
17 [matrix[0][0].conj(), matrix[1][0].conj()],
18 [matrix[0][1].conj(), matrix[1][1].conj()],
19 ]
20}
21
22#[derive(Clone)]
23/// Represents the state of a quantum register.
24///
25/// The state is represented as a complex vector, where each element corresponds to a probability amplitude for a particular basis state.
26/// The number of qubits in the system is also stored, which determines the length of the state vector (2^num_qubits).
27pub struct State {
28 /// The state vector of the system, represented as a complex vector.
29 /// Each element of the vector represents a probability amplitude for a particular state.
30 pub state_vector: Vec<Complex<f64>>,
31
32 /// The number of qubits in the system.
33 pub num_qubits: usize,
34}
35
36impl State {
37 /// Creates a new state object with the given state vector.
38 ///
39 /// # Arguments
40 ///
41 /// * `state_vector` - The state vector of the system, represented as a complex vector.
42 ///
43 /// # Returns
44 ///
45 /// * `state` - A result containing the state object if successful, or an error if the state vector is invalid.
46 ///
47 /// # Errors
48 ///
49 /// * Returns an error if the state vector is empty.
50 /// * Returns an error if the state vector is not normalised (i.e., the square norm is not 1).
51 /// * Returns an error if the number of qubits is invalid (i.e., the length of the state vector is not a power of 2).
52 pub fn new(state_vector: Vec<Complex<f64>>) -> Result<Self, Error> {
53 let len = state_vector.len();
54
55 if len == 0 {
56 return Err(Error::InvalidNumberOfQubits(0));
57 }
58
59 // Check if the length of the state vector is a power of 2
60 if !len.is_power_of_two() {
61 // For error reporting, num_qubits can be approximated or a specific error used.
62 return Err(Error::InvalidNumberOfQubits(
63 (len as f64).log2().floor() as usize
64 ));
65 }
66 // num_qubits can be safely calculated as len is non-zero and a power of two.
67 let num_qubits = len.trailing_zeros() as usize;
68
69 // Check if the square norm (probability) of the state vector is 1
70 let norm: f64 = state_vector.par_iter().map(|x| x.norm_sqr()).sum();
71 let tol: f64 = f64::EPSILON * len as f64; // Using len directly
72 if (norm - 1.0).abs() > tol {
73 return Err(Error::StateVectorNotNormalised);
74 }
75
76 Ok(Self {
77 state_vector,
78 num_qubits,
79 })
80 }
81
82 /// Creates a new state object with the given number of qubits initialised to the |0...0> state.
83 ///
84 /// # Arguments
85 ///
86 /// * `num_qubits` - The number of qubits in the system.
87 ///
88 /// # Returns
89 ///
90 /// * `state` - A result containing the state object if successful, or an error if the number of qubits is invalid.
91 ///
92 /// # Errors
93 ///
94 /// * Returns an error if the number of qubits is 0.
95 pub fn new_zero(num_qubits: usize) -> Result<Self, Error> {
96 if num_qubits == 0 {
97 return Err(Error::InvalidNumberOfQubits(num_qubits));
98 }
99 let dim: usize = 1 << num_qubits;
100 let mut state_vector: Vec<Complex<f64>> = vec![Complex::new(0.0, 0.0); dim];
101 state_vector[0] = Complex::new(1.0, 0.0); // |0...0> state has amplitude 1.0 at index 0
102
103 Ok(Self {
104 state_vector,
105 num_qubits,
106 })
107 }
108
109 /// Creates a new state object with the given number of qubits initialised to the `n`-th basis state.
110 ///
111 /// # Arguments
112 ///
113 /// * `num_qubits` - The number of qubits in the system.
114 /// * `n` - The index of the basis state to initialise to.
115 ///
116 /// # Returns
117 ///
118 /// * `state` - A result containing a new state object with the specified number of qubits, initialised to the `n`-th basis state or an error if `n` is out of bounds or if the number of qubits is invalid.
119 ///
120 /// # Errors
121 ///
122 /// * Returns an error if the number of qubits is 0 or if `n` is out of bounds for the given number of qubits.
123 pub fn new_basis_n(num_qubits: usize, n: usize) -> Result<Self, Error> {
124 let dim: usize = 1 << num_qubits;
125 if n >= dim {
126 return Err(Error::InvalidQubitIndex(n, num_qubits));
127 }
128 if num_qubits == 0 {
129 return Err(Error::InvalidNumberOfQubits(num_qubits));
130 }
131
132 let mut state_vector: Vec<Complex<f64>> = vec![Complex::new(0.0, 0.0); dim];
133 state_vector[n] = Complex::new(1.0, 0.0); // |n> state has amplitude 1.0 at index n
134
135 Ok(Self {
136 state_vector,
137 num_qubits,
138 })
139 }
140
141 /// Creates a new plus state object with the given number of qubits initialised to the |+...+> state.
142 ///
143 /// # Arguments
144 ///
145 /// * `num_qubits` - The number of qubits in the system.
146 ///
147 /// # Returns
148 ///
149 /// * `state` - A result containing a new state object with the specified number of qubits, initialised to the |+...+> state or an error if the number of qubits is invalid.
150 ///
151 /// # Errors
152 ///
153 /// * Returns an error if the number of qubits is 0.
154 pub fn new_plus(num_qubits: usize) -> Result<Self, Error> {
155 if num_qubits == 0 {
156 return Err(Error::InvalidNumberOfQubits(num_qubits));
157 }
158 let dim: usize = 1 << num_qubits;
159 let amplitude = Complex::new(1.0 / (dim as f64).sqrt(), 0.0);
160 let state_vector: Vec<Complex<f64>> = vec![amplitude; dim];
161
162 Ok(Self {
163 state_vector,
164 num_qubits,
165 })
166 }
167
168 /// Creates a new minus state object with the given number of qubits initialised to the |-...-> state.
169 ///
170 /// # Arguments
171 ///
172 /// * `num_qubits` - The number of qubits in the system.
173 ///
174 /// # Returns
175 ///
176 /// * `state` - A result containing a new state object with the specified number of qubits, initialised to the |-...-> state or an error if the number of qubits is invalid.
177 ///
178 /// # Errors
179 ///
180 /// * Returns an error if the number of qubits is 0.
181 pub fn new_minus(num_qubits: usize) -> Result<Self, Error> {
182 if num_qubits == 0 {
183 return Err(Error::InvalidNumberOfQubits(num_qubits));
184 }
185 let dim: usize = 1 << num_qubits;
186 let amplitude: Complex<f64> = Complex::new(1.0 / (dim as f64).sqrt(), 0.0);
187 const PARALLEL_THRESHOLD: usize = 1 << 6; // Threshold for parallelization
188
189 let state_vector: Vec<Complex<f64>> = if dim > PARALLEL_THRESHOLD {
190 (0..dim)
191 .into_par_iter()
192 .map(|i| {
193 let num_ones = i.count_ones() as usize;
194 if num_ones % 2 == 0 {
195 amplitude
196 } else {
197 -amplitude
198 }
199 })
200 .collect()
201 } else {
202 let mut sv = Vec::with_capacity(dim);
203 for i in 0..dim {
204 let num_ones = i.count_ones() as usize;
205 sv.push(if num_ones % 2 == 0 {
206 amplitude
207 } else {
208 -amplitude
209 });
210 }
211 sv
212 };
213
214 Ok(Self {
215 state_vector,
216 num_qubits,
217 })
218 }
219
220 /// Returns the probability of a basis state at index `n` in the state vector.
221 ///
222 /// # Arguments
223 ///
224 /// * `n` - The index of the basis state to get the probability for.
225 ///
226 /// # Returns
227 ///
228 /// * `probability` - The probability of the basis state at index `n`.
229 ///
230 /// # Errors
231 ///
232 /// * Returns an error if `n` is out of bounds for the state vector.
233 pub fn probability(&self, n: usize) -> Result<f64, Error> {
234 if n >= self.state_vector.len() {
235 return Err(Error::InvalidQubitIndex(n, self.num_qubits));
236 }
237 let amplitude: Complex<f64> = self.state_vector[n];
238 Ok(amplitude.norm_sqr())
239 }
240
241 /// Returns the number of qubits in the state vector.
242 ///
243 /// # Returns
244 ///
245 /// * `num_qubits` - The number of qubits in the state vector.
246 pub fn num_qubits(&self) -> usize {
247 self.num_qubits
248 }
249
250 /// Returns the amplitude of the basis state at index `n` in the state vector.
251 ///
252 /// # Arguments
253 ///
254 /// * `n` - The index of the basis state to get the amplitude for.
255 ///
256 /// # Returns
257 ///
258 /// * `amplitude` - The amplitude of the basis state at index `n`.
259 ///
260 /// # Errors
261 ///
262 /// * Returns an error if `n` is out of bounds for the state vector.
263 pub fn amplitude(&self, n: usize) -> Result<Complex<f64>, Error> {
264 if n >= self.state_vector.len() {
265 return Err(Error::InvalidQubitIndex(n, self.num_qubits));
266 }
267 Ok(self.state_vector[n])
268 }
269
270 // ***** MEASUREMENT FUNCTIONS *****
271
272 fn _measure_computational(
273 &self,
274 measured_qubits: &[usize],
275 ) -> Result<MeasurementResult, Error> {
276 self.measure(MeasurementBasis::Computational, measured_qubits)
277 }
278
279 /// Measures the state vector in the specified basis and returns the measurement result.
280 ///
281 /// # Arguments
282 ///
283 /// * `basis` - The basis to measure in.
284 /// * `indices` - The indices of the qubits to measure. If `indices` is empty, all qubits are measured.
285 ///
286 /// # Returns
287 ///
288 /// * `result` - A result containing the measurement result if successful, or an error if the measurement fails.
289 ///
290 /// # Errors
291 ///
292 /// * Returns an error if the measurement fails.
293 /// * Returns an error if the number of qubits is invalid.
294 /// * Returns an error if the indices are out of bounds for the state vector.
295 pub fn measure(
296 &self,
297 basis: MeasurementBasis,
298 measured_qubits: &[usize],
299 ) -> Result<MeasurementResult, Error> {
300 // If no indices are provided, measure all qubits
301 let all_qubits: Vec<usize> = if measured_qubits.is_empty() {
302 (0..self.num_qubits).collect()
303 } else {
304 Vec::new()
305 };
306
307 let actual_measured_qubits: &[usize] = if measured_qubits.is_empty() {
308 &all_qubits
309 } else {
310 measured_qubits
311 };
312
313 // Check for valid indices
314 let num_measured: usize = actual_measured_qubits.len();
315 if num_measured > self.num_qubits {
316 return Err(Error::InvalidNumberOfQubits(self.num_qubits));
317 }
318 for &index in actual_measured_qubits {
319 if index >= self.num_qubits {
320 return Err(Error::InvalidQubitIndex(index, self.num_qubits));
321 }
322 }
323
324 match basis {
325 MeasurementBasis::Computational => {
326 let num_outcomes: usize = 1 << num_measured;
327
328 // Calculate probabilities for each outcome (outcome as a single integer 0..num_outcomes-1)
329 let probabilities: Vec<f64> = self
330 .state_vector
331 .par_iter()
332 .enumerate()
333 .fold(
334 || vec![0.0; num_outcomes], // Thread-local accumulator
335 |mut acc_probs, (idx, amplitude)| {
336 let mut outcome_val_for_this_state = 0;
337 // Extract the bits corresponding to measured_qubits to form the outcome value
338 for (bit_idx, &qubit_pos) in actual_measured_qubits.iter().enumerate() {
339 if (idx >> qubit_pos) & 1 != 0 {
340 outcome_val_for_this_state |= 1 << bit_idx;
341 }
342 }
343 // Ensure outcome_val_for_this_state is within bounds (0 to num_outcomes-1)
344 if outcome_val_for_this_state < num_outcomes {
345 acc_probs[outcome_val_for_this_state] += amplitude.norm_sqr();
346 }
347 acc_probs
348 },
349 )
350 .reduce(
351 || vec![0.0; num_outcomes], // Initialiser for combining thread-local results
352 |mut total_probs, local_probs| {
353 for i in 0..num_outcomes {
354 total_probs[i] += local_probs[i];
355 }
356 total_probs
357 },
358 );
359
360 // Normalise probabilities
361 let total_probability: f64 = probabilities.iter().sum();
362 if total_probability < f64::EPSILON {
363 return Err(Error::UnknownError);
364 }
365 let normalised_probabilities: Vec<f64> = probabilities
366 .iter()
367 .map(|&prob| prob / total_probability)
368 .collect();
369
370 // Sample an outcome based on the probabilities
371 let mut rng = rand::rng();
372 let random_value: f64 = rng.random_range(0.0..1.0);
373
374 let mut cumulative_probability: f64 = 0.0;
375 let mut sampled_outcome_int: usize = 0;
376
377 // Sample loop
378 for (i, &prob) in normalised_probabilities.iter().enumerate() {
379 cumulative_probability += prob;
380 // Sample if random_value falls into the cumulative probability bin
381 if random_value < cumulative_probability {
382 sampled_outcome_int = i;
383 break; // Found the outcome, exit loop
384 }
385 }
386 // If, due to floating point issues, no outcome was selected, select the last one.
387 if random_value >= cumulative_probability && !normalised_probabilities.is_empty() {
388 sampled_outcome_int = normalised_probabilities.len() - 1;
389 }
390
391 // Collapse the state vector into a new vector
392 let mut collapsed_state_data: Vec<Complex<f64>> =
393 vec![Complex::new(0.0, 0.0); self.state_vector.len()];
394
395 let normalisation_sq: f64 = collapsed_state_data
396 .par_iter_mut()
397 .enumerate()
398 .zip(self.state_vector.par_iter()) // Zip with original state vector amplitudes
399 .map(|((idx, collapsed_amp_ref), &original_amp)| {
400 let mut current_outcome_val_for_this_state = 0;
401 // Extract the bits corresponding to measured_qubits
402 for (bit_idx, &qubit_pos) in actual_measured_qubits.iter().enumerate() {
403 if (idx >> qubit_pos) & 1 != 0 {
404 current_outcome_val_for_this_state |= 1 << bit_idx;
405 }
406 }
407
408 if current_outcome_val_for_this_state == sampled_outcome_int {
409 *collapsed_amp_ref = original_amp;
410 original_amp.norm_sqr() // Contribution to normalisation_sq
411 } else {
412 // *collapsed_amp_ref remains Complex::new(0.0, 0.0)
413 0.0 // No contribution
414 }
415 })
416 .sum(); // Sums up all contributions to get total normalisation_sq
417
418 // Renormalise the new collapsed state vector
419 if normalisation_sq > f64::EPSILON {
420 let norm_factor: f64 = normalisation_sq.sqrt();
421 for amplitude in collapsed_state_data.iter_mut() {
422 *amplitude /= norm_factor;
423 }
424 }
425
426 // Convert the sampled integer outcome to a Vec<u8>
427 let mut outcome_binary_vec: Vec<u8> = vec![0; num_measured];
428 for (i, qubit_pos) in outcome_binary_vec.iter_mut().enumerate() {
429 *qubit_pos = ((sampled_outcome_int >> i) & 1) as u8;
430 }
431
432 // Create the measurement result
433 Ok(MeasurementResult {
434 basis,
435 indices: actual_measured_qubits.to_vec(),
436 outcomes: outcome_binary_vec,
437 new_state: State::new(collapsed_state_data)?,
438 })
439 }
440 MeasurementBasis::X => {
441 // Apply Hadamard to measured qubits
442 let transformed_state = self.h_multi(actual_measured_qubits)?;
443 // Measure in computational basis
444 let computational_measurement_result =
445 transformed_state._measure_computational(actual_measured_qubits)?;
446 // Transform the new state back by applying Hadamard again
447 let final_state = computational_measurement_result
448 .new_state
449 .h_multi(actual_measured_qubits)?;
450 Ok(MeasurementResult {
451 basis: MeasurementBasis::X,
452 indices: computational_measurement_result.indices,
453 outcomes: computational_measurement_result.outcomes,
454 new_state: final_state,
455 })
456 }
457 MeasurementBasis::Y => {
458 // Apply Sdg then H to measured qubits
459 let state_after_sdag = self.s_dag_multi(actual_measured_qubits)?;
460 let transformed_state = state_after_sdag.h_multi(actual_measured_qubits)?;
461 // Measure in computational basis
462 let computational_measurement_result =
463 transformed_state._measure_computational(actual_measured_qubits)?;
464 // Transform the new state back by applying H then S
465 let state_after_h = computational_measurement_result
466 .new_state
467 .h_multi(actual_measured_qubits)?;
468 let final_state = state_after_h.s_multi(actual_measured_qubits)?;
469 Ok(MeasurementResult {
470 basis: MeasurementBasis::Y,
471 indices: computational_measurement_result.indices,
472 outcomes: computational_measurement_result.outcomes,
473 new_state: final_state,
474 })
475 }
476 MeasurementBasis::Custom(u_matrix) => {
477 // Apply the custom unitary U to measured qubits
478 let transformed_state = self.unitary_multi(actual_measured_qubits, u_matrix)?;
479
480 // Measure in computational basis
481 let computational_measurement_result =
482 transformed_state._measure_computational(actual_measured_qubits)?;
483
484 // Calculate U_dagger (adjoint of u_matrix)
485 let u_dagger_matrix = calculate_adjoint(&u_matrix);
486
487 // Transform the new state back by applying U_dagger
488 let final_state = computational_measurement_result
489 .new_state
490 .unitary_multi(actual_measured_qubits, u_dagger_matrix)?;
491
492 Ok(MeasurementResult {
493 basis: MeasurementBasis::Custom(u_matrix),
494 indices: computational_measurement_result.indices,
495 outcomes: computational_measurement_result.outcomes,
496 new_state: final_state,
497 })
498 }
499 }
500 }
501
502 /// Measures the state vector `n` times in the specified basis and returns the measurement results.
503 ///
504 /// # Arguments
505 ///
506 /// * `basis` - The basis to measure in.
507 /// * `indices` - The indices of the qubits to measure. If `indices` is empty, all qubits are measured.
508 /// * `n` - The number of measurements to perform.
509 ///
510 /// # Returns
511 ///
512 /// * `results` - A result containing a vector of measurement results if successful, or an error if the measurement fails.
513 ///
514 /// # Errors
515 ///
516 /// * Returns an error if the measurement fails.
517 /// * Returns an error if the number of qubits is invalid.
518 /// * Returns an error if the indices are out of bounds for the state vector.
519 /// * Returns an error if `n` is 0.
520 pub fn measure_n(
521 &self,
522 basis: MeasurementBasis,
523 measured_qubits: &[usize],
524 n: usize,
525 ) -> Result<Vec<MeasurementResult>, Error> {
526 if n == 0 {
527 return Err(Error::InvalidNumberOfMeasurements(0));
528 }
529
530 // If no indices are provided, measure all qubits
531 let all_indices: Vec<usize> = (0..self.num_qubits).collect();
532 let actual_measured_qubits: &[usize] = if measured_qubits.is_empty() {
533 &all_indices
534 } else {
535 measured_qubits
536 };
537
538 // Check for valid indices
539 let num_measured: usize = actual_measured_qubits.len();
540 if num_measured > self.num_qubits {
541 return Err(Error::InvalidNumberOfQubits(self.num_qubits));
542 }
543 for &index in actual_measured_qubits {
544 if index >= self.num_qubits {
545 return Err(Error::InvalidQubitIndex(index, self.num_qubits));
546 }
547 }
548
549 let results: Vec<MeasurementResult> = (0..n)
550 .into_par_iter()
551 .map(|_| self.measure(basis, actual_measured_qubits))
552 .collect::<Result<Vec<MeasurementResult>, Error>>()?;
553 Ok(results)
554 }
555
556 /// Performs a tensor product of two state vectors and returns the resulting state.
557 /// Uses parallel computation if the resulting dimension is large enough.
558 ///
559 /// # Arguments
560 ///
561 /// * `other` - The other state vector to perform the tensor product with.
562 ///
563 /// # Returns
564 ///
565 /// * `result` - A result containing the new state object if successful, or an error if the operation fails.
566 ///
567 /// # Errors
568 ///
569 /// * Returns an error if either state vector is empty.
570 /// * Returns an error if either state vector has an invalid number of qubits.
571 pub fn tensor_product(&self, other: &Self) -> Result<Self, Error> {
572 if self.num_qubits == 0 || other.num_qubits == 0 {
573 return Err(Error::InvalidNumberOfQubits(0));
574 }
575
576 let new_num_qubits: usize = self.num_qubits + other.num_qubits;
577 let new_dim: usize = 1 << new_num_qubits;
578 let other_dim: usize = 1 << other.num_qubits; // Cache dimension of other state
579
580 // Threshold for using parallel computation
581 const PARALLEL_THRESHOLD: usize = 1 << 6; // Parallelise when dimension is larger than 64
582
583 let new_state_vector: Vec<Complex<f64>> = if new_dim > PARALLEL_THRESHOLD {
584 // Parallel calculation for large states
585 (0..new_dim)
586 .into_par_iter()
587 .map(|new_index| {
588 let i: usize = new_index >> other.num_qubits; // Index for self.state_vector
589 let j: usize = new_index & (other_dim - 1); // Index for other.state_vector
590 self.state_vector[i] * other.state_vector[j]
591 })
592 .collect()
593 } else {
594 // Sequential calculation for smaller states
595 let mut temp_state_vector: Vec<Complex<f64>> = vec![Complex::new(0.0, 0.0); new_dim];
596 for i in 0..self.state_vector.len() {
597 for j in 0..other.state_vector.len() {
598 temp_state_vector[(i * other_dim) + j] =
599 self.state_vector[i] * other.state_vector[j];
600 }
601 }
602 temp_state_vector
603 };
604
605 Self::new(new_state_vector) // For normalisation check
606 }
607
608 /// Performs a tensor product of two state vectors without checking for validity.
609 #[allow(dead_code)]
610 pub(crate) fn tensor_product_unchecked(&self, other: &Self) -> Self {
611 let new_num_qubits: usize = self.num_qubits + other.num_qubits;
612 let new_dim: usize = 1 << new_num_qubits;
613 let other_dim: usize = 1 << other.num_qubits; // Cache dimension of other state
614
615 // Threshold for using parallel computation
616 const PARALLEL_THRESHOLD: usize = 1 << 6; // Parallelise when dimension is larger than 64
617
618 let new_state_vector: Vec<Complex<f64>> = if new_dim > PARALLEL_THRESHOLD {
619 // Parallel calculation for large states
620 (0..new_dim)
621 .into_par_iter()
622 .map(|new_index| {
623 let i: usize = new_index >> other.num_qubits; // Index for self.state_vector
624 let j: usize = new_index & (other_dim - 1); // Index for other.state_vector
625 self.state_vector[i] * other.state_vector[j]
626 })
627 .collect()
628 } else {
629 // Sequential calculation for smaller states
630 let mut temp_state_vector: Vec<Complex<f64>> = vec![Complex::new(0.0, 0.0); new_dim];
631 for i in 0..self.state_vector.len() {
632 for j in 0..other.state_vector.len() {
633 temp_state_vector[(i * other_dim) + j] =
634 self.state_vector[i] * other.state_vector[j];
635 }
636 }
637 temp_state_vector
638 };
639
640 Self {
641 state_vector: new_state_vector,
642 num_qubits: new_num_qubits,
643 }
644 }
645
646 /// Performs an inner product of two state vectors and returns the resulting complex number.
647 ///
648 /// # Arguments
649 ///
650 /// * `other` - The other state vector to perform the inner product with.
651 ///
652 /// # Returns
653 ///
654 /// * `result` - A result containing the inner product as a complex number if successful, or an error if the operation fails.
655 ///
656 /// # Errors
657 ///
658 /// * Returns an error if either state vector is empty.
659 /// * Returns an error if the state vectors have different dimensions.
660 pub fn inner_product(&self, other: &Self) -> Result<Complex<f64>, Error> {
661 if self.num_qubits == 0 || other.num_qubits == 0 {
662 return Err(Error::InvalidNumberOfQubits(0));
663 }
664
665 if self.state_vector.len() != other.state_vector.len() {
666 return Err(Error::InvalidNumberOfQubits(self.state_vector.len()));
667 }
668
669 const PARALLEL_THRESHOLD: usize = 1 << 6; // Threshold for parallelisation
670 let len = self.state_vector.len();
671
672 let inner_product: Complex<f64> = if len > PARALLEL_THRESHOLD {
673 self.state_vector
674 .par_iter()
675 .zip(other.state_vector.par_iter())
676 .map(|(a, b)| a.conj() * b)
677 .sum()
678 } else {
679 self.state_vector
680 .iter()
681 .zip(other.state_vector.iter())
682 .map(|(a, b)| a.conj() * b)
683 .sum()
684 };
685
686 Ok(inner_product)
687 }
688
689 // ***** OPERATION FUNCTIONS *****
690
691 /// Applies a unitary operation to the state vector.
692 ///
693 /// # Arguments
694 ///
695 /// * `unitary` - The unitary operation to apply, represented as an `Operator` trait object.
696 ///
697 /// * target_qubits - The indices of the qubits to apply the unitary operation to.
698 ///
699 /// * control_qubits - The indices of the control qubits for the unitary operation, if any.
700 ///
701 /// # Returns
702 ///
703 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
704 ///
705 /// # Errors
706 ///
707 /// * Returns an error if the unitary operation is invalid.
708 ///
709 /// * Returns an error if the number of qubits provided is invalid.
710 ///
711 /// * Returns an error if the indices are out of bounds for the state vector.
712 pub fn operate(
713 &self,
714 unitary: impl Operator,
715 target_qubits: &[usize],
716 control_qubits: &[usize],
717 ) -> Result<Self, Error> {
718 // Check for valid indices
719 let num_target: usize = target_qubits.len();
720 let num_control: usize = control_qubits.len();
721
722 if unitary.base_qubits() != (num_target + num_control) {
723 return Err(Error::InvalidNumberOfQubits(unitary.base_qubits()));
724 }
725
726 if num_target > self.num_qubits {
727 return Err(Error::InvalidNumberOfQubits(self.num_qubits));
728 }
729
730 for &index in target_qubits {
731 if index >= self.num_qubits {
732 return Err(Error::InvalidQubitIndex(index, self.num_qubits));
733 }
734 }
735
736 for &index in control_qubits {
737 if index >= self.num_qubits {
738 return Err(Error::InvalidQubitIndex(index, self.num_qubits));
739 }
740 }
741
742 // Apply the unitary operation to the state vector and return the new state
743 unitary.apply(self, target_qubits, control_qubits)
744 }
745
746 // -- SINGLE-QUBIT GATES --
747
748 /// Applies the Hadamard gate to the specified qubit in the state vector.
749 ///
750 /// # Arguments
751 ///
752 /// * `index` - The index of the qubit to apply the Hadamard gate to.
753 ///
754 /// # Returns
755 ///
756 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
757 ///
758 /// # Errors
759 ///
760 /// * Returns an error if the index is out of bounds for the state vector.
761 pub fn h(&self, index: usize) -> Result<Self, Error> {
762 Hadamard {}.apply(self, &[index], &[])
763 }
764
765 /// Applies the Hadamard gate to the specified qubits in the state vector in the given order.
766 ///
767 /// # Arguments
768 ///
769 /// * `qubits` - The indices of the qubits to apply the Hadamard gate to.
770 ///
771 /// # Returns
772 ///
773 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
774 ///
775 /// * # Errors
776 ///
777 /// * Returns an error if the number of qubits provided is invalid.
778 ///
779 /// * Returns an error if the indices are out of bounds for the state vector.
780 pub fn h_multi(&self, qubits: &[usize]) -> Result<Self, Error> {
781 let mut new_state: State = self.clone();
782 let h: Hadamard = Hadamard {};
783 for &qubit in qubits {
784 new_state = h.apply(&new_state, &[qubit], &[])?;
785 }
786 Ok(new_state)
787 }
788
789 /// Applies the controlled Hadamard gate to the specified qubits in the state vector in the given order.
790 ///
791 /// # Arguments
792 ///
793 /// * `target_qubits` - The indices of the target qubits to apply the controlled Hadamard gate to.
794 ///
795 /// * `control_qubits` - The indices of the control qubits for the controlled Hadamard gate.
796 ///
797 /// # Returns
798 ///
799 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
800 ///
801 /// * # Errors
802 ///
803 /// * Returns an error if the number of qubits provided is invalid.
804 ///
805 /// * Returns an error if the indices are out of bounds for the state vector.
806 ///
807 /// * Returns an error if the control qubits and target qubits overlap.
808 pub fn ch_multi(
809 &self,
810 target_qubits: &[usize],
811 control_qubits: &[usize],
812 ) -> Result<Self, Error> {
813 let mut new_state: State = self.clone();
814 let h: Hadamard = Hadamard {};
815 for &qubit in target_qubits {
816 new_state = h.apply(&new_state, &[qubit], control_qubits)?;
817 }
818 Ok(new_state)
819 }
820
821 /// Applies the Pauli-X (NOT) gate to the specified qubit in the state vector.
822 ///
823 /// # Arguments
824 ///
825 /// * `index` - The index of the qubit to apply the Pauli-X gate to.
826 ///
827 /// # Returns
828 ///
829 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
830 ///
831 /// # Errors
832 ///
833 /// * Returns an error if the index is out of bounds for the state vector.
834 pub fn x(&self, index: usize) -> Result<Self, Error> {
835 Pauli::X.apply(self, &[index], &[])
836 }
837
838 /// Applies the Pauli-X (NOT) gate to the specified qubits in the state vector in the given order.
839 ///
840 /// # Arguments
841 ///
842 /// * `qubits` - The indices of the qubits to apply the Pauli-X gate to.
843 ///
844 /// # Returns
845 ///
846 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
847 ///
848 /// # Errors
849 ///
850 /// * Returns an error if the number of qubits provided is invalid.
851 ///
852 /// * Returns an error if the indices are out of bounds for the state vector.
853 pub fn x_multi(&self, qubits: &[usize]) -> Result<Self, Error> {
854 let mut new_state: State = self.clone();
855 let x: Pauli = Pauli::X;
856 for &qubit in qubits {
857 new_state = x.apply(&new_state, &[qubit], &[])?;
858 }
859 Ok(new_state)
860 }
861
862 /// Applies the controlled Pauli-X (NOT) gate to the specified qubits in the state vector in the given order.
863 ///
864 /// # Arguments
865 ///
866 /// * `target_qubits` - The indices of the target qubits to apply the controlled Pauli-X gate to.
867 /// * `control_qubits` - The indices of the control qubits for the controlled Pauli-X gate.
868 ///
869 /// # Returns
870 ///
871 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
872 ///
873 /// # Errors
874 ///
875 /// * Returns an error if the number of qubits provided is invalid.
876 /// * Returns an error if the indices are out of bounds for the state vector.
877 /// * Returns an error if the control qubits and target qubits overlap.
878 pub fn cx_multi(
879 &self,
880 target_qubits: &[usize],
881 control_qubits: &[usize],
882 ) -> Result<Self, Error> {
883 let mut new_state: State = self.clone();
884 let x: Pauli = Pauli::X;
885 for &qubit in target_qubits {
886 new_state = x.apply(&new_state, &[qubit], control_qubits)?;
887 }
888 Ok(new_state)
889 }
890
891 /// Applies the Pauli-Y gate to the specified qubit in the state vector.
892 ///
893 /// # Arguments
894 ///
895 /// * `index` - The index of the qubit to apply the Pauli-Y gate to.
896 ///
897 /// # Returns
898 ///
899 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
900 ///
901 /// # Errors
902 ///
903 /// * Returns an error if the index is out of bounds for the state vector.
904 pub fn y(&self, index: usize) -> Result<Self, Error> {
905 Pauli::Y.apply(self, &[index], &[])
906 }
907
908 /// Applies the Pauli-Y gate to the specified qubits in the state vector in the given order.
909 ///
910 /// # Arguments
911 ///
912 /// * `qubits` - The indices of the qubits to apply the Pauli-Y gate to.
913 ///
914 /// # Returns
915 ///
916 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
917 ///
918 /// # Errors
919 ///
920 /// * Returns an error if the number of qubits provided is invalid.
921 ///
922 /// * Returns an error if the indices are out of bounds for the state vector.
923 pub fn y_multi(&self, qubits: &[usize]) -> Result<Self, Error> {
924 let mut new_state: State = self.clone();
925 let y: Pauli = Pauli::Y;
926 for &qubit in qubits {
927 new_state = y.apply(&new_state, &[qubit], &[])?;
928 }
929 Ok(new_state)
930 }
931
932 /// Applies the controlled Pauli-Y gate to the specified qubits in the state vector in the given order.
933 ///
934 /// # Arguments
935 ///
936 /// * `target_qubits` - The indices of the target qubits to apply the controlled Pauli-Y gate to.
937 /// * `control_qubits` - The indices of the control qubits for the controlled Pauli-Y gate.
938 ///
939 /// # Returns
940 ///
941 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
942 ///
943 /// # Errors
944 ///
945 /// * Returns an error if the number of qubits provided is invalid.
946 /// * Returns an error if the indices are out of bounds for the state vector.
947 /// * Returns an error if the control qubits and target qubits overlap.
948 pub fn cy_multi(
949 &self,
950 target_qubits: &[usize],
951 control_qubits: &[usize],
952 ) -> Result<Self, Error> {
953 let mut new_state: State = self.clone();
954 let y: Pauli = Pauli::Y;
955 for &qubit in target_qubits {
956 new_state = y.apply(&new_state, &[qubit], control_qubits)?;
957 }
958 Ok(new_state)
959 }
960
961 /// Applies the Pauli-Z gate to the specified qubit in the state vector.
962 ///
963 /// # Arguments
964 ///
965 /// * `index` - The index of the qubit to apply the Pauli-Z gate to.
966 ///
967 /// # Returns
968 ///
969 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
970 ///
971 /// # Errors
972 ///
973 /// * Returns an error if the index is out of bounds for the state vector.
974 pub fn z(&self, index: usize) -> Result<Self, Error> {
975 Pauli::Z.apply(self, &[index], &[])
976 }
977
978 /// Applies the Pauli-Z gate to the specified qubits in the state vector in the given order.
979 ///
980 /// # Arguments
981 ///
982 /// * `qubits` - The indices of the qubits to apply the Pauli-Z gate to.
983 ///
984 /// # Returns
985 ///
986 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
987 ///
988 /// # Errors
989 ///
990 /// * Returns an error if the number of qubits provided is invalid.
991 ///
992 /// * Returns an error if the indices are out of bounds for the state vector.
993 pub fn z_multi(&self, qubits: &[usize]) -> Result<Self, Error> {
994 let mut new_state: State = self.clone();
995 let z: Pauli = Pauli::Z;
996 for &qubit in qubits {
997 new_state = z.apply(&new_state, &[qubit], &[])?;
998 }
999 Ok(new_state)
1000 }
1001
1002 /// Applies the controlled Pauli-Z gate to the specified qubits in the state vector in the given order.
1003 ///
1004 /// # Arguments
1005 ///
1006 /// * `target_qubits` - The indices of the target qubits to apply the controlled Pauli-Z gate to.
1007 /// * `control_qubits` - The indices of the control qubits for the controlled Pauli-Z gate.
1008 ///
1009 /// # Returns
1010 ///
1011 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1012 ///
1013 /// # Errors
1014 ///
1015 /// * Returns an error if the number of qubits provided is invalid.
1016 /// * Returns an error if the indices are out of bounds for the state vector.
1017 /// * Returns an error if the control qubits and target qubits overlap.
1018 pub fn cz_multi(
1019 &self,
1020 target_qubits: &[usize],
1021 control_qubits: &[usize],
1022 ) -> Result<Self, Error> {
1023 let mut new_state: State = self.clone();
1024 let z: Pauli = Pauli::Z;
1025 for &qubit in target_qubits {
1026 new_state = z.apply(&new_state, &[qubit], control_qubits)?;
1027 }
1028 Ok(new_state)
1029 }
1030
1031 /// Applies the Identity gate to the state vector.
1032 ///
1033 /// # Arguments
1034 ///
1035 /// * `qubit` - The index of the qubit to apply the Identity gate to.
1036 ///
1037 /// # Returns
1038 ///
1039 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1040 ///
1041 /// # Errors
1042 ///
1043 /// * Returns an error if the index is out of bounds for the state vector.
1044 pub fn i(&self, qubit: usize) -> Result<Self, Error> {
1045 Identity {}.apply(self, &[qubit], &[])
1046 }
1047
1048 /// Applies the Identity gate to the state vector for multiple qubits in the given order.
1049 ///
1050 /// # Arguments
1051 ///
1052 /// * `qubits` - The indices of the qubits to apply the Identity gate to.
1053 ///
1054 /// # Returns
1055 ///
1056 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1057 ///
1058 /// # Errors
1059 ///
1060 /// * Returns an error if the number of qubits provided is invalid.
1061 ///
1062 /// * Returns an error if the indices are out of bounds for the state vector.
1063 pub fn i_multi(&self, qubits: &[usize]) -> Result<Self, Error> {
1064 let mut new_state: State = self.clone();
1065 let i: Identity = Identity {};
1066 for &qubit in qubits {
1067 new_state = i.apply(&new_state, &[qubit], &[])?;
1068 }
1069 Ok(new_state)
1070 }
1071
1072 /// Applies the controlled Identity gate to the state vector for multiple qubits in the given order.
1073 ///
1074 /// # Arguments
1075 ///
1076 /// * `target_qubits` - The indices of the target qubits to apply the controlled Identity gate to.
1077 /// * `control_qubits` - The indices of the control qubits for the controlled Identity gate.
1078 ///
1079 /// # Returns
1080 ///
1081 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1082 ///
1083 /// # Errors
1084 ///
1085 /// * Returns an error if the number of qubits provided is invalid.
1086 /// * Returns an error if the indices are out of bounds for the state vector.
1087 /// * Returns an error if the control qubits and target qubits overlap.
1088 pub fn ci_multi(
1089 &self,
1090 target_qubits: &[usize],
1091 control_qubits: &[usize],
1092 ) -> Result<Self, Error> {
1093 let mut new_state: State = self.clone();
1094 let i: Identity = Identity {};
1095 for &qubit in target_qubits {
1096 new_state = i.apply(&new_state, &[qubit], control_qubits)?;
1097 }
1098 Ok(new_state)
1099 }
1100
1101 /// Applies the Phase S gate to the specified qubit in the state vector.
1102 ///
1103 /// # Arguments
1104 ///
1105 /// * `index` - The index of the qubit to apply the Phase S gate to.
1106 ///
1107 /// # Returns
1108 ///
1109 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1110 ///
1111 /// # Errors
1112 ///
1113 /// * Returns an error if the index is out of bounds for the state vector.
1114 pub fn s(&self, index: usize) -> Result<Self, Error> {
1115 PhaseS {}.apply(self, &[index], &[])
1116 }
1117
1118 /// Applies the Phase S gate to the specified qubits in the state vector in the given order.
1119 ///
1120 /// # Arguments
1121 ///
1122 /// * `qubits` - The indices of the qubits to apply the Phase S gate to.
1123 ///
1124 /// # Returns
1125 ///
1126 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1127 ///
1128 /// # Errors
1129 ///
1130 /// * Returns an error if the number of qubits provided is invalid.
1131 ///
1132 /// * Returns an error if the indices are out of bounds for the state vector.
1133 pub fn s_multi(&self, qubits: &[usize]) -> Result<Self, Error> {
1134 let mut new_state: State = self.clone();
1135 let s_gate: PhaseS = PhaseS {};
1136 for &qubit in qubits {
1137 new_state = s_gate.apply(&new_state, &[qubit], &[])?;
1138 }
1139 Ok(new_state)
1140 }
1141
1142 /// Applies the controlled Phase S gate to the specified qubits in the state vector in the given order.
1143 ///
1144 /// # Arguments
1145 ///
1146 /// * `target_qubits` - The indices of the target qubits to apply the controlled Phase S gate to.
1147 /// * `control_qubits` - The indices of the control qubits for the controlled Phase S gate.
1148 ///
1149 /// # Returns
1150 ///
1151 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1152 ///
1153 /// # Errors
1154 ///
1155 /// * Returns an error if the number of qubits provided is invalid.
1156 /// * Returns an error if the indices are out of bounds for the state vector.
1157 /// * Returns an error if the control qubits and target qubits overlap.
1158 pub fn cs_multi(
1159 &self,
1160 target_qubits: &[usize],
1161 control_qubits: &[usize],
1162 ) -> Result<Self, Error> {
1163 let mut new_state: State = self.clone();
1164 let s_gate: PhaseS = PhaseS {};
1165 for &qubit in target_qubits {
1166 new_state = s_gate.apply(&new_state, &[qubit], control_qubits)?;
1167 }
1168 Ok(new_state)
1169 }
1170
1171 /// Applies the Phase T gate to the specified qubit in the state vector.
1172 ///
1173 /// # Arguments
1174 ///
1175 /// * `index` - The index of the qubit to apply the Phase T gate to.
1176 ///
1177 /// # Returns
1178 ///
1179 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1180 ///
1181 /// # Errors
1182 ///
1183 /// * Returns an error if the index is out of bounds for the state vector.
1184 pub fn t(&self, index: usize) -> Result<Self, Error> {
1185 PhaseT {}.apply(self, &[index], &[])
1186 }
1187
1188 /// Applies the Phase T gate to the specified qubits in the state vector in the given order.
1189 ///
1190 /// # Arguments
1191 ///
1192 /// * `qubits` - The indices of the qubits to apply the Phase T gate to.
1193 ///
1194 /// # Returns
1195 ///
1196 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1197 ///
1198 /// # Errors
1199 ///
1200 /// * Returns an error if the number of qubits provided is invalid.
1201 ///
1202 /// * Returns an error if the indices are out of bounds for the state vector.
1203 pub fn t_multi(&self, qubits: &[usize]) -> Result<Self, Error> {
1204 let mut new_state: State = self.clone();
1205 let t_gate: PhaseT = PhaseT {};
1206 for &qubit in qubits {
1207 new_state = t_gate.apply(&new_state, &[qubit], &[])?;
1208 }
1209 Ok(new_state)
1210 }
1211
1212 /// Applies the controlled Phase T gate to the specified qubits in the state vector in the given order.
1213 ///
1214 /// # Arguments
1215 ///
1216 /// * `target_qubits` - The indices of the target qubits to apply the controlled Phase T gate to.
1217 /// * `control_qubits` - The indices of the control qubits for the controlled Phase T gate.
1218 ///
1219 /// # Returns
1220 ///
1221 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1222 ///
1223 /// # Errors
1224 ///
1225 /// * Returns an error if the number of qubits provided is invalid.
1226 /// * Returns an error if the indices are out of bounds for the state vector.
1227 /// * Returns an error if the control qubits and target qubits overlap.
1228 pub fn ct_multi(
1229 &self,
1230 target_qubits: &[usize],
1231 control_qubits: &[usize],
1232 ) -> Result<Self, Error> {
1233 let mut new_state: State = self.clone();
1234 let t_gate: PhaseT = PhaseT {};
1235 for &qubit in target_qubits {
1236 new_state = t_gate.apply(&new_state, &[qubit], control_qubits)?;
1237 }
1238 Ok(new_state)
1239 }
1240
1241 /// Applies the Phase S dagger gate to the specified qubit in the state vector.
1242 ///
1243 /// # Arguments
1244 ///
1245 /// * `index` - The index of the qubit to apply the Phase S dagger gate to.
1246 ///
1247 /// # Returns
1248 ///
1249 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1250 ///
1251 /// # Errors
1252 ///
1253 /// * Returns an error if the index is out of bounds for the state vector.
1254 pub fn s_dag(&self, index: usize) -> Result<Self, Error> {
1255 PhaseSdag {}.apply(self, &[index], &[])
1256 }
1257
1258 /// Applies the Phase S dagger gate to the specified qubits in the state vector in the given order.
1259 ///
1260 /// # Arguments
1261 ///
1262 /// * `qubits` - The indices of the qubits to apply the Phase S dagger gate to.
1263 ///
1264 /// # Returns
1265 ///
1266 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1267 ///
1268 /// # Errors
1269 ///
1270 /// * Returns an error if the number of qubits provided is invalid.
1271 ///
1272 /// * Returns an error if the indices are out of bounds for the state vector.
1273 pub fn s_dag_multi(&self, qubits: &[usize]) -> Result<Self, Error> {
1274 let mut new_state: State = self.clone();
1275 let sdag_gate: PhaseSdag = PhaseSdag {};
1276 for &qubit in qubits {
1277 new_state = sdag_gate.apply(&new_state, &[qubit], &[])?;
1278 }
1279 Ok(new_state)
1280 }
1281
1282 /// Applies the controlled Phase S dagger gate to the specified qubits in the state vector in the given order.
1283 ///
1284 /// # Arguments
1285 ///
1286 /// * `target_qubits` - The indices of the target qubits to apply the controlled Phase S dagger gate to.
1287 /// * `control_qubits` - The indices of the control qubits for the controlled Phase S dagger gate.
1288 ///
1289 /// # Returns
1290 ///
1291 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1292 ///
1293 /// # Errors
1294 ///
1295 /// * Returns an error if the number of qubits provided is invalid.
1296 /// * Returns an error if the indices are out of bounds for the state vector.
1297 /// * Returns an error if the control qubits and target qubits overlap.
1298 pub fn cs_dag_multi(
1299 &self,
1300 target_qubits: &[usize],
1301 control_qubits: &[usize],
1302 ) -> Result<Self, Error> {
1303 let mut new_state: State = self.clone();
1304 let sdag_gate: PhaseSdag = PhaseSdag {};
1305 for &qubit in target_qubits {
1306 new_state = sdag_gate.apply(&new_state, &[qubit], control_qubits)?;
1307 }
1308 Ok(new_state)
1309 }
1310
1311 /// Applies the Phase T dagger gate to the specified qubit in the state vector.
1312 ///
1313 /// # Arguments
1314 ///
1315 /// * `index` - The index of the qubit to apply the Phase T dagger gate to.
1316 ///
1317 /// # Returns
1318 ///
1319 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1320 ///
1321 /// # Errors
1322 ///
1323 /// * Returns an error if the index is out of bounds for the state vector.
1324 pub fn t_dag(&self, index: usize) -> Result<Self, Error> {
1325 PhaseTdag {}.apply(self, &[index], &[])
1326 }
1327
1328 /// Applies the Phase T dagger gate to the specified qubits in the state vector in the given order.
1329 ///
1330 /// # Arguments
1331 ///
1332 /// * `qubits` - The indices of the qubits to apply the Phase T dagger gate to.
1333 ///
1334 /// # Returns
1335 ///
1336 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1337 ///
1338 /// # Errors
1339 ///
1340 /// * Returns an error if the number of qubits provided is invalid.
1341 ///
1342 /// * Returns an error if the indices are out of bounds for the state vector.
1343 pub fn t_dag_multi(&self, qubits: &[usize]) -> Result<Self, Error> {
1344 let mut new_state: State = self.clone();
1345 let tdag_gate: PhaseTdag = PhaseTdag {};
1346 for &qubit in qubits {
1347 new_state = tdag_gate.apply(&new_state, &[qubit], &[])?;
1348 }
1349 Ok(new_state)
1350 }
1351
1352 /// Applies the controlled Phase T dagger gate to the specified qubits in the state vector in the given order.
1353 ///
1354 /// # Arguments
1355 ///
1356 /// * `target_qubits` - The indices of the target qubits to apply the controlled Phase T dagger gate to.
1357 /// * `control_qubits` - The indices of the control qubits for the controlled Phase T dagger gate.
1358 ///
1359 /// # Returns
1360 ///
1361 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1362 ///
1363 /// # Errors
1364 ///
1365 /// * Returns an error if the number of qubits provided is invalid.
1366 /// * Returns an error if the indices are out of bounds for the state vector.
1367 /// * Returns an error if the control qubits and target qubits overlap.
1368 pub fn ct_dag_multi(
1369 &self,
1370 target_qubits: &[usize],
1371 control_qubits: &[usize],
1372 ) -> Result<Self, Error> {
1373 let mut new_state: State = self.clone();
1374 let tdag_gate: PhaseTdag = PhaseTdag {};
1375 for &qubit in target_qubits {
1376 new_state = tdag_gate.apply(&new_state, &[qubit], control_qubits)?;
1377 }
1378 Ok(new_state)
1379 }
1380
1381 /// Applies the Phase Shift gate with the specified angle to the given qubit.
1382 ///
1383 /// # Arguments
1384 ///
1385 /// * `index` - The index of the qubit to apply the Phase Shift gate to.
1386 /// * `angle` - The phase shift angle in radians.
1387 ///
1388 /// # Returns
1389 ///
1390 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1391 ///
1392 /// # Errors
1393 ///
1394 /// * Returns an error if the index is out of bounds for the state vector.
1395 pub fn p(&self, index: usize, angle: f64) -> Result<Self, Error> {
1396 PhaseShift::new(angle).apply(self, &[index], &[])
1397 }
1398
1399 /// Applies the Phase Shift gate with the specified angle to the given qubits in order.
1400 ///
1401 /// # Arguments
1402 ///
1403 /// * `qubits` - The indices of the qubits to apply the Phase Shift gate to.
1404 ///
1405 /// * `angle` - The phase shift angle in radians.
1406 ///
1407 /// # Returns
1408 ///
1409 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1410 ///
1411 /// # Errors
1412 ///
1413 /// * Returns an error if the number of qubits provided is invalid.
1414 ///
1415 /// * Returns an error if the indices are out of bounds for the state vector.
1416 pub fn p_multi(&self, qubits: &[usize], angle: f64) -> Result<Self, Error> {
1417 let mut new_state: State = self.clone();
1418 let phase_shift_gate: PhaseShift = PhaseShift::new(angle);
1419 for &qubit in qubits {
1420 new_state = phase_shift_gate.apply(&new_state, &[qubit], &[])?;
1421 }
1422 Ok(new_state)
1423 }
1424
1425 /// Applies the controlled Phase Shift gate with the specified angle to the given qubits in order.
1426 ///
1427 /// # Arguments
1428 ///
1429 /// * `target_qubits` - The indices of the target qubits to apply the controlled Phase Shift gate to.
1430 /// * `control_qubits` - The indices of the control qubits for the controlled Phase Shift gate.
1431 /// * `angle` - The phase shift angle in radians.
1432 ///
1433 /// # Returns
1434 ///
1435 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1436 ///
1437 /// # Errors
1438 ///
1439 /// * Returns an error if the number of qubits provided is invalid.
1440 /// * Returns an error if the indices are out of bounds for the state vector.
1441 /// * Returns an error if the control qubits and target qubits overlap.
1442 pub fn cp_multi(
1443 &self,
1444 target_qubits: &[usize],
1445 control_qubits: &[usize],
1446 angle: f64,
1447 ) -> Result<Self, Error> {
1448 let mut new_state: State = self.clone();
1449 let phase_shift_gate: PhaseShift = PhaseShift::new(angle);
1450 for &qubit in target_qubits {
1451 new_state = phase_shift_gate.apply(&new_state, &[qubit], control_qubits)?;
1452 }
1453 Ok(new_state)
1454 }
1455
1456 /// Applies the RotateX gate with the specified angle to the given qubit.
1457 ///
1458 /// # Arguments
1459 ///
1460 /// * `index` - The index of the qubit to apply the RotateX gate to.
1461 /// * `angle` - The rotation angle in radians.
1462 ///
1463 /// # Returns
1464 ///
1465 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1466 ///
1467 /// # Errors
1468 ///
1469 /// * Returns an error if the index is out of bounds for the state vector.
1470 pub fn rx(&self, index: usize, angle: f64) -> Result<Self, Error> {
1471 RotateX::new(angle).apply(self, &[index], &[])
1472 }
1473
1474 /// Applies the RotateX gate with the specified angle to the given qubits in order.
1475 ///
1476 /// # Arguments
1477 ///
1478 /// * `qubits` - The indices of the qubits to apply the RotateX gate to.
1479 ///
1480 /// * `angle` - The rotation angle in radians.
1481 ///
1482 /// # Returns
1483 ///
1484 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1485 ///
1486 /// # Errors
1487 ///
1488 /// * Returns an error if the number of qubits provided is invalid.
1489 ///
1490 /// * Returns an error if the indices are out of bounds for the state vector.
1491 pub fn rx_multi(&self, qubits: &[usize], angle: f64) -> Result<Self, Error> {
1492 let mut new_state: State = self.clone();
1493 let rotate_x_gate: RotateX = RotateX::new(angle);
1494 for &qubit in qubits {
1495 new_state = rotate_x_gate.apply(&new_state, &[qubit], &[])?;
1496 }
1497 Ok(new_state)
1498 }
1499
1500 /// Applies the controlled RotateX gate with the specified angle to the given qubits in order.
1501 ///
1502 /// # Arguments
1503 ///
1504 /// * `target_qubits` - The indices of the target qubits to apply the controlled RotateX gate to.
1505 /// * `control_qubits` - The indices of the control qubits for the controlled RotateX gate.
1506 /// * `angle` - The rotation angle in radians.
1507 ///
1508 /// # Returns
1509 ///
1510 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1511 ///
1512 /// # Errors
1513 ///
1514 /// * Returns an error if the number of qubits provided is invalid.
1515 /// * Returns an error if the indices are out of bounds for the state vector.
1516 /// * Returns an error if the control qubits and target qubits overlap.
1517 pub fn crx_multi(
1518 &self,
1519 target_qubits: &[usize],
1520 control_qubits: &[usize],
1521 angle: f64,
1522 ) -> Result<Self, Error> {
1523 let mut new_state: State = self.clone();
1524 let rotate_x_gate: RotateX = RotateX::new(angle);
1525 for &qubit in target_qubits {
1526 new_state = rotate_x_gate.apply(&new_state, &[qubit], control_qubits)?;
1527 }
1528 Ok(new_state)
1529 }
1530
1531 /// Applies the RotateY gate with the specified angle to the given qubit.
1532 ///
1533 /// # Arguments
1534 ///
1535 /// * `index` - The index of the qubit to apply the RotateY gate to.
1536 /// * `angle` - The rotation angle in radians.
1537 ///
1538 /// # Returns
1539 ///
1540 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1541 ///
1542 /// # Errors
1543 ///
1544 /// * Returns an error if the index is out of bounds for the state vector.
1545 pub fn ry(&self, index: usize, angle: f64) -> Result<Self, Error> {
1546 RotateY::new(angle).apply(self, &[index], &[])
1547 }
1548
1549 /// Applies the RotateY gate with the specified angle to the given qubits in order.
1550 ///
1551 /// # Arguments
1552 ///
1553 /// * `qubits` - The indices of the qubits to apply the RotateY gate to.
1554 ///
1555 /// * `angle` - The rotation angle in radians.
1556 ///
1557 /// # Returns
1558 ///
1559 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1560 ///
1561 /// # Errors
1562 ///
1563 /// * Returns an error if the number of qubits provided is invalid.
1564 ///
1565 /// * Returns an error if the indices are out of bounds for the state vector.
1566 pub fn ry_multi(&self, qubits: &[usize], angle: f64) -> Result<Self, Error> {
1567 let mut new_state: State = self.clone();
1568 let rotate_y_gate: RotateY = RotateY::new(angle);
1569 for &qubit in qubits {
1570 new_state = rotate_y_gate.apply(&new_state, &[qubit], &[])?;
1571 }
1572 Ok(new_state)
1573 }
1574
1575 /// Applies the controlled RotateY gate with the specified angle to the given qubits in order.
1576 ///
1577 /// # Arguments
1578 ///
1579 /// * `target_qubits` - The indices of the target qubits to apply the controlled RotateY gate to.
1580 /// * `control_qubits` - The indices of the control qubits for the controlled RotateY gate.
1581 /// * `angle` - The rotation angle in radians.
1582 ///
1583 /// # Returns
1584 ///
1585 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1586 ///
1587 /// # Errors
1588 ///
1589 /// * Returns an error if the number of qubits provided is invalid.
1590 /// * Returns an error if the indices are out of bounds for the state vector.
1591 /// * Returns an error if the control qubits and target qubits overlap.
1592 pub fn cry_multi(
1593 &self,
1594 target_qubits: &[usize],
1595 control_qubits: &[usize],
1596 angle: f64,
1597 ) -> Result<Self, Error> {
1598 let mut new_state: State = self.clone();
1599 let rotate_y_gate: RotateY = RotateY::new(angle);
1600 for &qubit in target_qubits {
1601 new_state = rotate_y_gate.apply(&new_state, &[qubit], control_qubits)?;
1602 }
1603 Ok(new_state)
1604 }
1605
1606 /// Applies the RotateZ gate with the specified angle to the given qubit.
1607 ///
1608 /// # Arguments
1609 ///
1610 /// * `index` - The index of the qubit to apply the RotateZ gate to.
1611 /// * `angle` - The rotation angle in radians.
1612 ///
1613 /// # Returns
1614 ///
1615 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1616 ///
1617 /// # Errors
1618 ///
1619 /// * Returns an error if the index is out of bounds for the state vector.
1620 pub fn rz(&self, index: usize, angle: f64) -> Result<Self, Error> {
1621 RotateZ::new(angle).apply(self, &[index], &[])
1622 }
1623
1624 /// Applies the RotateZ gate with the specified angle to the given qubits in order.
1625 ///
1626 /// # Arguments
1627 ///
1628 /// * `qubits` - The indices of the qubits to apply the RotateZ gate to.
1629 ///
1630 /// * `angle` - The rotation angle in radians.
1631 ///
1632 /// # Returns
1633 ///
1634 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1635 ///
1636 /// # Errors
1637 ///
1638 /// * Returns an error if the number of qubits provided is invalid.
1639 ///
1640 /// * Returns an error if the indices are out of bounds for the state vector.
1641 pub fn rz_multi(&self, qubits: &[usize], angle: f64) -> Result<Self, Error> {
1642 let mut new_state: State = self.clone();
1643 let rotate_z_gate: RotateZ = RotateZ::new(angle);
1644 for &qubit in qubits {
1645 new_state = rotate_z_gate.apply(&new_state, &[qubit], &[])?;
1646 }
1647 Ok(new_state)
1648 }
1649
1650 /// Applies the controlled RotateZ gate with the specified angle to the given qubits in order.
1651 ///
1652 /// # Arguments
1653 ///
1654 /// * `target_qubits` - The indices of the target qubits to apply the controlled RotateZ gate to.
1655 /// * `control_qubits` - The indices of the control qubits for the controlled RotateZ gate.
1656 /// * `angle` - The rotation angle in radians.
1657 ///
1658 /// # Returns
1659 ///
1660 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1661 ///
1662 /// # Errors
1663 ///
1664 /// * Returns an error if the number of qubits provided is invalid.
1665 /// * Returns an error if the indices are out of bounds for the state vector.
1666 /// * Returns an error if the control qubits and target qubits overlap.
1667 pub fn crz_multi(
1668 &self,
1669 target_qubits: &[usize],
1670 control_qubits: &[usize],
1671 angle: f64,
1672 ) -> Result<Self, Error> {
1673 let mut new_state: State = self.clone();
1674 let rotate_z_gate: RotateZ = RotateZ::new(angle);
1675 for &qubit in target_qubits {
1676 new_state = rotate_z_gate.apply(&new_state, &[qubit], control_qubits)?;
1677 }
1678 Ok(new_state)
1679 }
1680
1681 /// Applies the unitary gate to the specified qubit in the state vector.
1682 ///
1683 /// # Arguments
1684 ///
1685 /// * `index` - The index of the qubit to apply the unitary gate to.
1686 ///
1687 /// * `unitary` - The unitary matrix to apply.
1688 ///
1689 /// # Returns
1690 ///
1691 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1692 ///
1693 /// # Errors
1694 ///
1695 /// * Returns an error if the index is out of bounds for the state vector.
1696 ///
1697 /// * Returns an error if the unitary matrix is not unitary.
1698 pub fn unitary(&self, index: usize, unitary: [[Complex<f64>; 2]; 2]) -> Result<Self, Error> {
1699 let mut new_state: State = self.clone();
1700 let unitary_gate: Unitary2 = Unitary2::new(unitary)?;
1701 new_state = unitary_gate.apply(&new_state, &[index], &[])?;
1702 Ok(new_state)
1703 }
1704
1705 /// Applies the unitary gate to the specified qubits in the state vector in the given order.
1706 ///
1707 /// # Arguments
1708 ///
1709 /// * `qubits` - The indices of the qubits to apply the unitary gate to.
1710 ///
1711 /// * `unitary` - The unitary matrix to apply.
1712 ///
1713 /// # Returns
1714 ///
1715 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1716 ///
1717 /// # Errors
1718 ///
1719 /// * Returns an error if the number of qubits provided is invalid.
1720 ///
1721 /// * Returns an error if the indices are out of bounds for the state vector.
1722 ///
1723 /// * Returns an error if the unitary matrix is not unitary.
1724 pub fn unitary_multi(
1725 &self,
1726 qubits: &[usize],
1727 unitary: [[Complex<f64>; 2]; 2],
1728 ) -> Result<Self, Error> {
1729 let mut new_state: State = self.clone();
1730 let unitary_gate: Unitary2 = Unitary2::new(unitary)?;
1731 for &qubit in qubits {
1732 new_state = unitary_gate.apply(&new_state, &[qubit], &[])?;
1733 }
1734 Ok(new_state)
1735 }
1736
1737 /// Applies the controlled unitary gate to the specified qubits in the state vector in the given order.
1738 ///
1739 /// # Arguments
1740 ///
1741 /// * `target_qubits` - The indices of the target qubits to apply the controlled unitary gate to.
1742 ///
1743 /// * `control_qubits` - The indices of the control qubits for the controlled unitary gate.
1744 ///
1745 /// * `unitary` - The unitary matrix to apply.
1746 ///
1747 /// # Returns
1748 ///
1749 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1750 ///
1751 /// # Errors
1752 ///
1753 /// * Returns an error if the number of qubits provided is invalid.
1754 ///
1755 /// * Returns an error if the indices are out of bounds for the state vector.
1756 ///
1757 /// * Returns an error if the control qubits and target qubits overlap.
1758 ///
1759 /// * Returns an error if the unitary matrix is not unitary.
1760 pub fn cunitary_multi(
1761 &self,
1762 target_qubits: &[usize],
1763 control_qubits: &[usize],
1764 unitary: [[Complex<f64>; 2]; 2],
1765 ) -> Result<Self, Error> {
1766 let mut new_state: State = self.clone();
1767 let unitary_gate: Unitary2 = Unitary2::new(unitary)?;
1768 for &qubit in target_qubits {
1769 new_state = unitary_gate.apply(&new_state, &[qubit], control_qubits)?;
1770 }
1771 Ok(new_state)
1772 }
1773
1774 /// Applies the Unitary (constructed from rotation angle and phase shift) to the specified qubit in the state vector.
1775 ///
1776 /// # Arguments
1777 ///
1778 /// * `index` - The index of the qubit to apply the Unitary gate to.
1779 ///
1780 /// * `angle` - The rotation angle in radians.
1781 ///
1782 /// * `phase` - The phase shift angle in radians.
1783 ///
1784 /// # Returns
1785 ///
1786 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1787 ///
1788 /// # Errors
1789 ///
1790 /// * Returns an error if the index is out of bounds for the state vector.
1791 pub fn ry_phase(&self, index: usize, angle: f64, phase: f64) -> Result<Self, Error> {
1792 Unitary2::from_ry_phase(angle, phase).apply(self, &[index], &[])
1793 }
1794
1795 /// Applies the Unitary (constructed from rotation angle and phase shift) to the specified qubits in the state vector in the given order.
1796 ///
1797 /// # Arguments
1798 ///
1799 /// * `qubits` - The indices of the qubits to apply the Unitary gate to.
1800 ///
1801 /// * `angle` - The rotation angle in radians.
1802 ///
1803 /// * `phase` - The phase shift angle in radians.
1804 ///
1805 /// # Returns
1806 ///
1807 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1808 ///
1809 /// # Errors
1810 ///
1811 /// * Returns an error if the number of qubits provided is invalid.
1812 ///
1813 /// * Returns an error if the indices are out of bounds for the state vector.
1814 pub fn ry_phase_multi(&self, qubits: &[usize], angle: f64, phase: f64) -> Result<Self, Error> {
1815 let mut new_state: State = self.clone();
1816 let unitary_gate: Unitary2 = Unitary2::from_ry_phase(angle, phase);
1817 for &qubit in qubits {
1818 new_state = unitary_gate.apply(&new_state, &[qubit], &[])?;
1819 }
1820 Ok(new_state)
1821 }
1822
1823 /// Applies the controlled Unitary (constructed from rotation angle and phase shift) to the specified qubits in the state vector in the given order.
1824 ///
1825 /// # Arguments
1826 ///
1827 /// * `target_qubits` - The indices of the target qubits to apply the controlled Unitary gate to.
1828 ///
1829 /// * `control_qubits` - The indices of the control qubits for the controlled Unitary gate.
1830 ///
1831 /// * `angle` - The rotation angle in radians.
1832 ///
1833 /// * * `phase` - The phase shift angle in radians.
1834 ///
1835 /// # Returns
1836 ///
1837 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1838 ///
1839 /// # Errors
1840 ///
1841 /// * Returns an error if the number of qubits provided is invalid.
1842 ///
1843 /// * Returns an error if the indices are out of bounds for the state vector.
1844 ///
1845 /// * Returns an error if the control qubits and target qubits overlap.
1846 pub fn cry_phase_gates(
1847 &self,
1848 target_qubits: &[usize],
1849 control_qubits: &[usize],
1850 angle: f64,
1851 phase: f64,
1852 ) -> Result<Self, Error> {
1853 let mut new_state: State = self.clone();
1854 let unitary_gate: Unitary2 = Unitary2::from_ry_phase(angle, phase);
1855 for &qubit in target_qubits {
1856 new_state = unitary_gate.apply(&new_state, &[qubit], control_qubits)?;
1857 }
1858 Ok(new_state)
1859 }
1860
1861 // -- MULTI-QUBIT GATES --
1862
1863 /// Applies the CNOT (Controlled-NOT) gate to the state vector.
1864 ///
1865 /// # Arguments
1866 ///
1867 /// * `control` - The index of the control qubit.
1868 /// * `target` - The index of the target qubit.
1869 ///
1870 /// # Returns
1871 ///
1872 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1873 ///
1874 /// # Errors
1875 ///
1876 /// * Returns an error if any index is out of bounds for the state vector.
1877 pub fn cnot(&self, control: usize, target: usize) -> Result<Self, Error> {
1878 CNOT {}.apply(self, &[target], &[control])
1879 }
1880
1881 /// Applies the SWAP gate to the state vector.
1882 ///
1883 /// # Arguments
1884 ///
1885 /// * `qubit1` - The index of the first qubit to swap.
1886 /// * `qubit2` - The index of the second qubit to swap.
1887 ///
1888 /// # Returns
1889 ///
1890 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1891 ///
1892 /// # Errors
1893 ///
1894 /// * Returns an error if any index is out of bounds for the state vector.
1895 pub fn swap(&self, qubit1: usize, qubit2: usize) -> Result<Self, Error> {
1896 SWAP {}.apply(self, &[qubit1, qubit2], &[])
1897 }
1898
1899 /// Applies the controlled SWAP gate to the state vector.
1900 ///
1901 /// # Arguments
1902 ///
1903 /// * `target1` - The index of the first target qubit to swap.
1904 /// * `target2` - The index of the second target qubit to swap.
1905 /// * `controls` - The indices of the control qubits.
1906 ///
1907 /// # Returns
1908 ///
1909 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1910 ///
1911 /// # Errors
1912 ///
1913 /// * Returns an error if any index is out of bounds for the state vector.
1914 /// * Returns an error if target or control qubits overlap.
1915 pub fn cswap(&self, target1: usize, target2: usize, controls: &[usize]) -> Result<Self, Error> {
1916 SWAP {}.apply(self, &[target1, target2], controls)
1917 }
1918
1919 /// Applies the Matchgate to the state vector
1920 ///
1921 /// # Arguments
1922 ///
1923 /// * `target` - The index of the first target qubit. The second target qubit is automatically determined to be the next qubit.
1924 /// * `theta` - The rotation angle in radians
1925 /// * `phi1` - The first phase angle in radians
1926 /// * `phi2` - The second phase angle in radians
1927 ///
1928 /// # Returns
1929 ///
1930 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1931 ///
1932 /// # Errors
1933 ///
1934 /// * Returns an error if any index is out of bounds for the state vector.
1935 /// * Returns an error if target or control qubits overlap.
1936 pub fn matchgate(
1937 &self,
1938 target: usize,
1939 theta: f64,
1940 phi1: f64,
1941 phi2: f64,
1942 ) -> Result<State, Error> {
1943 Matchgate { theta, phi1, phi2 }.apply(self, &[target], &[])
1944 }
1945
1946 /// Applies the controlled Matchgate to the state vector
1947 ///
1948 /// # Arguments
1949 ///
1950 /// * `target` - The index of the first target qubit. The second target qubit is automatically determined to be the next qubit.
1951 /// * `theta` - The rotation angle in radians
1952 /// * `phi1` - The first phase angle in radians
1953 /// * `phi2` - The second phase angle in radians
1954 /// * `controls` - The indices of the control qubits
1955 ///
1956 /// # Returns
1957 ///
1958 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1959 ///
1960 /// # Errors
1961 ///
1962 /// * Returns an error if any index is out of bounds for the state vector.
1963 /// * Returns an error if target or control qubits overlap.
1964 pub fn cmatchgate(
1965 &self,
1966 target: usize,
1967 theta: f64,
1968 phi1: f64,
1969 phi2: f64,
1970 controls: &[usize],
1971 ) -> Result<State, Error> {
1972 Matchgate { theta, phi1, phi2 }.apply(self, &[target], controls)
1973 }
1974
1975 /// Applies the Toffoli (Controlled-Controlled-NOT) gate to the state vector.
1976 ///
1977 /// # Arguments
1978 ///
1979 /// * `control1` - The index of the first control qubit.
1980 /// * `control2` - The index of the second control qubit.
1981 /// * `target` - The index of the target qubit.
1982 ///
1983 /// # Returns
1984 ///
1985 /// * `Result` - A result containing the new state object if successful, or an error if the operation fails.
1986 ///
1987 /// # Errors
1988 ///
1989 /// * Returns an error if any index is out of bounds for the state vector.
1990 pub fn toffoli(&self, control1: usize, control2: usize, target: usize) -> Result<Self, Error> {
1991 Toffoli {}.apply(self, &[target], &[control1, control2])
1992 }
1993}
1994
1995impl PartialEq for State {
1996 fn eq(&self, other: &Self) -> bool {
1997 // Check if the number of qubits is the same
1998 if self.num_qubits != other.num_qubits {
1999 return false;
2000 }
2001
2002 // Check if the state vectors have the same length (should be redundant with num_qubits check)
2003 if self.state_vector.len() != other.state_vector.len() {
2004 return false;
2005 }
2006
2007 // Check if each element in the state vectors is approximately equal within epsilon
2008 for (a, b) in self.state_vector.iter().zip(other.state_vector.iter()) {
2009 let real_diff = (a.re - b.re).abs();
2010 let imag_diff = (a.im - b.im).abs();
2011
2012 if real_diff > f32::EPSILON.into() || imag_diff > f32::EPSILON.into() {
2013 return false;
2014 }
2015 }
2016
2017 true
2018 }
2019}
2020
2021/// A trait to enable chainable operations on Result<State, Error>
2022pub trait ChainableState {
2023 // -- SINGLE QUBIT GATES --
2024
2025 /// Applies the Hadamard gate to the specified qubit in the state vector.
2026 fn h(self, index: usize) -> Result<State, Error>;
2027
2028 /// Applies the Hadamard gate to the specified qubits in the state vector in the given order.
2029 fn h_multi(self, qubits: &[usize]) -> Result<State, Error>;
2030
2031 /// Applies the controlled Hadamard gate to the specified qubits in the state vector in the given order.
2032 fn ch_multi(self, target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2033
2034 /// Applies the Pauli-X (NOT) gate to the specified qubit in the state vector.
2035 fn x(self, index: usize) -> Result<State, Error>;
2036
2037 /// Applies the Pauli-X (NOT) gate to the specified qubits in the state vector in the given order.
2038 fn x_multi(self, qubits: &[usize]) -> Result<State, Error>;
2039
2040 /// Applies the controlled Pauli-X (NOT) gate to the specified qubits in the state vector in the given order.
2041 fn cx_multi(self, target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2042
2043 /// Applies the Pauli-Y gate to the specified qubit in the state vector.
2044 fn y(self, index: usize) -> Result<State, Error>;
2045
2046 /// Applies the Pauli-Y gate to the specified qubits in the state vector in the given order.
2047 fn y_multi(self, qubits: &[usize]) -> Result<State, Error>;
2048
2049 /// Applies the controlled Pauli-Y gate to the specified qubits in the state vector in the given order.
2050 fn cy_multi(self, target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2051
2052 /// Applies the Pauli-Z gate to the specified qubit in the state vector.
2053 fn z(self, index: usize) -> Result<State, Error>;
2054
2055 /// Applies the Pauli-Z gate to the specified qubits in the state vector in the given order.
2056 fn z_multi(self, qubits: &[usize]) -> Result<State, Error>;
2057
2058 /// Applies the controlled Pauli-Z gate to the specified qubits in the state vector in the given order.
2059 fn cz_multi(self, target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2060
2061 /// Applies the Identity gate to the state vector.
2062 fn i(self, qubit: usize) -> Result<State, Error>;
2063
2064 /// Applies the Identity gate to the state vector for multiple qubits in the given order.
2065 fn i_multi(self, qubits: &[usize]) -> Result<State, Error>;
2066
2067 /// Applies the controlled Identity gate to the state vector for multiple qubits in the given order.
2068 fn ci_multi(self, target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2069
2070 /// Applies the Phase S gate to the specified qubit in the state vector.
2071 fn s(self, index: usize) -> Result<State, Error>;
2072 /// Applies the Phase S gate to the specified qubits in the state vector in the given order.
2073 fn s_multi(self, qubits: &[usize]) -> Result<State, Error>;
2074
2075 /// Applies the controlled Phase S gate to the specified qubits in the state vector in the given order.
2076 fn cs_multi(self, target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2077
2078 /// Applies the Phase T gate to the specified qubit in the state vector.
2079 fn t(self, index: usize) -> Result<State, Error>;
2080 /// Applies the Phase T gate to the specified qubits in the state vector in the given order.
2081 fn t_multi(self, qubits: &[usize]) -> Result<State, Error>;
2082
2083 /// Applies the controlled Phase T gate to the specified qubits in the state vector in the given order.
2084 fn ct_multi(self, target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2085
2086 /// Applies the Phase S dagger gate to the specified qubit in the state vector.
2087 fn s_dag(self, index: usize) -> Result<State, Error>;
2088 /// Applies the Phase S dagger gate to the specified qubits in the state vector in the given order.
2089 fn s_dag_multi(self, qubits: &[usize]) -> Result<State, Error>;
2090
2091 /// Applies the controlled Phase S dagger gate to the specified qubits in the state vector in the given order.
2092 fn cs_dag_multi(
2093 self,
2094 target_qubits: &[usize],
2095 control_qubits: &[usize],
2096 ) -> Result<State, Error>;
2097
2098 /// Applies the Phase T dagger gate to the specified qubit in the state vector.
2099 fn t_dag(self, index: usize) -> Result<State, Error>;
2100 /// Applies the Phase T dagger gate to the specified qubits in the state vector in the given order.
2101 fn t_dag_multi(self, qubits: &[usize]) -> Result<State, Error>;
2102
2103 /// Applies the controlled Phase T dagger gate to the specified qubits in the state vector in the given order.
2104 fn ct_dag_multi(
2105 self,
2106 target_qubits: &[usize],
2107 control_qubits: &[usize],
2108 ) -> Result<State, Error>;
2109
2110 /// Applies the Phase Shift gate with the specified angle to the given qubit.
2111 fn p(self, index: usize, angle: f64) -> Result<State, Error>;
2112 /// Applies the Phase Shift gate with the specified angle to the given qubits in order.
2113 fn p_multi(self, qubits: &[usize], angle: f64) -> Result<State, Error>;
2114
2115 /// Applies the controlled Phase Shift gate with the specified angle to the given qubits in order.
2116 fn cp_multi(
2117 self,
2118 target_qubits: &[usize],
2119 control_qubits: &[usize],
2120 angle: f64,
2121 ) -> Result<State, Error>;
2122
2123 /// Applies the RotateX gate with the specified angle to the given qubit.
2124 fn rx(self, index: usize, angle: f64) -> Result<State, Error>;
2125 /// Applies the RotateX gate with the specified angle to the given qubits in order.
2126 fn rx_multi(self, qubits: &[usize], angle: f64) -> Result<State, Error>;
2127
2128 /// Applies the controlled RotateX gate with the specified angle to the given qubits in order.
2129 fn crx_multi(
2130 self,
2131 target_qubits: &[usize],
2132 control_qubits: &[usize],
2133 angle: f64,
2134 ) -> Result<State, Error>;
2135
2136 /// Applies the RotateY gate with the specified angle to the given qubit.
2137 fn ry(self, index: usize, angle: f64) -> Result<State, Error>;
2138 /// Applies the RotateY gate with the specified angle to the given qubits in order.
2139 fn ry_multi(self, qubits: &[usize], angle: f64) -> Result<State, Error>;
2140
2141 /// Applies the controlled RotateY gate with the specified angle to the given qubits in order.
2142 fn cry_multi(
2143 self,
2144 target_qubits: &[usize],
2145 control_qubits: &[usize],
2146 angle: f64,
2147 ) -> Result<State, Error>;
2148
2149 /// Applies the RotateZ gate with the specified angle to the given qubit.
2150 fn rz(self, index: usize, angle: f64) -> Result<State, Error>;
2151 /// Applies the RotateZ gate with the specified angle to the given qubits in order.
2152 fn rz_multi(self, qubits: &[usize], angle: f64) -> Result<State, Error>;
2153
2154 /// Applies the controlled RotateZ gate with the specified angle to the given qubits in order.
2155 fn crz_multi(
2156 self,
2157 target_qubits: &[usize],
2158 control_qubits: &[usize],
2159 angle: f64,
2160 ) -> Result<State, Error>;
2161
2162 /// Applies the unitary gate to the specified qubit in the state vector.
2163 fn unitary(self, index: usize, unitary: [[Complex<f64>; 2]; 2]) -> Result<State, Error>;
2164
2165 /// Applies the unitary gate to the specified qubits in the state vector in the given order.
2166 fn unitary_multi(
2167 self,
2168 qubits: &[usize],
2169 unitary: [[Complex<f64>; 2]; 2],
2170 ) -> Result<State, Error>;
2171
2172 /// Applies the controlled unitary gate to the specified qubits in the state vector in the given order.
2173 fn cunitary_multi(
2174 self,
2175 target_qubits: &[usize],
2176 control_qubits: &[usize],
2177 unitary: [[Complex<f64>; 2]; 2],
2178 ) -> Result<State, Error>;
2179
2180 /// Applies the Unitary (constructed from rotation angle and phase shift) to the specified qubit in the state vector.
2181 fn ry_phase(self, index: usize, angle: f64, phase: f64) -> Result<State, Error>;
2182 /// Applies the Unitary (constructed from rotation angle and phase shift) to the specified qubits in the state vector in the given order.
2183 fn ry_phase_multi(self, qubits: &[usize], angle: f64, phase: f64) -> Result<State, Error>;
2184 /// Applies the controlled Unitary (constructed from rotation angle and phase shift) to the specified qubits in the state vector in the given order.
2185 fn cry_phase_gates(
2186 self,
2187 target_qubits: &[usize],
2188 control_qubits: &[usize],
2189 angle: f64,
2190 phase: f64,
2191 ) -> Result<State, Error>;
2192
2193 // -- MULTI-QUBIT GATES --
2194
2195 /// Applies the CNOT (Controlled-NOT) gate to the state vector.
2196 fn cnot(self, control: usize, target: usize) -> Result<State, Error>;
2197
2198 /// Applies the SWAP gate to the state vector.
2199 fn swap(self, qubit1: usize, qubit2: usize) -> Result<State, Error>;
2200
2201 /// Applies the controlled SWAP gate to the state vector.
2202 fn cswap(self, target1: usize, target2: usize, controls: &[usize]) -> Result<State, Error>;
2203
2204 /// Applies the Toffoli (Controlled-Controlled-NOT) gate to the state vector.
2205 fn toffoli(self, control1: usize, control2: usize, target: usize) -> Result<State, Error>;
2206
2207 /// Applies the Matchgate to the state vector.
2208 fn matchgate(self, target: usize, theta: f64, phi1: f64, phi2: f64) -> Result<State, Error>;
2209
2210 /// Applies the controlled Matchgate to the state vector.
2211 fn cmatchgate(
2212 self,
2213 target: usize,
2214 theta: f64,
2215 phi1: f64,
2216 phi2: f64,
2217 controls: &[usize],
2218 ) -> Result<State, Error>;
2219
2220 /// Applies a unitary operation to the state vector.
2221 fn operate(
2222 self,
2223 unitary: impl Operator,
2224 target_qubits: &[usize],
2225 control_qubits: &[usize],
2226 ) -> Result<State, Error>;
2227
2228 // -- MEASUREMENT --
2229
2230 /// Measures the state vector in the specified basis and returns the measurement result.
2231 fn measure(
2232 self,
2233 basis: MeasurementBasis,
2234 measured_qubits: &[usize],
2235 ) -> Result<MeasurementResult, Error>;
2236
2237 /// Measures the state vector `n` times in the specified basis and returns the measurement results.
2238 fn measure_n(
2239 self,
2240 basis: MeasurementBasis,
2241 measured_qubits: &[usize],
2242 n: usize,
2243 ) -> Result<Vec<MeasurementResult>, Error>;
2244}
2245
2246macro_rules! impl_chainable_state {
2247 ($($method:ident($($arg:ident: $arg_type:ty),*) -> $return_type:ty);* $(;)?) => {
2248 impl ChainableState for Result<State, Error> {
2249 $(
2250 fn $method(self, $($arg: $arg_type),*) -> $return_type {
2251 self.and_then(|state| state.$method($($arg),*))
2252 }
2253 )*
2254 }
2255 };
2256}
2257
2258impl_chainable_state! {
2259 // -- SINGLE QUBIT GATES --
2260 h(index: usize) -> Result<State, Error>;
2261 h_multi(qubits: &[usize]) -> Result<State, Error>;
2262 ch_multi(target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2263 x(index: usize) -> Result<State, Error>;
2264 x_multi(qubits: &[usize]) -> Result<State, Error>;
2265 cx_multi(target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2266 y(index: usize) -> Result<State, Error>;
2267 y_multi(qubits: &[usize]) -> Result<State, Error>;
2268 cy_multi(target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2269 z(index: usize) -> Result<State, Error>;
2270 z_multi(qubits: &[usize]) -> Result<State, Error>;
2271 cz_multi(target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2272 i(qubit: usize) -> Result<State, Error>;
2273 i_multi(qubits: &[usize]) -> Result<State, Error>;
2274 ci_multi(target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2275 s(index: usize) -> Result<State, Error>;
2276 s_multi(qubits: &[usize]) -> Result<State, Error>;
2277 cs_multi(target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2278 t(index: usize) -> Result<State, Error>;
2279 t_multi(qubits: &[usize]) -> Result<State, Error>;
2280 ct_multi(target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2281 s_dag(index: usize) -> Result<State, Error>;
2282 s_dag_multi(qubits: &[usize]) -> Result<State, Error>;
2283 cs_dag_multi(target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2284 t_dag(index: usize) -> Result<State, Error>;
2285 t_dag_multi(qubits: &[usize]) -> Result<State, Error>;
2286 ct_dag_multi(target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2287 p(index: usize, angle: f64) -> Result<State, Error>;
2288 p_multi(qubits: &[usize], angle: f64) -> Result<State, Error>;
2289 cp_multi(target_qubits: &[usize], control_qubits: &[usize], angle: f64) -> Result<State, Error>;
2290 rx(index: usize, angle: f64) -> Result<State, Error>;
2291 rx_multi(qubits: &[usize], angle: f64) -> Result<State, Error>;
2292 crx_multi(target_qubits: &[usize], control_qubits: &[usize], angle: f64) -> Result<State, Error>;
2293 ry(index: usize, angle: f64) -> Result<State, Error>;
2294 ry_multi(qubits: &[usize], angle: f64) -> Result<State, Error>;
2295 cry_multi(target_qubits: &[usize], control_qubits: &[usize], angle: f64) -> Result<State, Error>;
2296 rz(index: usize, angle: f64) -> Result<State, Error>;
2297 rz_multi(qubits: &[usize], angle: f64) -> Result<State, Error>;
2298 crz_multi(target_qubits: &[usize], control_qubits: &[usize], angle: f64) -> Result<State, Error>;
2299 unitary(index: usize, unitary: [[Complex<f64>; 2]; 2]) -> Result<State, Error>;
2300 unitary_multi(qubits: &[usize], unitary: [[Complex<f64>; 2]; 2]) -> Result<State, Error>;
2301 cunitary_multi(target_qubits: &[usize], control_qubits: &[usize], unitary: [[Complex<f64>; 2]; 2]) -> Result<State, Error>;
2302 ry_phase(index: usize, angle: f64, phase: f64) -> Result<State, Error>;
2303 ry_phase_multi(qubits: &[usize], angle: f64, phase: f64) -> Result<State, Error>;
2304 cry_phase_gates(target_qubits: &[usize], control_qubits: &[usize], angle: f64, phase: f64) -> Result<State, Error>;
2305
2306 // -- MULTI-QUBIT GATES --
2307 cnot(control: usize, target: usize) -> Result<State, Error>;
2308 swap(qubit1: usize, qubit2: usize) -> Result<State, Error>;
2309 cswap(target1: usize, target2: usize, controls: &[usize]) -> Result<State, Error>;
2310 toffoli(control1: usize, control2: usize, target: usize) -> Result<State, Error>;
2311 matchgate(target: usize, theta: f64, phi1: f64, phi2: f64) -> Result<State, Error>;
2312 cmatchgate(target: usize, theta: f64, phi1: f64, phi2: f64, controls: &[usize]) -> Result<State, Error>;
2313 operate(unitary: impl Operator, target_qubits: &[usize], control_qubits: &[usize]) -> Result<State, Error>;
2314 measure(basis: MeasurementBasis, measured_qubits: &[usize]) -> Result<MeasurementResult, Error>;
2315 measure_n(basis: MeasurementBasis, measured_qubits: &[usize], n: usize) -> Result<Vec<MeasurementResult>, Error>;
2316}
2317
2318// Implement multiplication by Complex<f64>
2319impl Mul<Complex<f64>> for State {
2320 type Output = Self;
2321
2322 /// Multiplies each amplitude in the state vector by a complex scalar.
2323 /// Note: This operation typically results in an unnormalised state.
2324 fn mul(self, rhs: Complex<f64>) -> Self::Output {
2325 let new_state_vector: Vec<Complex<f64>> = self
2326 .state_vector
2327 .into_par_iter() // Use parallel iterator for potential performance gain
2328 .map(|amplitude| amplitude * rhs)
2329 .collect();
2330
2331 // Create a new State directly, bypassing the normalization check in `new`
2332 State {
2333 state_vector: new_state_vector,
2334 num_qubits: self.num_qubits,
2335 }
2336 }
2337}
2338
2339// Implement multiplication by f64
2340impl Mul<f64> for State {
2341 type Output = Self;
2342
2343 /// Multiplies each amplitude in the state vector by a real scalar.
2344 /// Note: This operation typically results in an unnormalised state.
2345 fn mul(self, rhs: f64) -> Self::Output {
2346 let complex_rhs = Complex::new(rhs, 0.0); // Convert f64 to Complex<f64>
2347 let new_state_vector: Vec<Complex<f64>> = self
2348 .state_vector
2349 .into_par_iter() // Use parallel iterator
2350 .map(|amplitude| amplitude * complex_rhs)
2351 .collect();
2352
2353 // Create a new State directly
2354 State {
2355 state_vector: new_state_vector,
2356 num_qubits: self.num_qubits,
2357 }
2358 }
2359}
2360
2361// Implement multiplication State = f64 * State
2362impl Mul<State> for f64 {
2363 type Output = State;
2364
2365 /// Multiplies each amplitude in the state vector by a real scalar from the left.
2366 /// Note: This operation typically results in an unnormalised state.
2367 fn mul(self, rhs: State) -> Self::Output {
2368 let complex_lhs = Complex::new(self, 0.0); // Convert f64 to Complex<f64>
2369 let new_state_vector: Vec<Complex<f64>> = rhs
2370 .state_vector
2371 .into_par_iter() // Use parallel iterator
2372 .map(|amplitude| complex_lhs * amplitude)
2373 .collect();
2374
2375 // Create a new State directly
2376 State {
2377 state_vector: new_state_vector,
2378 num_qubits: rhs.num_qubits,
2379 }
2380 }
2381}
2382
2383// Implement multiplication State = Complex<f64> * State
2384impl Mul<State> for Complex<f64> {
2385 type Output = State;
2386
2387 /// Multiplies each amplitude in the state vector by a complex scalar from the left.
2388 /// Note: This operation typically results in an unnormalised state.
2389 fn mul(self, rhs: State) -> Self::Output {
2390 let new_state_vector: Vec<Complex<f64>> = rhs
2391 .state_vector
2392 .into_par_iter() // Use parallel iterator
2393 .map(|amplitude| self * amplitude)
2394 .collect();
2395
2396 // Create a new State directly
2397 State {
2398 state_vector: new_state_vector,
2399 num_qubits: rhs.num_qubits,
2400 }
2401 }
2402}
2403
2404// Implement addition for State + State
2405impl Add<State> for State {
2406 type Output = Self;
2407
2408 /// Adds two state vectors element-wise.
2409 /// Panics if the states do not have the same number of qubits.
2410 /// Note: This operation typically results in an unnormalised state.
2411 fn add(self, rhs: State) -> Self::Output {
2412 if self.num_qubits != rhs.num_qubits {
2413 panic!(
2414 "Cannot add states with different numbers of qubits: {} != {}",
2415 self.num_qubits, rhs.num_qubits
2416 );
2417 }
2418
2419 let new_state_vector: Vec<Complex<f64>> = self
2420 .state_vector
2421 .into_par_iter()
2422 .zip(rhs.state_vector.into_par_iter())
2423 .map(|(a, b)| a + b)
2424 .collect();
2425
2426 // Create a new State directly
2427 State {
2428 state_vector: new_state_vector,
2429 num_qubits: self.num_qubits,
2430 }
2431 }
2432}
2433
2434// Implement sum for State
2435impl std::iter::Sum for State {
2436 fn sum<I>(mut iter: I) -> Self
2437 where
2438 I: Iterator<Item = Self>,
2439 {
2440 // Take the first state as the initial accumulator.
2441 let mut accumulator = match iter.next() {
2442 Some(first_state) => first_state,
2443 None => {
2444 panic!(
2445 "Cannot sum an empty iterator of State objects: num_qubits for the sum is undefined."
2446 );
2447 }
2448 };
2449
2450 // Fold the rest of the states into the accumulator.
2451 // The `Add` impl for `State` handles element-wise addition and
2452 // panics if `num_qubits` do not match.
2453 for state in iter {
2454 if accumulator.num_qubits != state.num_qubits {
2455 panic!(
2456 "Cannot sum states with different numbers of qubits: {} != {}",
2457 accumulator.num_qubits, state.num_qubits
2458 );
2459 }
2460 accumulator = accumulator + state; // Uses the implemented Add for State
2461 }
2462 accumulator
2463 }
2464}
2465
2466// Implement subtraction for State - State
2467impl Sub<State> for State {
2468 type Output = Self;
2469
2470 /// Subtracts the right-hand state vector from the left-hand state vector element-wise.
2471 /// Panics if the states do not have the same number of qubits.
2472 /// Note: This operation typically results in an unnormalised state.
2473 fn sub(self, rhs: State) -> Self::Output {
2474 if self.num_qubits != rhs.num_qubits {
2475 panic!(
2476 "Cannot subtract states with different numbers of qubits: {} != {}",
2477 self.num_qubits, rhs.num_qubits
2478 );
2479 }
2480
2481 let new_state_vector: Vec<Complex<f64>> = self
2482 .state_vector
2483 .into_par_iter()
2484 .zip(rhs.state_vector.into_par_iter())
2485 .map(|(a, b)| a - b)
2486 .collect();
2487
2488 // Create a new State directly
2489 State {
2490 state_vector: new_state_vector,
2491 num_qubits: self.num_qubits,
2492 }
2493 }
2494}
2495
2496impl std::fmt::Debug for State {
2497 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2498 let mut state_str = String::new();
2499 state_str.push_str(format!("State with {} qubits:\n[", self.num_qubits).as_str());
2500 for amplitude in &self.state_vector {
2501 let amplitude_string: String = if amplitude.im == 0.0 {
2502 format!("{:.2}", amplitude.re)
2503 } else if amplitude.re == 0.0 {
2504 format!("{:.2}i", amplitude.im)
2505 } else {
2506 format!("{:.2} + {:.2}i", amplitude.re, amplitude.im)
2507 };
2508 // Add the amplitude to the string representations
2509 state_str.push_str(format!("{}, ", amplitude_string).as_str());
2510 }
2511 state_str.pop(); // Remove the last comma
2512 state_str.pop(); // Remove the last space
2513 state_str.push(']');
2514 write!(f, "{}", state_str)
2515 }
2516}