Skip to main content

Process

Struct Process 

Source
pub struct Process { /* private fields */ }
Expand description

A quantum process: the top-level compilation and execution unit.

Create a Process with Process::new, allocate qubits with Process::alloc, append gate sequences with Process::append_block, and trigger execution with Process::execute (batch mode) or read results immediately after each gate/measurement in live mode.

Each process follows a linear ProcessState machine and can be executed at most once. Results are cached and retrieved via Process::read_sample, Process::read_exp_value, and Process::read_gradient.

Implementations§

Source§

impl Process

Source

pub fn new(qpu_config: QPUConfig) -> Self

Creates a new Process from the given QPUConfig.

The process starts in the ProcessState::AcceptingGate state with an empty gate sequence, no allocated qubits, and an angle-cancellation threshold (epsilon) of 1e-10 radians.

Examples found in repository?
examples/qft.rs (lines 52-55)
49fn main() -> Result<(), KetError> {
50    let num_qubits = 12;
51
52    let mut process = Process::new(QPUConfig {
53        num_qubits,
54        quantum_execution: None,
55    });
56
57    let qubits: Result<Vec<_>, _> = (0..num_qubits).map(|_| process.alloc()).collect();
58    let qubits = qubits?;
59
60    process.append_block(qft(&qubits, true)?)?;
61
62    println!("{:#?}", process);
63
64    Ok(())
65}
More examples
Hide additional examples
examples/grover.rs (lines 17-20)
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}
Source

pub const fn alloc(&mut self) -> Result<usize, KetError>

Allocates the next available logical qubit and returns its index.

§Errors
Examples found in repository?
examples/qft.rs (line 57)
49fn main() -> Result<(), KetError> {
50    let num_qubits = 12;
51
52    let mut process = Process::new(QPUConfig {
53        num_qubits,
54        quantum_execution: None,
55    });
56
57    let qubits: Result<Vec<_>, _> = (0..num_qubits).map(|_| process.alloc()).collect();
58    let qubits = qubits?;
59
60    process.append_block(qft(&qubits, true)?)?;
61
62    println!("{:#?}", process);
63
64    Ok(())
65}
More examples
Hide additional examples
examples/grover.rs (line 22)
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}
Source

pub fn append_block(&mut self, block: BasicBlock) -> Result<(), KetError>

Appends a BasicBlock of gate instructions to this process.

If required, gate decomposition is performed in parallel before the block is merged into the main circuit. In live mode every gate is sent to the QPU backend immediately.

§Errors
Examples found in repository?
examples/qft.rs (line 60)
49fn main() -> Result<(), KetError> {
50    let num_qubits = 12;
51
52    let mut process = Process::new(QPUConfig {
53        num_qubits,
54        quantum_execution: None,
55    });
56
57    let qubits: Result<Vec<_>, _> = (0..num_qubits).map(|_| process.alloc()).collect();
58    let qubits = qubits?;
59
60    process.append_block(qft(&qubits, true)?)?;
61
62    println!("{:#?}", process);
63
64    Ok(())
65}
More examples
Hide additional examples
examples/grover.rs (line 31)
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}
Source

pub fn main_block(&self) -> &BasicBlock

Returns a reference to the accumulated gate sequence of this process.

Useful for introspection or serialization before execution.

Source

pub fn measure(&mut self, qubits: &[usize]) -> Result<u64, KetError>

Performs a single-shot mid-circuit measurement of qubits.

§Errors
Source

pub fn dump(&mut self, qubits: &[usize]) -> Result<DumpData, KetError>

Dumps the quantum state of qubits (live mode only).

§Errors
Source

pub fn sample( &mut self, qubits: &[usize], shots: usize, ) -> Result<Option<SampleData>, KetError>

Requests a measurement sample of qubits over shots repetitions.

Live mode: The sample is taken immediately and returned as Ok(Some(SampleData)).

Batch mode: The request is recorded and Ok(None) is returned. The process transitions to ProcessState::ReadyToExecute. Call Process::execute to dispatch the circuit and then retrieve the result with Process::read_sample.

§Errors
Source

pub fn read_sample(&self) -> Option<&SampleData>

Returns a reference to the cached SampleData from the most recent execution, or None if no sample result is available yet.

Source

pub fn exp_value( &mut self, hamiltonian: Hamiltonian, ) -> Result<Option<f64>, KetError>

Requests the expectation value ⟨ψ|H|ψ⟩ of hamiltonian.

Live mode: The expectation value is computed immediately and returned as Ok(Some(f64)).

Batch mode (no gradient): The Hamiltonian is appended to the internal list. The process stays in (or transitions to) ProcessState::AcceptingHamiltonian, allowing additional Hamiltonians to be registered before execution.

Batch mode (with gradient): The Hamiltonian is registered and the process immediately transitions to ProcessState::ReadyToExecute because the parameter-shift rule requires exactly one observable.

In both batch cases Ok(None) is returned; call Process::execute followed by Process::read_exp_value to retrieve the results.

§Errors
  • KetError::ExpectationValueUnavailable: the process is in an incompatible state (e.g., already terminated or a sample request has been registered), or no execution backend is configured.
Source

pub fn read_exp_value(&self) -> Option<&[f64]>

Returns a slice of the cached expectation-value results from the most recent execution, or None if no results are available yet.

The slice contains one value per Hamiltonian registered via Process::exp_value, in registration order.

Source

pub fn read_gradient(&self) -> Option<&[f64]>

Returns a slice of the cached gradient values from the most recent execution, or None if gradient computation was not enabled or has not yet been performed.

The slice contains one value per registered parameter (in registration order). Each element is the partial derivative of the expectation value with respect to that parameter.

Source

pub fn param(&mut self, param: f64) -> Param

Registers a new differentiable parameter with initial value param and returns a Param::Ref token for embedding in gate rotation angles.

Source

pub fn execute(&mut self) -> Result<(), KetError>

Compiles and executes the accumulated circuit (batch mode only).

§Errors
Source

pub fn status(&self) -> ProcessState

Returns the current ProcessState of this process.

Trait Implementations§

Source§

impl Debug for Process

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.