Struct ket::process::Process

source ·
pub struct Process { /* private fields */ }
Expand description

Quantum Process for managing qubit allocation and circuit creation.

This struct encapsulates the necessary information for handling qubit allocations and creating quantum circuits. It provides functions to apply quantum gates, measure qubits, and execute quantum code.

§Examples

use ket::{Configuration, Process, QuantumGate};

// Configuration instance must be provided by the quantum execution.
// See the KBW documentation for examples.
let configuration = Configuration::new(2);

// Create a new process with the provided configurations.
// The configuration will specify the maximum number of qubits the quantum
// execution can handle, the execution mode, and more.
let mut process = Process::new(configuration);

// Allocate qubits and return their references for later usage.
let qubit_a = process.allocate_qubit()?;
let qubit_b = process.allocate_qubit()?;

// Apply a Hadamard gate to the first qubit.
process.apply_gate(QuantumGate::Hadamard, qubit_a)?;

// Push the first qubit to the control stack, apply a Pauli X gate to the second qubit,
// and pop the qubit from the control stack.
process.ctrl_push(&[qubit_a])?;
process.apply_gate(QuantumGate::PauliX, qubit_b)?;
process.ctrl_pop()?;

// Measure the qubits and return the results references.
let m_a = process.measure(&[qubit_a])?;
let m_b = process.measure(&[qubit_b])?;

Implementations§

source§

impl Process

source

pub fn new(config: Configuration) -> Self

Creates a new Process with the given configurations

Examples found in repository?
examples/bell.rs (line 17)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
fn main() -> Result<(), KetError> {
    // Configuration instance must be provided by the quantum execution.
    // See the KBW documentation for examples.
    let configuration = Configuration::new(2);

    // Create a new process with the provided configurations.
    // The configuration will specify the maximum number of qubits the quantum
    // execution can handle, the execution mode, and more.
    let mut process = Process::new(configuration);

    // Allocate qubits and return their references for later usage.
    let qubit_a = process.allocate_qubit()?;
    let qubit_b = process.allocate_qubit()?;

    // Apply a Hadamard gate to the first qubit.
    process.apply_gate(QuantumGate::Hadamard, qubit_a)?;

    // Push the first qubit to the control stack, apply a Pauli X gate to the second qubit,
    // and pop the qubit from the control stack.
    process.ctrl_push(&[qubit_a])?;
    process.apply_gate(QuantumGate::PauliX, qubit_b)?;
    process.ctrl_pop()?;

    // Measure the qubits and return the results references.
    let _m_a = process.measure(&[qubit_a])?;
    let _m_b = process.measure(&[qubit_b])?;

    let _exp = process.exp_values(PauliHamiltonian {
        coefficients: vec![1.0],
        products: vec![vec![
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_a,
            },
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_b,
            },
        ]],
    })?;

    Ok(())
}
source

pub fn allocate_qubit(&mut self) -> Result<usize>

Allocate a qubit and return its index.

The qubit index resulting from the allocation is used in quantum gate application, measurement, quantum state dump, and expected value calculations.

§Examples
let qubit_index = process.allocate_qubit()?;
// Now you can use the allocated qubit_index in quantum operations.
§Errors

Returns an error if the process is in an inverse scope, if it is ready for execution, or if the number of allocated qubits exceeds the configured limit.

Examples found in repository?
examples/bell.rs (line 20)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
fn main() -> Result<(), KetError> {
    // Configuration instance must be provided by the quantum execution.
    // See the KBW documentation for examples.
    let configuration = Configuration::new(2);

    // Create a new process with the provided configurations.
    // The configuration will specify the maximum number of qubits the quantum
    // execution can handle, the execution mode, and more.
    let mut process = Process::new(configuration);

    // Allocate qubits and return their references for later usage.
    let qubit_a = process.allocate_qubit()?;
    let qubit_b = process.allocate_qubit()?;

    // Apply a Hadamard gate to the first qubit.
    process.apply_gate(QuantumGate::Hadamard, qubit_a)?;

    // Push the first qubit to the control stack, apply a Pauli X gate to the second qubit,
    // and pop the qubit from the control stack.
    process.ctrl_push(&[qubit_a])?;
    process.apply_gate(QuantumGate::PauliX, qubit_b)?;
    process.ctrl_pop()?;

    // Measure the qubits and return the results references.
    let _m_a = process.measure(&[qubit_a])?;
    let _m_b = process.measure(&[qubit_b])?;

    let _exp = process.exp_values(PauliHamiltonian {
        coefficients: vec![1.0],
        products: vec![vec![
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_a,
            },
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_b,
            },
        ]],
    })?;

    Ok(())
}
source

