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 : }
|