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
impl Process
Sourcepub fn new(qpu_config: QPUConfig) -> Self
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?
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
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 const fn alloc(&mut self) -> Result<usize, KetError>
pub const fn alloc(&mut self) -> Result<usize, KetError>
Allocates the next available logical qubit and returns its index.
§Errors
KetError::ProcessTerminated: the process has already been executed.KetError::QubitLimitExceeded: all qubits permitted by the QPU configuration have been allocated.
Examples found in repository?
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
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_block(&mut self, block: BasicBlock) -> Result<(), KetError>
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
KetError::GateAppendForbidden: the process is not in the gate-accepting state.KetError::QubitIndexOutOfRange: the block references a qubit that has not yet been allocated.
Examples found in repository?
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
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 main_block(&self) -> &BasicBlock
pub fn main_block(&self) -> &BasicBlock
Returns a reference to the accumulated gate sequence of this process.
Useful for introspection or serialization before execution.
Sourcepub fn measure(&mut self, qubits: &[usize]) -> Result<u64, KetError>
pub fn measure(&mut self, qubits: &[usize]) -> Result<u64, KetError>
Performs a single-shot mid-circuit measurement of qubits.
§Errors
KetError::MeasurementUnavailableInBatch: the process is not running in live execution mode.
Sourcepub fn dump(&mut self, qubits: &[usize]) -> Result<DumpData, KetError>
pub fn dump(&mut self, qubits: &[usize]) -> Result<DumpData, KetError>
Dumps the quantum state of qubits (live mode only).
§Errors
KetError::DumpUnavailableInBatch: the process is not running in live execution mode.
Sourcepub fn sample(
&mut self,
qubits: &[usize],
shots: usize,
) -> Result<Option<SampleData>, KetError>
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
KetError::SamplingUnavailable: a conflicting measurement has already been registered, or no execution backend is configured.
Sourcepub fn read_sample(&self) -> Option<&SampleData>
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.
Sourcepub fn exp_value(
&mut self,
hamiltonian: Hamiltonian,
) -> Result<Option<f64>, KetError>
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.
Sourcepub fn read_exp_value(&self) -> Option<&[f64]>
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.
Sourcepub fn read_gradient(&self) -> Option<&[f64]>
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.
Sourcepub fn param(&mut self, param: f64) -> Param
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.
Sourcepub fn execute(&mut self) -> Result<(), KetError>
pub fn execute(&mut self) -> Result<(), KetError>
Compiles and executes the accumulated circuit (batch mode only).
§Errors
KetError::NoPendingMeasurement: nosampleorexp_valuerequest has been registered before callingexecute.KetError::ExplicitExecuteInLiveMode: the process is in live execution mode, where gates are dispatched immediately.
Sourcepub fn status(&self) -> ProcessState
pub fn status(&self) -> ProcessState
Returns the current ProcessState of this process.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for Process
impl !Send for Process
impl !Sync for Process
impl !UnwindSafe for Process
impl Freeze for Process
impl Unpin for Process
impl UnsafeUnpin for Process
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> 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