pub fn free_qubit(&mut self, qubit: usize) -> Result<()>

Frees a previously allocated qubit

§Examples
let qubit_index = process.allocate_qubit()?;
// Perform quantum operations...
process.free_qubit(qubit_index)?;
// Qubit has been freed and can no longer be used in quantum operations.
§Errors

Returns an error if the process is in an inverse scope, if it is ready for execution, or if the specified qubit has not been allocated.

source

pub fn apply_gate(&mut self, gate: QuantumGate, target: usize) -> Result<()>

Applies a quantum gate to a target qubit

This function considers the control qubit list to apply the quantum gate in the target qubit.

If the process has an opened inverse scope, the gate will only be applied when the scope is closed.

§Examples
let qubit_index = process.allocate_qubit()?;
process.apply_gate(QuantumGate::Hadamard, qubit_index)?;
// Perform additional quantum operations...
§Errors

Returns an error if the process is ready for execution, if the specified qubit has not been allocated, or if the target qubit is part of the control qubits.

Examples found in repository?
examples/bell.rs (line 24)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
fn main() -> Result<(), KetError> {
    // Configuration instance must be provided by the quantum execution.
    // See the KBW documentation for examples.
    let configuration = Configuration::new(2);

    // Create a new process with the provided configurations.
    // The configuration will specify the maximum number of qubits the quantum
    // execution can handle, the execution mode, and more.
    let mut process = Process::new(configuration);

    // Allocate qubits and return their references for later usage.
    let qubit_a = process.allocate_qubit()?;
    let qubit_b = process.allocate_qubit()?;

    // Apply a Hadamard gate to the first qubit.
    process.apply_gate(QuantumGate::Hadamard, qubit_a)?;

    // Push the first qubit to the control stack, apply a Pauli X gate to the second qubit,
    // and pop the qubit from the control stack.
    process.ctrl_push(&[qubit_a])?;
    process.apply_gate(QuantumGate::PauliX, qubit_b)?;
    process.ctrl_pop()?;

    // Measure the qubits and return the results references.
    let _m_a = process.measure(&[qubit_a])?;
    let _m_b = process.measure(&[qubit_b])?;

    let _exp = process.exp_values(PauliHamiltonian {
        coefficients: vec![1.0],
        products: vec![vec![
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_a,
            },
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_b,
            },
        ]],
    })?;

    Ok(())
}
source

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

Measures the specified qubits

This function performs measurements on the specified qubits. It updates the internal state of the process, records measurement instructions, and returns the index of the measurement result.

§Examples
let qubit_index = process.allocate_qubit()?;
let measurement_index = process.measure(&[qubit_index])?;
// Perform additional quantum operations or measurements...
§Errors

Returns an error if the process is in an adjacent scope, if the process is ready for execution, or if measurements are not allowed based on the process configuration.

Examples found in repository?
examples/bell.rs (line 33)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
fn main() -> Result<(), KetError> {
    // Configuration instance must be provided by the quantum execution.
    // See the KBW documentation for examples.
    let configuration = Configuration::new(2);

    // Create a new process with the provided configurations.
    // The configuration will specify the maximum number of qubits the quantum
    // execution can handle, the execution mode, and more.
    let mut process = Process::new(configuration);

    // Allocate qubits and return their references for later usage.
    let qubit_a = process.allocate_qubit()?;
    let qubit_b = process.allocate_qubit()?;

    // Apply a Hadamard gate to the first qubit.
    process.apply_gate(QuantumGate::Hadamard, qubit_a)?;

    // Push the first qubit to the control stack, apply a Pauli X gate to the second qubit,
    // and pop the qubit from the control stack.
    process.ctrl_push(&[qubit_a])?;
    process.apply_gate(QuantumGate::PauliX, qubit_b)?;
    process.ctrl_pop()?;

    // Measure the qubits and return the results references.
    let _m_a = process.measure(&[qubit_a])?;
    let _m_b = process.measure(&[qubit_b])?;

    let _exp = process.exp_values(PauliHamiltonian {
        coefficients: vec![1.0],
        products: vec![vec![
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_a,
            },
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_b,
            },
        ]],
    })?;

    Ok(())
}
source

