LCOV - code coverage report
Current view: top level - src - circuit.rs (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 241 245 98.4 %
Date: 2021-11-09 13:25:48 Functions: 55 59 93.2 %

          Line data    Source code
       1             : // Copyright © 2021 HQS Quantum Simulations GmbH. All Rights Reserved.
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
       4             : // in compliance with the License. You may obtain a copy of the License at
       5             : //
       6             : //     http://www.apache.org/licenses/LICENSE-2.0
       7             : //
       8             : // Unless required by applicable law or agreed to in writing, software distributed under the
       9             : // License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
      10             : // express or implied. See the License for the specific language governing permissions and
      11             : // limitations under the License.
      12             : 
      13             : use crate::operations::{Define, InvolveQubits, InvolvedQubits, Operate, Operation, Substitute};
      14             : #[cfg(feature = "overrotate")]
      15             : use crate::operations::{Rotate, Rotation};
      16             : use crate::RoqoqoError;
      17             : use qoqo_calculator::Calculator;
      18             : #[cfg(feature = "overrotate")]
      19             : use std::convert::TryFrom;
      20             : use std::ops;
      21             : use std::{
      22             :     collections::{HashMap, HashSet},
      23             :     usize,
      24             : };
      25             : use std::{
      26             :     fmt::{Display, Formatter},
      27             :     iter::{FromIterator, IntoIterator},
      28             : };
      29             : 
      30             : /// Represents a quantum circuit in roqoqo.
      31             : ///
      32             : /// In roqoqo, single operations are collected in a circuit to build up a quantum program.
      33             : /// Roqoqo circuits are strictly linear sequences of operations.
      34             : /// The circuit struct behaves similar to a list and provides several standard
      35             : /// functions of a Vec<Operation>, such as len(), is_empty(), get(), iter() and into_iter().
      36             : ///
      37             : /// # Example
      38             : ///
      39             : /// ```
      40             : /// use roqoqo::Circuit;
      41             : /// use roqoqo::operations::{Operation, RotateX};
      42             : /// use qoqo_calculator::CalculatorFloat;
      43             : /// // creating circuit
      44             : /// let mut circuit = Circuit::new();
      45             : /// // adding operation to circuit
      46             : /// circuit.add_operation(RotateX::new(0,CalculatorFloat::from(0)));
      47             : /// assert_eq!(circuit.len(), 1);
      48             : /// // iterating over circuit I
      49             : /// let operation_vector: Vec<&Operation>= circuit.iter().collect();
      50             : /// // iterating over circuit II
      51             : /// for op in circuit{
      52             : ///    println!("{:?}", op);
      53             : /// }
      54             : /// // collecting operations into circuit
      55             : /// let vector = vec![Operation::from(RotateX::new(0,CalculatorFloat::from(0))), Operation::from(RotateX::new(0,CalculatorFloat::from(0)))];
      56             : /// let new_circuit: Circuit = vector.into_iter().collect();
      57             : /// ```
      58             : ///
      59             : /// Similarly to single Operations, Circuits can be translated to other frameworks via interfaces.
      60             : ///
      61             : /// For Circuits the following functions are defined:
      62             : /// * `new()`: creates an empty Circuit
      63             : /// * `add_operation(operation)`: adds the specified operation to the Circuit
      64             : /// * `get(index)`: returns the operation at the specified index in the Circuit
      65             : /// * `get_mut(index)`: returns mutable reference to the operation at the specified index in the Circuit
      66             : /// * `iter()`: creates an iterator of the Circuit
      67             : /// * `len()`: returns the length of the Circuit
      68             : /// * `is_empty()`: returns a boolean of whether the Circuit contains any definitions and operations or not
      69             : /// * `involved_qubits()`: returns the qubits invovlved in the whole Circuit
      70             : /// * `definitions()`: returns the definitions in the Circuit
      71             : /// * `operations()`: returns the operations in the Circuit
      72             : /// * `substitute_parameters(calculator)`: substitutes any symbolic parameters in (a copy of) the Circuit according to the specified Calculator
      73             : /// * `remap_qubits(mapping)`: remaps the qubits in (a copy of) the Circuit according to the specified mapping
      74             : /// * `count_occurences(operations)`: returns the number of operations in the Circuit with the specified operation tags
      75             : /// * `get_operation_types()`: returns a list of all of the operations in the Circuit (in hqslang)
      76             : /// * `from_iter(iterator)`: creates a Circuit from the items in the specified iterator
      77             : /// * `extend(iterator)`: adds the operations in the specified iterator to the Circuit
      78             : /// * `default()`: creates an empty Circuit
      79             : /// * `[...]`: gets a slice of the Circuit (returned as a vector)
      80             : /// * `+` and `+=`: add two circuits or an operation to the Circuit
      81             : ///
      82          79 : #[derive(Debug, Clone, PartialEq)]
      83             : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
      84             : pub struct Circuit {
      85             :     /// Definitions in the quantum circuit, must be unique.
      86             :     definitions: Vec<Operation>,
      87             :     /// Operations of the quantum circuit, do not have to be unique.
      88             :     operations: Vec<Operation>,
      89             : }
      90             : 
      91             : impl Circuit {
      92             :     /// Creates an empty quantum Circuit.
      93             :     ///
      94             :     /// # Returns
      95             :     ///
      96             :     /// * `Self` - The empty Circuit.
      97         266 :     pub fn new() -> Self {
      98         266 :         Circuit {
      99         266 :             definitions: Vec::new(),
     100         266 :             operations: Vec::new(),
     101         266 :         }
     102         266 :     }
     103             :     /// Adds an Operation to Circuit (self).
     104             :     ///
     105             :     /// # Arguments
     106             :     ///
     107             :     /// * `op` - The Operation to add to the Circuit.
     108         354 :     pub fn add_operation<T>(&mut self, op: T)
     109         354 :     where
     110         354 :         T: Into<Operation>,
     111         354 :     {
     112         354 :         let input: Operation = op.into();
     113         354 :         match &input {
     114           5 :             Operation::DefinitionBit(_) => self.definitions.push(input),
     115          10 :             Operation::DefinitionFloat(_) => {
     116          10 :                 self.definitions.push(input);
     117          10 :             }
     118           1 :             Operation::DefinitionComplex(_) => {
     119           1 :                 self.definitions.push(input);
     120           1 :             }
     121           1 :             Operation::DefinitionUsize(_) => {
     122           1 :                 self.definitions.push(input);
     123           1 :             }
     124           3 :             Operation::InputSymbolic(_) => {
     125           3 :                 self.definitions.push(input);
     126           3 :             }
     127         334 :             _ => self.operations.push(input),
     128             :         }
     129         354 :     }
     130             : 
     131             :     /// Returns a reference to the element at index similar to std::Vec get function.
     132             :     ///
     133             :     /// Contrary to std::Vec get function not implemented for slices  .
     134             :     ///
     135             :     /// # Arguments
     136             :     ///
     137             :     /// * `index` - The index of the Operation to get in the Circuit.
     138             :     ///
     139             :     /// # Returns
     140             :     ///
     141             :     /// * `Option<&Operation>` - The operation at the given index (if it exists).
     142          19 :     pub fn get(&self, index: usize) -> Option<&Operation> {
     143          19 :         let def_len = self.definitions.len();
     144          19 :         if index >= self.definitions.len() {
     145          11 :             self.operations.get(index - def_len)
     146             :         } else {
     147           8 :             self.definitions.get(index)
     148             :         }
     149          19 :     }
     150             : 
     151             :     /// Returns a mutable reference to the element at index similar to std::Vec get function.
     152             :     ///
     153             :     /// Contrary to std::Vec get function not implemented for slices.
     154             :     ///
     155             :     /// # Arguments
     156             :     ///
     157             :     /// * `index` - The index of the Operation to get in the Circuit.
     158             :     ///
     159             :     /// # Returns
     160             :     ///
     161             :     /// * `Option<mut &Operation>` - A mutable reference to the operation at the given index (if it exists).
     162           2 :     pub fn get_mut(&mut self, index: usize) -> Option<&mut Operation> {
     163           2 :         let def_len = self.definitions.len();
     164           2 :         if index >= self.definitions.len() {
     165           1 :             self.operations.get_mut(index - def_len)
     166             :         } else {
     167           1 :             self.definitions.get_mut(index)
     168             :         }
     169           2 :     }
     170             : 
     171             :     /// Creates an iterator of the Circuit.
     172             :     ///
     173             :     /// # Returns
     174             :     ///
     175             :     /// `Iterator<Item = &Operation>` - The Circuit in iterator form.
     176          20 :     pub fn iter(&self) -> impl Iterator<Item = &Operation> {
     177          20 :         self.definitions.iter().chain(self.operations.iter())
     178          20 :     }
     179             : 
     180             :     /// Returns true if the Circuit contains symbolic variables.
     181             :     ///
     182             :     /// # Returns
     183             :     ///
     184             :     /// * `bool` - True if the Circuit contains symbolic values, false if it does not.
     185           4 :     pub fn is_parametrized(&self) -> bool {
     186           4 :         self.operations.iter().any(|o| o.is_parametrized())
     187           3 :             || self.definitions.iter().any(|o| o.is_parametrized())
     188           4 :     }
     189             : 
     190             :     /// Returns the length of the Circuit.
     191             :     ///
     192             :     /// # Returns
     193             :     ///
     194             :     /// * `usize` - The length of the Circuit.
     195           4 :     pub fn len(&self) -> usize {
     196           4 :         self.definitions.len() + self.operations.len()
     197           4 :     }
     198             : 
     199             :     /// Returns true if the Circuit does not contain any operations and definitions.
     200             :     ///
     201             :     /// # Returns
     202             :     ///
     203             :     /// * `bool` - True if the Circuit is empty, false if it is not.
     204           3 :     pub fn is_empty(&self) -> bool {
     205           3 :         self.definitions.is_empty() && self.operations.is_empty()
     206           3 :     }
     207             : 
     208             :     /// Returns qubits the Circuit acts on.
     209             :     ///
     210             :     /// # Returns
     211             :     ///
     212             :     /// * `InvolvedQubits` - The qubits involved in the Circuit.
     213           5 :     pub fn involved_qubits(&self) -> InvolvedQubits {
     214           5 :         let mut temp_involved: HashSet<usize> = HashSet::new();
     215           5 :         for op in self.operations.iter() {
     216           5 :             match &op.involved_qubits() {
     217             :                 InvolvedQubits::All => {
     218           1 :                     return InvolvedQubits::All;
     219             :                 }
     220           1 :                 InvolvedQubits::None => (),
     221           3 :                 InvolvedQubits::Set(x) => temp_involved = temp_involved.union(x).cloned().collect(),
     222             :             }
     223             :         }
     224           4 :         match temp_involved.is_empty() {
     225           1 :             true => InvolvedQubits::None,
     226           3 :             false => InvolvedQubits::Set(temp_involved),
     227             :         }
     228           5 :     }
     229             : 
     230             :     /// Returns reference to the vector of definitions in Circuit.
     231             :     ///
     232             :     /// Definitions need to be unique.
     233             :     ///
     234             :     /// # Returns
     235             :     ///
     236             :     /// * `&Vec<Operation>` - A vector of the definitions in the Circuit.
     237           2 :     pub fn definitions(&self) -> &Vec<Operation> {
     238           2 :         &self.definitions
     239           2 :     }
     240             : 
     241             :     /// Returns reference to the vector of quantum operations in Circuit.
     242             :     ///
     243             :     /// Operations do not need to be unique.
     244             :     ///
     245             :     /// # Returns
     246             :     ///
     247             :     /// * `&Vec<Operation>` - A vector of the operations in the Circuit.
     248          25 :     pub fn operations(&self) -> &Vec<Operation> {
     249          25 :         &self.operations
     250          25 :     }
     251             : 
     252             :     /// Substitutes the symbolic parameters in a clone of Circuit according to the calculator input.
     253             :     ///
     254             :     /// # Arguments
     255             :     ///
     256             :     /// * ``calculator` - The Calculator containing the substitutions to use in the Circuit.
     257             :     ///
     258             :     /// # Returns
     259             :     ///
     260             :     /// * `Ok(Self)` -  The Circuit with the parameters substituted.
     261             :     /// * `Err(RoqoqoError)` - The subsitution failed.
     262          24 :     pub fn substitute_parameters(&self, calculator: &mut Calculator) -> Result<Self, RoqoqoError> {
     263          24 :         let mut tmp_def: Vec<Operation> = Vec::new();
     264           1 :         for def in self.definitions.iter() {
     265           1 :             let tmp_op = def.substitute_parameters(calculator)?;
     266           1 :             if let Operation::InputSymbolic(x) = &tmp_op {
     267           1 :                 calculator.set_variable(x.name(), *x.input())
     268           0 :             }
     269           1 :             tmp_def.push(tmp_op);
     270             :         }
     271          24 :         let mut tmp_op: Vec<Operation> = Vec::new();
     272          22 :         for op in self.operations.iter() {
     273          22 :             tmp_op.push(op.substitute_parameters(calculator)?);
     274             :         }
     275          20 :         Ok(Self {
     276          20 :             definitions: tmp_def,
     277          20 :             operations: tmp_op,
     278          20 :         })
     279          24 :     }
     280             :     /// Remaps the qubits in operations in clone of Circuit.
     281             :     ///
     282             :     /// # Arguments
     283             :     ///
     284             :     /// * ``mapping` - The HashMap containing the {qubit: qubit} mapping to use in the Circuit.
     285             :     ///
     286             :     /// # Returns
     287             :     ///
     288             :     /// * `Ok(Self)` -  The Circuit with the qubits remapped.
     289             :     /// * `Err(RoqoqoError)` - The remapping failed.
     290           8 :     pub fn remap_qubits(&self, mapping: &HashMap<usize, usize>) -> Result<Self, RoqoqoError> {
     291           8 :         let mut tmp_op: Vec<Operation> = Vec::new();
     292           6 :         for op in self.operations.iter() {
     293           6 :             tmp_op.push(op.remap_qubits(mapping)?);
     294             :         }
     295           8 :         Ok(Self {
     296           8 :             definitions: self.definitions.clone(),
     297           8 :             operations: tmp_op,
     298           8 :         })
     299           8 :     }
     300             : 
     301             :     /// Counts the number of occurences of a set of operation tags in the circuit.
     302             :     ///
     303             :     /// # Arguments
     304             :     ///
     305             :     /// `operations` - The list of operation tags that should be counted.
     306             :     ///
     307             :     /// # Returns
     308             :     ///
     309             :     /// * `usize` - The number of occurences of these operation tags.
     310           4 :     pub fn count_occurences(&self, operations: &[&str]) -> usize {
     311           4 :         let mut counter: usize = 0;
     312          24 :         for op in self.iter() {
     313          24 :             if operations.iter().any(|x| op.tags().contains(x)) {
     314          12 :                 counter += 1
     315          12 :             }
     316             :         }
     317           4 :         counter
     318           4 :     }
     319             : 
     320             :     /// Returns a list of the hqslang names of all operations occuring in the circuit.
     321             :     ///
     322             :     /// # Returns
     323             :     ///
     324             :     /// * `HashSet<&str>` - The operation types in the Circuit.
     325           2 :     pub fn get_operation_types(&self) -> HashSet<&str> {
     326           2 :         let mut operations: HashSet<&str> = HashSet::new();
     327          11 :         for op in self.iter() {
     328          11 :             let _ = operations.insert(op.hqslang());
     329          11 :         }
     330           2 :         operations
     331           2 :     }
     332             : 
     333             :     /// Returns clone of the circuit with all Overrotation Pragmas applied.
     334             :     ///
     335             :     /// # Returns
     336             :     ///
     337             :     /// * `Ok(Circuit)` - The Circuit with overrotations applied.
     338             :     /// * `Err(RoqoqoError::OverrotationError)` - Applying overrotations failed.
     339             :     ///
     340             :     /// # Example
     341             :     ///
     342             :     /// ```
     343             :     /// use roqoqo::Circuit;
     344             :     /// use roqoqo::operations::{PragmaOverrotation, RotateX, RotateY};
     345             :     /// let mut circuit = Circuit::new();
     346             :     /// // Adding Overrotation of next RotateY operation acting on qubit 1
     347             :     /// // overrotating parameter theta with a statistical value
     348             :     /// // value is drawn from normal distribution with standard deviation 30.0
     349             :     /// // and multiplied by amplitude 20.0
     350             :     /// circuit += PragmaOverrotation::new("RotateY".to_string(), vec![1], 20.0, 30.0);
     351             :     /// circuit += RotateX::new(0, 0.0.into());
     352             :     /// circuit += RotateY::new(0, 1.0.into());
     353             :     /// circuit += RotateY::new(1, 2.0.into());
     354             :     /// circuit += RotateY::new(1, 3.0.into());
     355             :     ///
     356             :     /// let circuit_overrotated = circuit.overrotate().unwrap();
     357             :     ///
     358             :     /// println!("{}", circuit);
     359             :     /// println!("{}", circuit_overrotated);
     360             :     /// ```
     361             :     ///
     362             :     #[cfg(feature = "overrotate")]
     363             :     pub fn overrotate(&self) -> Result<Self, RoqoqoError> {
     364             :         let mut tmp_vec = self.operations.clone();
     365             :         let mut return_circuit = Circuit {
     366             :             definitions: self.definitions.clone(),
     367             :             operations: Vec::new(),
     368             :         };
     369             :         let mut length = tmp_vec.len();
     370             :         while length > 0 {
     371             :             match tmp_vec
     372             :                 .iter()
     373             :                 .enumerate()
     374             :                 .find(|(_, op)| op.hqslang() == "PragmaOverrotation")
     375             :                 .map(|(i, op)| (i, op.clone()))
     376             :             {
     377             :                 Some((index, Operation::PragmaOverrotation(overrotation))) => {
     378             :                     // for op in tmp_vec[..index].iter() {
     379             :                     //     return_circuit.operations.push(op.clone())
     380             :                     // }
     381             :                     let hqslang = overrotation.gate_hqslang();
     382             :                     match tmp_vec[index..].iter().enumerate().find(|(_, op)| {
     383             :                         hqslang == op.hqslang()
     384             :                             && overrotation.involved_qubits() == op.involved_qubits()
     385             :                     }) {
     386             :                         Some((ind, _)) => {
     387             :                             let mut tmp_tmp_vec: Vec<Operation> = Vec::new();
     388             :                             for (mov_ind, op) in tmp_vec.into_iter().enumerate() {
     389             :                                 if mov_ind == index + ind {
     390             :                                     println!("index: {}. op: {:?}", mov_ind, op.clone());
     391             :                                     tmp_tmp_vec.push(
     392             :                                         Rotation::try_from(op)?
     393             :                                             .overrotate(
     394             :                                                 overrotation.amplitude(),
     395             :                                                 overrotation.variance(),
     396             :                                             )
     397             :                                             .into(),
     398             :                                     )
     399             :                                 } else if index != mov_ind {
     400             :                                     tmp_tmp_vec.push(op)
     401             :                                 }
     402             :                             }
     403             :                             tmp_vec = tmp_tmp_vec
     404             :                         }
     405             :                         None => {
     406             :                             let mut tmp_tmp_vec: Vec<Operation> = Vec::new();
     407             :                             for (mov_ind, op) in tmp_vec.into_iter().enumerate() {
     408             :                                 if index != mov_ind {
     409             :                                     tmp_tmp_vec.push(op)
     410             :                                 }
     411             :                             }
     412             :                             tmp_vec = tmp_tmp_vec
     413             :                         }
     414             :                     }
     415             :                 }
     416             :                 _ => {
     417             :                     for op in tmp_vec {
     418             :                         return_circuit.operations.push(op)
     419             :                     }
     420             :                     tmp_vec = Vec::new();
     421             :                 }
     422             :             }
     423             :             length = tmp_vec.len();
     424             :         }
     425             :         Ok(return_circuit)
     426             :     }
     427             : }
     428             : 
     429             : /// Implements Index Access for Circuit.
     430             : ///
     431             : /// # Panics
     432             : ///
     433             : /// Panics when index is out of range of operations in circuit.
     434             : /// This is consistent with standard Vec behaviour
     435             : /// and returning Option or Result enums instead would conflict with definition of Output type.
     436             : impl ops::Index<usize> for Circuit {
     437             :     type Output = Operation;
     438             : 
     439             :     /// Returns reference to Operation at index.
     440             :     ///
     441             :     /// # Arguments
     442             :     ///
     443             :     /// * `index` - The index of the operation.
     444             :     ///
     445             :     /// # Panics
     446             :     ///
     447             :     /// Panics when index is out of range of operations in circuit.
     448           4 :     fn index(&self, index: usize) -> &Self::Output {
     449           4 :         let def_len = self.definitions.len();
     450           4 :         if index >= def_len {
     451           2 :             &self.operations[index - def_len]
     452             :         } else {
     453           2 :             &self.definitions[index]
     454             :         }
     455           4 :     }
     456             : }
     457             : 
     458             : impl ops::IndexMut<usize> for Circuit {
     459             :     /// Returns reference to Operation at index.
     460             :     ///
     461             :     /// # Arguments
     462             :     ///
     463             :     /// * `index` - The index of the operation.
     464             :     ///
     465             :     /// # Panics
     466             :     ///
     467             :     /// Panics when index is out of range of operations in circuit.
     468           2 :     fn index_mut(&mut self, index: usize) -> &mut Self::Output {
     469           2 :         let def_len = self.definitions.len();
     470           2 :         if index >= def_len {
     471           1 :             &mut self.operations[index - def_len]
     472             :         } else {
     473           1 :             &mut self.definitions[index]
     474             :         }
     475           2 :     }
     476             : }
     477             : 
     478             : impl IntoIterator for Circuit {
     479             :     type Item = Operation;
     480             :     type IntoIter = OperationIterator;
     481             :     /// Returns the Circuit in Iterator form.
     482             :     ///
     483             :     /// # Returns
     484             :     ///
     485             :     /// * `Self::IntoIter` - The Circuit in Iterator form.
     486           2 :     fn into_iter(self) -> Self::IntoIter {
     487           2 :         Self::IntoIter {
     488           2 :             definition_iter: self.definitions.into_iter(),
     489           2 :             operation_iter: self.operations.into_iter(),
     490           2 :         }
     491           2 :     }
     492             : }
     493             : 
     494             : impl<T> FromIterator<T> for Circuit
     495             : where
     496             :     T: Into<Operation>,
     497             : {
     498             :     /// Returns the circuit in Circuit form, from an Iterator form of the circuit.
     499             :     ///
     500             :     /// # Returns
     501             :     ///
     502             :     /// * `Self::IntoIter` - The Circuit in Circuit form.
     503           1 :     fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
     504           1 :         let mut circuit = Circuit::new();
     505           2 :         for op in iter {
     506           2 :             circuit.add_operation(op.into());
     507           2 :         }
     508           1 :         circuit
     509           1 :     }
     510             : }
     511             : 
     512             : impl<T> Extend<T> for Circuit
     513             : where
     514             :     T: Into<Operation>,
     515             : {
     516             :     /// Extends the Circuit by the specified operations (in Iterator form).
     517             :     ///
     518             :     /// # Arguments
     519             :     ///
     520             :     /// * `iter` - The iterator containing the operations by which to extend the Circuit.
     521           1 :     fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
     522           2 :         for op in iter {
     523           2 :             self.add_operation(op.into());
     524           2 :         }
     525           1 :     }
     526             : }
     527             : 
     528             : impl Default for Circuit {
     529             :     /// Creates a default implementation of the Circuit, which is an empty Circuit.
     530             :     ///
     531             :     /// # Returns
     532             :     ///
     533             :     /// * `Self` - The default Circuit (empty).
     534          14 :     fn default() -> Self {
     535          14 :         Self::new()
     536          14 :     }
     537             : }
     538             : 
     539             : /// Trait for returning Vectors based on Range structs usually used for Index<> trait and slice access.
     540             : ///
     541             : /// Required because Circuit does not have a continuous internal vector representation of the values.
     542             : /// Returns a Vec instead of slices.
     543             : ///
     544             : /// # Example
     545             : ///
     546             : /// ```
     547             : /// use roqoqo::{Circuit, AsVec};
     548             : /// use roqoqo::operations::{DefinitionFloat, Operation, RotateZ};
     549             : /// use qoqo_calculator::CalculatorFloat;
     550             : ///
     551             : /// let mut circuit = Circuit::new();
     552             : /// let definition = DefinitionFloat::new(String::from("ro"), 1, false);
     553             : /// let rotatez0 = RotateZ::new(0, CalculatorFloat::from(0.0));
     554             : /// circuit.add_operation(definition.clone());
     555             : /// circuit.add_operation(rotatez0.clone());
     556             : ///
     557             : /// let vec_ops = vec![
     558             : ///     Operation::from(definition.clone()),
     559             : ///     Operation::from(rotatez0.clone()),
     560             : /// ];
     561             : ///
     562             : /// assert_eq!(circuit.as_vec(0..1).clone(), Some(vec![vec_ops[0].clone()])); // Range
     563             : /// assert_eq!(circuit.as_vec(0..).clone(), Some(vec_ops.clone())); // RangeTo
     564             : /// assert_eq!(circuit.as_vec(..1).clone(), Some(vec![vec_ops[0].clone()])); // RangeFrom
     565             : /// ```
     566             : ///
     567             : pub trait AsVec<T> {
     568             :     /// Returns slice of Circuit as Vec<Operations>.
     569             :     ///
     570             :     /// # Arguments
     571             :     ///
     572             :     /// * `range` - The indices of the slice of the Circuit to be returned.
     573             :     ///
     574             :     /// # Returns
     575             :     ///
     576             :     /// * `Option<Vec<Operation>>` - A vector of the operations in the Circuit with the specified indices.
     577             :     fn as_vec(&self, range: T) -> Option<Vec<Operation>>;
     578             : }
     579             : 
     580             : impl AsVec<std::ops::Range<usize>> for Circuit {
     581             :     /// Returns slice of Circuit as Vec<Operations>.
     582             :     ///
     583             :     /// # Arguments
     584             :     ///
     585             :     /// * `range` - The indices of the slice of the Circuit to be returned.
     586             :     ///
     587             :     /// # Returns
     588             :     ///
     589             :     /// * `Option<Vec<Operation>>` - A vector of the operations in the Circuit with the specified indices.
     590           4 :     fn as_vec(&self, range: std::ops::Range<usize>) -> Option<Vec<Operation>> {
     591           4 :         let mut return_vec: Vec<Operation>;
     592           4 :         let def_len = self.definitions.len();
     593           4 :         if range.end - def_len >= self.operations.len() {
     594           1 :             return None;
     595           3 :         }
     596           3 :         if range.start < def_len {
     597           2 :             if range.end < def_len {
     598           0 :                 return_vec = self.definitions[range].to_vec();
     599           2 :             } else {
     600           2 :                 return_vec = self.definitions[range.start..].to_vec();
     601           2 :                 let mut tmp_vec = self.operations[..range.end - def_len].to_vec();
     602           2 :                 return_vec.append(&mut tmp_vec);
     603           2 :             }
     604           1 :         } else {
     605           1 :             return_vec = self.operations[range.start - def_len..range.end - def_len].to_vec();
     606           1 :         }
     607           3 :         Some(return_vec)
     608           4 :     }
     609             : }
     610             : 
     611             : impl AsVec<std::ops::RangeTo<usize>> for Circuit {
     612             :     /// Returns slice of Circuit as Vec<Operations>.
     613             :     ///
     614             :     /// # Arguments
     615             :     ///
     616             :     /// * `range` - The indices of the slice of the Circuit to be returned.
     617             :     ///
     618             :     /// # Returns
     619             :     ///
     620             :     /// * `Option<Vec<Operation>>` - A vector of the operations in the Circuit with the specified indices.
     621           3 :     fn as_vec(&self, range: std::ops::RangeTo<usize>) -> Option<Vec<Operation>> {
     622           3 :         let mut return_vec: Vec<Operation>;
     623           3 :         let def_len = self.definitions.len();
     624           3 :         if range.end - def_len >= self.operations.len() {
     625           1 :             return None;
     626           2 :         }
     627           2 :         if range.end < def_len {
     628           0 :             return_vec = self.definitions[range].to_vec();
     629           2 :         } else {
     630           2 :             return_vec = self.definitions.clone();
     631           2 :             let mut tmp_vec = self.operations[..range.end - def_len].to_vec();
     632           2 :             return_vec.append(&mut tmp_vec);
     633           2 :         }
     634           2 :         Some(return_vec)
     635           3 :     }
     636             : }
     637             : 
     638             : impl AsVec<std::ops::RangeFrom<usize>> for Circuit {
     639             :     /// Returns slice of Circuit as Vec<Operations>.
     640             :     ///
     641             :     /// # Arguments
     642             :     ///
     643             :     /// * `range` - The indices of the slice of the Circuit to be returned.
     644             :     ///
     645             :     /// # Returns
     646             :     ///
     647             :     /// * `Option<Vec<Operation>>` - A vector of the operations in the Circuit with the specified indices.
     648           2 :     fn as_vec(&self, range: std::ops::RangeFrom<usize>) -> Option<Vec<Operation>> {
     649           2 :         let mut return_vec: Vec<Operation>;
     650           2 :         let def_len = self.definitions.len();
     651           2 :         if range.start < def_len {
     652           1 :             return_vec = self.definitions[range.start..].to_vec();
     653           1 :             let mut tmp_vec = self.operations.clone();
     654           1 :             return_vec.append(&mut tmp_vec);
     655           1 :         } else {
     656           1 :             return_vec = self.operations[range.start - def_len..].to_vec();
     657           1 :         }
     658           2 :         Some(return_vec)
     659           2 :     }
     660             : }
     661             : 
     662             : /// Implements `+` (add) for Circuit and generic type `T`.
     663             : ///
     664             : /// # Arguments
     665             : ///
     666             : /// * `other` - Any type T that implements Into<Operation> trait.
     667             : impl<T> ops::Add<T> for Circuit
     668             : where
     669             :     T: Into<Operation>,
     670             : {
     671             :     type Output = Self;
     672           1 :     fn add(self, other: T) -> Self {
     673           1 :         let mut return_circuit = self;
     674           1 :         return_circuit.add_operation(other);
     675           1 :         return_circuit
     676           1 :     }
     677             : }
     678             : 
     679             : /// Implements `+` (add) for two Circuits.
     680             : ///
     681             : /// # Arguments
     682             : ///
     683             : /// * `other` - The Circuit to be added.
     684             : impl ops::Add<Circuit> for Circuit {
     685             :     type Output = Self;
     686           1 :     fn add(self, other: Circuit) -> Self {
     687           1 :         Self {
     688           1 :             definitions: self
     689           1 :                 .definitions
     690           1 :                 .into_iter()
     691           1 :                 .chain(other.definitions.into_iter())
     692           1 :                 .collect(),
     693           1 :             operations: self
     694           1 :                 .operations
     695           1 :                 .into_iter()
     696           1 :                 .chain(other.operations.into_iter())
     697           1 :                 .collect(),
     698           1 :         }
     699           1 :     }
     700             : }
     701             : 
     702             : /// Implements `+` (add) for Circuit and Circuit reference.
     703             : ///
     704             : /// # Arguments
     705             : ///
     706             : /// * `other` - The Circuit reference to be added.
     707             : impl ops::Add<&Circuit> for Circuit {
     708             :     type Output = Self;
     709           1 :     fn add(self, other: &Circuit) -> Self {
     710           1 :         Self {
     711           1 :             definitions: self
     712           1 :                 .definitions
     713           1 :                 .into_iter()
     714           1 :                 .chain(other.definitions.iter().cloned())
     715           1 :                 .collect(),
     716           1 :             operations: self
     717           1 :                 .operations
     718           1 :                 .into_iter()
     719           1 :                 .chain(other.operations.iter().cloned())
     720           1 :                 .collect(),
     721           1 :         }
     722           1 :     }
     723             : }
     724             : 
     725             : /// Implements `+=` (add) for Circuit and generic type `T`.
     726             : ///
     727             : /// # Arguments
     728             : ///
     729             : /// * `other` - Any type T that implements Into<Operation> trait.
     730             : impl<T> ops::AddAssign<T> for Circuit
     731             : where
     732             :     T: Into<Operation>,
     733             : {
     734         260 :     fn add_assign(&mut self, other: T) {
     735         260 :         self.add_operation(other);
     736         260 :     }
     737             : }
     738             : 
     739             : /// Implements `+=` (add) for two Circuits.
     740             : ///
     741             : /// # Arguments
     742             : ///
     743             : /// * `other` - The Circuit to be appended.
     744             : impl ops::AddAssign<Circuit> for Circuit {
     745           1 :     fn add_assign(&mut self, other: Circuit) {
     746           1 :         self.definitions.extend(other.definitions.into_iter());
     747           1 :         self.operations.extend(other.operations.into_iter())
     748           1 :     }
     749             : }
     750             : 
     751             : /// Implements `+=` (add) for Circuits and Circuit reference.
     752             : ///
     753             : /// # Arguments
     754             : ///
     755             : /// * `other` - The Circuit to be appended.
     756             : impl ops::AddAssign<&Circuit> for Circuit {
     757           1 :     fn add_assign(&mut self, other: &Circuit) {
     758           1 :         self.definitions.extend(other.definitions.iter().cloned());
     759           1 :         self.operations.extend(other.operations.iter().cloned())
     760           1 :     }
     761             : }
     762             : 
     763             : /// Implements the Display trait for Circuit.
     764             : impl Display for Circuit {
     765           1 :     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
     766           1 :         let mut s: String = String::new();
     767           2 :         for op in self.iter() {
     768           2 :             s.push_str(&format!("{:?}\n", op))
     769             :         }
     770           1 :         write!(f, "{}", s)
     771           1 :     }
     772             : }
     773             : 
     774             : /// Iterator over roqoqo operations.
     775           4 : #[derive(Debug, Clone)]
     776             : pub struct OperationIterator {
     777             :     /// Definitions in the quantum circuit in Iterator form, must be unique.
     778             :     definition_iter: std::vec::IntoIter<Operation>,
     779             :     /// Operations in the quantum circuit in Iterator form, must not be unique.
     780             :     operation_iter: std::vec::IntoIter<Operation>,
     781             : }
     782             : 
     783             : impl Iterator for OperationIterator {
     784             :     type Item = Operation;
     785             :     /// Advances the iterator and returns the next value.
     786             :     ///
     787             :     /// Returns None when iteration is finished. Individual iterator implementations may choose to resume iteration,
     788             :     /// and so calling next() again may or may not eventually start returning Some(Operation) again at some point.
     789             :     ///
     790             :     /// # Returns
     791             :     ///
     792             :     /// * `Option<Self::Item>` - The Operation that is next in the Iterator.
     793          12 :     fn next(&mut self) -> Option<Self::Item> {
     794          12 :         match self.definition_iter.next() {
     795           0 :             Some(x) => Some(x),
     796          12 :             None => self.operation_iter.next(),
     797             :         }
     798          12 :     }
     799             : }

Generated by: LCOV version 1.13