pub struct BasicBlock {
pub gates: Vec<GateInstruction>,
pub qubits_op: BTreeMap<usize, QubitOp>,
pub global: Option<f64>,
}Expand description
A straight-line sequence of quantum gate instructions.
A BasicBlock is created empty and gates are appended one at a time via
BasicBlock::append_gate or in bulk via BasicBlock::append_block.
Each append operation attempts lightweight algebraic simplifications:
adjacent inverse gate pairs are cancelled and consecutive same-axis
rotation gates are merged into one.
The block also maintains a dependency index (qubits_op) consumed by the
qubit-allocation and circuit-mapping passes.
Fields§
§gates: Vec<GateInstruction>The ordered list of gate instructions in this block.
qubits_op: BTreeMap<usize, QubitOp>Per-qubit dependency records (propriety and read-control sets).
global: Option<f64>Accumulated global phase (in radians), or None if no global phase
has been added to this block.
Implementations§
Source§impl BasicBlock
impl BasicBlock
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new, empty BasicBlock.
Examples found in repository?
18fn qft(qubits: &[usize], do_swap: bool) -> Result<BasicBlock, KetError> {
19 let mut quantum_code = BasicBlock::new();
20 if qubits.len() == 1 {
21 quantum_code.append_gate(QuantumGate::Hadamard, qubits[0]);
22 return Ok(quantum_code);
23 }
24
25 let init = &qubits[..qubits.len() - 1];
26 let last = qubits[qubits.len() - 1];
27 quantum_code.append_gate(QuantumGate::Hadamard, last);
28 for (i, c) in init.iter().enumerate() {
29 quantum_code.append_block(
30 controlled_gate(
31 QuantumGate::Phase(Param::Value(PI / 2.0_f64.powi(i as i32 + 1))),
32 &[*c],
33 last,
34 )?,
35 None,
36 );
37 }
38 quantum_code.append_block(qft(init, false)?, None);
39
40 if do_swap {
41 for i in 0..qubits.len() / 2 {
42 quantum_code.append_block(swap_gate(qubits[i], qubits[qubits.len() - i - 1])?, None);
43 }
44 }
45
46 Ok(quantum_code)
47}More examples
14fn main() -> Result<(), KetError> {
15 let num_qubits = 3;
16
17 let mut process = Process::new(QPUConfig {
18 num_qubits,
19 quantum_execution: None,
20 });
21
22 let qubits: Result<Vec<_>, _> = (0..num_qubits).map(|_| process.alloc()).collect();
23 let qubits = qubits?;
24
25 let mut quantum_code = BasicBlock::new();
26
27 for target in &qubits {
28 quantum_code.append_gate(QuantumGate::Hadamard, *target);
29 }
30
31 process.append_block(quantum_code)?;
32
33 let steps = ((FRAC_PI_4) * f64::sqrt((1 << num_qubits) as f64)) as i64;
34
35 for _ in 0..steps {
36 process.append_block(compute_action_uncompute_gate(
37 |mut compute| {
38 for target in &qubits {
39 compute.append_gate(QuantumGate::PauliX, *target);
40 }
41 Ok(compute)
42 },
43 |mut action| {
44 action.append_gate(QuantumGate::PauliZ, qubits[0]);
45 Ok(action.control(&qubits[1..])?)
46 },
47 )?)?;
48
49 process.append_block(compute_action_uncompute_gate(
50 |mut compute| {
51 for target in &qubits {
52 compute.append_gate(QuantumGate::Hadamard, *target);
53 compute.append_gate(QuantumGate::PauliX, *target);
54 }
55 Ok(compute)
56 },
57 |mut action| {
58 action.append_gate(QuantumGate::PauliZ, qubits[0]);
59 Ok(action.control(&qubits[1..])?)
60 },
61 )?)?;
62 }
63
64 println!("{:#?}", process);
65
66 Ok(())
67}Sourcepub fn append_gate(&mut self, gate: QuantumGate, target: usize)
pub fn append_gate(&mut self, gate: QuantumGate, target: usize)
Appends an uncontrolled gate to the block.
Examples found in repository?
18fn qft(qubits: &[usize], do_swap: bool) -> Result<BasicBlock, KetError> {
19 let mut quantum_code = BasicBlock::new();
20 if qubits.len() == 1 {
21 quantum_code.append_gate(QuantumGate::Hadamard, qubits[0]);
22 return Ok(quantum_code);
23 }
24
25 let init = &qubits[..qubits.len() - 1];
26 let last = qubits[qubits.len() - 1];
27 quantum_code.append_gate(QuantumGate::Hadamard, last);
28 for (i, c) in init.iter().enumerate() {
29 quantum_code.append_block(
30 controlled_gate(
31 QuantumGate::Phase(Param::Value(PI / 2.0_f64.powi(i as i32 + 1))),
32 &[*c],
33 last,
34 )?,
35 None,
36 );
37 }
38 quantum_code.append_block(qft(init, false)?, None);
39
40 if do_swap {
41 for i in 0..qubits.len() / 2 {
42 quantum_code.append_block(swap_gate(qubits[i], qubits[qubits.len() - i - 1])?, None);
43 }
44 }
45
46 Ok(quantum_code)
47}More examples
14fn main() -> Result<(), KetError> {
15 let num_qubits = 3;
16
17 let mut process = Process::new(QPUConfig {
18 num_qubits,
19 quantum_execution: None,
20 });
21
22 let qubits: Result<Vec<_>, _> = (0..num_qubits).map(|_| process.alloc()).collect();
23 let qubits = qubits?;
24
25 let mut quantum_code = BasicBlock::new();
26
27 for target in &qubits {
28 quantum_code.append_gate(QuantumGate::Hadamard, *target);
29 }
30
31 process.append_block(quantum_code)?;
32
33 let steps = ((FRAC_PI_4) * f64::sqrt((1 << num_qubits) as f64)) as i64;
34
35 for _ in 0..steps {
36 process.append_block(compute_action_uncompute_gate(
37 |mut compute| {
38 for target in &qubits {
39 compute.append_gate(QuantumGate::PauliX, *target);
40 }
41 Ok(compute)
42 },
43 |mut action| {
44 action.append_gate(QuantumGate::PauliZ, qubits[0]);
45 Ok(action.control(&qubits[1..])?)
46 },
47 )?)?;
48
49 process.append_block(compute_action_uncompute_gate(
50 |mut compute| {
51 for target in &qubits {
52 compute.append_gate(QuantumGate::Hadamard, *target);
53 compute.append_gate(QuantumGate::PauliX, *target);
54 }
55 Ok(compute)
56 },
57 |mut action| {
58 action.append_gate(QuantumGate::PauliZ, qubits[0]);
59 Ok(action.control(&qubits[1..])?)
60 },
61 )?)?;
62 }
63
64 println!("{:#?}", process);
65
66 Ok(())
67}Sourcepub fn control(&self, control_qubits: &[usize]) -> Result<Self, KetError>
pub fn control(&self, control_qubits: &[usize]) -> Result<Self, KetError>
Returns a copy of this block with control_qubits added to every gate.
§Errors
Propagates any KetError returned by GateInstruction::control.
Examples found in repository?
14fn main() -> Result<(), KetError> {
15 let num_qubits = 3;
16
17 let mut process = Process::new(QPUConfig {
18 num_qubits,
19 quantum_execution: None,
20 });
21
22 let qubits: Result<Vec<_>, _> = (0..num_qubits).map(|_| process.alloc()).collect();
23 let qubits = qubits?;
24
25 let mut quantum_code = BasicBlock::new();
26
27 for target in &qubits {
28 quantum_code.append_gate(QuantumGate::Hadamard, *target);
29 }
30
31 process.append_block(quantum_code)?;
32
33 let steps = ((FRAC_PI_4) * f64::sqrt((1 << num_qubits) as f64)) as i64;
34
35 for _ in 0..steps {
36 process.append_block(compute_action_uncompute_gate(
37 |mut compute| {
38 for target in &qubits {
39 compute.append_gate(QuantumGate::PauliX, *target);
40 }
41 Ok(compute)
42 },
43 |mut action| {
44 action.append_gate(QuantumGate::PauliZ, qubits[0]);
45 Ok(action.control(&qubits[1..])?)
46 },
47 )?)?;
48
49 process.append_block(compute_action_uncompute_gate(
50 |mut compute| {
51 for target in &qubits {
52 compute.append_gate(QuantumGate::Hadamard, *target);
53 compute.append_gate(QuantumGate::PauliX, *target);
54 }
55 Ok(compute)
56 },
57 |mut action| {
58 action.append_gate(QuantumGate::PauliZ, qubits[0]);
59 Ok(action.control(&qubits[1..])?)
60 },
61 )?)?;
62 }
63
64 println!("{:#?}", process);
65
66 Ok(())
67}Sourcepub fn enable_approximated_decomposition(&mut self)
pub fn enable_approximated_decomposition(&mut self)
Enable approximate decomposition enabled on all gate instructions.
Sourcepub fn lock_control(&mut self)
pub fn lock_control(&mut self)
Lock control sets locked on all gates.
Sourcepub fn append_block(&mut self, block: Self, epsilon: Option<f64>)
pub fn append_block(&mut self, block: Self, epsilon: Option<f64>)
Appends all instructions from block into self, applying algebraic
simplifications using the given epsilon tolerance.
After draining block.gates, the global phases are summed and the
qubits_op dependency maps are merged (restricting propriety to the
more-general of the two).
Examples found in repository?
18fn qft(qubits: &[usize], do_swap: bool) -> Result<BasicBlock, KetError> {
19 let mut quantum_code = BasicBlock::new();
20 if qubits.len() == 1 {
21 quantum_code.append_gate(QuantumGate::Hadamard, qubits[0]);
22 return Ok(quantum_code);
23 }
24
25 let init = &qubits[..qubits.len() - 1];
26 let last = qubits[qubits.len() - 1];
27 quantum_code.append_gate(QuantumGate::Hadamard, last);
28 for (i, c) in init.iter().enumerate() {
29 quantum_code.append_block(
30 controlled_gate(
31 QuantumGate::Phase(Param::Value(PI / 2.0_f64.powi(i as i32 + 1))),
32 &[*c],
33 last,
34 )?,
35 None,
36 );
37 }
38 quantum_code.append_block(qft(init, false)?, None);
39
40 if do_swap {
41 for i in 0..qubits.len() / 2 {
42 quantum_code.append_block(swap_gate(qubits[i], qubits[qubits.len() - i - 1])?, None);
43 }
44 }
45
46 Ok(quantum_code)
47}Sourcepub fn add_global_phase(&mut self, phase: f64)
pub fn add_global_phase(&mut self, phase: f64)
Sum a global phase in the block.
Sourcepub fn max_qubit_index(&self) -> Option<usize>
pub fn max_qubit_index(&self) -> Option<usize>
Returns the highest qubit index referenced by any gate in this block,
or None if the block is empty.
Sourcepub fn flat_gates(
&self,
parameters: Option<&[f64]>,
shift: Option<(usize, usize, f64)>,
) -> Vec<DecomposedGate>
pub fn flat_gates( &self, parameters: Option<&[f64]>, shift: Option<(usize, usize, f64)>, ) -> Vec<DecomposedGate>
Flattens decomposed multi-qubit gates into a single sequence of
DecomposedGate.
When parameters is provided, any symbolic Param::Ref values are
resolved to their concrete floating-point equivalents before output.
Sourcepub fn set_as_diagonal(&mut self)
pub fn set_as_diagonal(&mut self)
Forces the propriety classification of every qubit entry to at most
GatePropriety::Diagonal, even if the actual gate sequence is more
general. Used when an externally-verified analysis guarantees the
circuit is diagonal.
Sourcepub fn set_as_permutation(&mut self)
pub fn set_as_permutation(&mut self)
Forces the propriety classification of every qubit entry to at most
GatePropriety::Permutation, even if the actual gate sequence is
more general. Used when an externally-verified analysis guarantees the
circuit only permutes basis states.
Trait Implementations§
Source§impl Clone for BasicBlock
impl Clone for BasicBlock
Source§fn clone(&self) -> BasicBlock
fn clone(&self) -> BasicBlock
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for BasicBlock
impl Debug for BasicBlock
Source§impl Default for BasicBlock
impl Default for BasicBlock
Source§fn default() -> BasicBlock
fn default() -> BasicBlock
Auto Trait Implementations§
impl Freeze for BasicBlock
impl RefUnwindSafe for BasicBlock
impl Send for BasicBlock
impl Sync for BasicBlock
impl Unpin for BasicBlock
impl UnsafeUnpin for BasicBlock
impl UnwindSafe for BasicBlock
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more