pub fn exp_values(&mut self, hamiltonian: PauliHamiltonian) -> Result<usize>

Calculates the expected values of a Pauli Hamiltonian

This function calculates the expected values of a Pauli Hamiltonian. It updates the internal state of the process, records the calculation instructions, and returns the index of the expected value result.

§Examples
use ket::{Pauli, PauliHamiltonian, PauliTerm};

let qubit_a = process.allocate_qubit()?;
let qubit_b = process.allocate_qubit()?;
let _exp = process.exp_values(PauliHamiltonian {
    coefficients: vec![1.0],
    products: vec![vec![
        PauliTerm {
            pauli: Pauli::PauliX,
            qubit: qubit_a,
        },
        PauliTerm {
            pauli: Pauli::PauliX,
            qubit: qubit_b,
        },
    ]],
})?;
§Errors

Returns an error if the process is in an adjacent scope, if the process is ready for execution, or if expected value calculations are not allowed based on the process configuration. Additionally, it verifies whether the qubits involved in the Hamiltonian are allocated.

Examples found in repository?
examples/bell.rs (lines 36-48)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
fn main() -> Result<(), KetError> {
    // Configuration instance must be provided by the quantum execution.
    // See the KBW documentation for examples.
    let configuration = Configuration::new(2);

    // Create a new process with the provided configurations.
    // The configuration will specify the maximum number of qubits the quantum
    // execution can handle, the execution mode, and more.
    let mut process = Process::new(configuration);

    // Allocate qubits and return their references for later usage.
    let qubit_a = process.allocate_qubit()?;
    let qubit_b = process.allocate_qubit()?;

    // Apply a Hadamard gate to the first qubit.
    process.apply_gate(QuantumGate::Hadamard, qubit_a)?;

    // Push the first qubit to the control stack, apply a Pauli X gate to the second qubit,
    // and pop the qubit from the control stack.
    process.ctrl_push(&[qubit_a])?;
    process.apply_gate(QuantumGate::PauliX, qubit_b)?;
    process.ctrl_pop()?;

    // Measure the qubits and return the results references.
    let _m_a = process.measure(&[qubit_a])?;
    let _m_b = process.measure(&[qubit_b])?;

    let _exp = process.exp_values(PauliHamiltonian {
        coefficients: vec![1.0],
        products: vec![vec![
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_a,
            },
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_b,
            },
        ]],
    })?;

    Ok(())
}
source

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

Performs sampling on specified qubits

This function performs sampling on the specified qubits with a specified number of shots. It updates the internal state of the process, records sampling instructions, and returns the index of the sample result.

§Examples
let qubit_a = process.allocate_qubit()?;
let qubit_b = process.allocate_qubit()?;
let shots = 1000;
let sample_index = process.sample(&[qubit_a, qubit_b], shots)?;
// Perform additional quantum operations or sampling...
§Errors

Returns an error if the process is in an adjacent scope, if the process is ready for execution, or if sampling is not allowed based on the process configuration. Additionally, it verifies whether the qubits involved in the sampling are allocated.

source

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

Dumps the state of specified qubits

This function dumps the state of the specified qubits. It updates the internal state of the process, records dump instructions, and returns the index of the dump result.

§Examples
let qubit_a = process.allocate_qubit()?;
let qubit_b = process.allocate_qubit()?;
let dump_index = process.dump(&[qubit_a, qubit_b])?;
// Perform additional quantum operations or dumps...
§Errors

Returns an error if the process is in an adjacent scope, if the process is ready for execution, or if dumping is not allowed based on the process configuration. Additionally, it verifies whether the qubits involved in the dump operation are allocated.

source

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

Pushes control qubits onto the control stack

This function pushes control qubits onto the control stack. It updates the internal state of the process and ensures that qubits are not controlled more than once.

§Examples
let qubit_a = process.allocate_qubit()?;
let qubit_b = process.allocate_qubit()?;
process.ctrl_push(&[qubit_a, qubit_b])?;
// Perform additional quantum operations...
§Errors

Returns an error if the process is ready for execution or if the control qubits are allocated more than once during a control operation.

Examples found in repository?
examples/bell.rs (line 28)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
fn main() -> Result<(), KetError> {
    // Configuration instance must be provided by the quantum execution.
    // See the KBW documentation for examples.
    let configuration = Configuration::new(2);

    // Create a new process with the provided configurations.
    // The configuration will specify the maximum number of qubits the quantum
    // execution can handle, the execution mode, and more.
    let mut process = Process::new(configuration);

    // Allocate qubits and return their references for later usage.
    let qubit_a = process.allocate_qubit()?;
    let qubit_b = process.allocate_qubit()?;

    // Apply a Hadamard gate to the first qubit.
    process.apply_gate(QuantumGate::Hadamard, qubit_a)?;

    // Push the first qubit to the control stack, apply a Pauli X gate to the second qubit,
    // and pop the qubit from the control stack.
    process.ctrl_push(&[qubit_a])?;
    process.apply_gate(QuantumGate::PauliX, qubit_b)?;
    process.ctrl_pop()?;

    // Measure the qubits and return the results references.
    let _m_a = process.measure(&[qubit_a])?;
    let _m_b = process.measure(&[qubit_b])?;

    let _exp = process.exp_values(PauliHamiltonian {
        coefficients: vec![1.0],
        products: vec![vec![
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_a,
            },
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_b,
            },
        ]],
    })?;

    Ok(())
}
source

pub fn ctrl_pop(&mut self) -> Result<()>

Pops the last added control qubits from the control stack

§Errors

Returns an error if the process is ready for execution or if there are no control configurations on the control stack to pop.

Examples found in repository?
examples/bell.rs (line 30)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
fn main() -> Result<(), KetError> {
    // Configuration instance must be provided by the quantum execution.
    // See the KBW documentation for examples.
    let configuration = Configuration::new(2);

    // Create a new process with the provided configurations.
    // The configuration will specify the maximum number of qubits the quantum
    // execution can handle, the execution mode, and more.
    let mut process = Process::new(configuration);

    // Allocate qubits and return their references for later usage.
    let qubit_a = process.allocate_qubit()?;
    let qubit_b = process.allocate_qubit()?;

    // Apply a Hadamard gate to the first qubit.
    process.apply_gate(QuantumGate::Hadamard, qubit_a)?;

    // Push the first qubit to the control stack, apply a Pauli X gate to the second qubit,
    // and pop the qubit from the control stack.
    process.ctrl_push(&[qubit_a])?;
    process.apply_gate(QuantumGate::PauliX, qubit_b)?;
    process.ctrl_pop()?;

    // Measure the qubits and return the results references.
    let _m_a = process.measure(&[qubit_a])?;
    let _m_b = process.measure(&[qubit_b])?;

    let _exp = process.exp_values(PauliHamiltonian {
        coefficients: vec![1.0],
        products: vec![vec![
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_a,
            },
            PauliTerm {
                pauli: Pauli::PauliX,
                qubit: qubit_b,
            },
        ]],
    })?;

    Ok(())
}
source

pub fn adj_begin(&mut self) -> Result<()>

Begins an adjoint block, where gates are inverted upon insertion

§Errors

Returns an error if the process is ready for execution.

source

pub fn adj_end(&mut self) -> Result<()>

Ends the adjoint block, reverting to normal gate insertion

§Errors

Returns an error if the process is ready for execution or if there is no adjoint block to end.

source

pub fn prepare_for_execution(&mut self) -> Result<()>

Prepares the process for quantum execution

source

pub fn get_qubit_status(&self, qubit: usize) -> &QubitStatus

Returns the status of the specified qubit

source

pub fn get_measurement(&self, index: usize) -> &Measurement

Returns the measurement result at the specified index

source

pub fn get_exp_value(&self, index: usize) -> &ExpValue

Returns the expected value result at the specified index

source

pub fn get_sample(&self, index: usize) -> &Sample

Returns the sample result at the specified index

source

pub fn get_dump(&self, index: usize) -> &Dump

Returns the dump result at the specified index

source

pub fn get_metadata(&self) -> &Metadata

Return process metadata

source

pub fn set_result(&mut self, results: ResultData) -> Result<()>

Set the quantum execution result

This function allow to manually set the quantum execution result for the process. However, this function should only be used for testing purposes. The result must be provided by the quantum executor set in the configuration.

Auto Trait Implementations§

§

impl !RefUnwindSafe for Process

§

impl !Send for Process

§

impl !Sync for Process

§

impl Unpin for Process

§

impl !UnwindSafe for Process

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, U> TryFrom<U> for T
where U: Into<T>,

§

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>,

§

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.