ket.base¶
Base classes for quantum programming.
This module provides the base classes for quantum programming in Ket, including the
Process
, which is the gateway for qubit allocation and quantum execution,
and the Quant
, which stores the qubit’s reference.
With the exception of Process
, the classes in this module are not
intended to be instantiated directly by the user. Instead, they are meant to be
created through provided functions.
Classes ket.base
¶
Quantum measurement result. |
|
Parameter for gradient calculation. |
|
Quantum program process. |
|
List of qubits. |
|
Quantum state measurement samples. |
- class Measurement(qubits: Quant)¶
Quantum measurement result.
This class holds a reference for a measurement result. The result may not be available right after the measurement call, especially in batch execution.
To read the value, access the attribute
value
. If the value is not available, the measurement will return None; otherwise, it will return an unsigned integer.You can instantiate this class by calling the
measure
function.Example
from ket import * p = Process() q = p.alloc(2) CNOT(H(q[0]), q[1]) result = measure(q) print(result.value) # 0 or 3
- class Parameter(process, index, value, multiplier=1)¶
Parameter for gradient calculation.
This class represents a parameter for gradient calculation in a quantum process. It should not be instanced directly, but rather obtained from the
param
method.
- class Process(execution_target: BatchExecution | LiveExecution | None = None, num_qubits: int | None = None, simulator: Literal['sparse', 'dense', 'dense v2'] | None = None, execution: Literal['live', 'batch'] | None = None, gradient: bool = False, **kwargs)¶
Quantum program process.
A
Process
in Ket is responsible for preparing and executing quantum circuits. It serves as a direct interface to the underlying Rust runtime library. The primary way to interact with a process is through thealloc
method to allocate qubits.Example
from ket import Process p = Process() qubits = p.alloc(10) # Allocate 10 qubits
By default, quantum execution is handled by the KBW simulator in sparse mode with support for up to 32 qubits. In sparse mode, qubits are represented using a data structure similar to a sparse matrix. This mode performs well when the quantum state involves the superposition of a small number of basis states, such as GHZ states, and is suitable as a general default when the number of qubits is unknown.
The dense simulation mode, on the other hand, has exponential time complexity in the number of qubits. It leverages CPU parallelism more effectively, but requires careful management of the number of qubits, defaulting to 12. The choice between sparse and dense simulation depends on the specific quantum algorithm being implemented, as each mode has trade-offs in performance and scalability.
The execution mode of the simulator can be set to either
"live"
or"batch"
:Live (default): Quantum instructions are executed immediately upon invocation. This mode is ideal for interactive simulation.
Batch: Quantum instructions are queued and executed only at the a measurement result is requested. This mode better reflects the behavior of real quantum hardware and is recommended for preparing code for deployment to QPUs.
Batch Execution Example:
from ket import * p = Process(execution="batch") a, b = p.alloc(2) CNOT(H(a), b) # Prepare a Bell state d = sample(a + b) print(d.get()) # Execution happens here CNOT(a, b) # Raises an error: process already executed
Live Execution Example:
from ket import * p = Process(execution="live") a, b = p.alloc(2) CNOT(H(a), b) # Prepare a Bell state print(sample(a + b).get()) # Output is available immediately CNOT(a, b) H(a) print(sample(a + b).get())
- Parameters:
execution_target – Quantum execution target object. If not provided, the KBW simulator is used.
num_qubits – Number of qubits for the KBW simulator. Defaults to 32 for sparse mode, or 12 for dense mode.
simulator – Simulation mode for the KBW simulator, either
"sparse"
or"dense"
. Defaults to"sparse"
.execution – Execution mode for the KBW simulator, either
"live"
or"batch"
. Defaults to"live"
.
- alloc(num_qubits: int = 1) Quant ¶
Allocate qubits and return a
Quant
object.Each qubit is assigned a unique index, and the resulting
Quant
object encapsulates the allocated qubits along with a reference to the parentProcess
object.Example
>>> from ket import Process >>> p = Process() >>> qubits = p.alloc(3) >>> print(qubits) <Ket 'Quant' [0, 1, 2] pid=0x...>
- Parameters:
num_qubits – The number of qubits to allocate. Defaults to 1.
- Returns:
A list like object representing the allocated qubits.
- get_instructions() list[dict] ¶
Retrieve quantum instructions from the process.
The format of the instructions is defined in the runtime library Libket.
Example
>>> from ket import * >>> p = Process() >>> a, b = p.alloc(2) >>> CNOT(H(a), b) >>> # Get quantum instructions >>> instructions = p.get_instructions() >>> pprint(instructions) [{'Gate': {'control': [], 'gate': 'Hadamard', 'target': {'Main': {'index': 0}}}}, {'Gate': {'control': [{'Main': {'index': 0}}], 'gate': 'PauliX', 'target': {'Main': {'index': 1}}}}]
- Returns:
A list of dictionaries containing quantum instructions extracted from the process.
- get_mapped_instructions() list[dict] | None ¶
Retrieve quantum instructions after the circuit mapping.
The format of the instructions is defined in the runtime library Libket.
The instructions are extracted after the circuit mapping step, which is performed during the compilation process. A qubit coupling graph must be passed to the process for the quantum circuit mapping to happen. Note that at this point, the single qubit gates have not been translated to the native gate set of the quantum hardware yet.
Example
>>> n = 4 >>> coupling_graph = [(0, 1), (1, 2), (2, 3), (3, 0)] >>> p = Process(num_qubits=n, coupling_graph=coupling_graph) >>> q = p.alloc(n) >>> ctrl(H(q[0]), X)(q[1:]) >>> m = measure(q) >>> p.prepare_for_execution() >>> pprint(p.get_mapped_instructions()) [{'Gate': {'control': [], 'gate': 'Hadamard', 'target': {'index': 0}}}, {'Gate': {'control': [{'index': 0}], 'gate': 'PauliX', 'target': {'index': 1}}}, 'Identity', {'Gate': {'control': [{'index': 3}], 'gate': 'PauliX', 'target': {'index': 0}}}, {'Gate': {'control': [{'index': 0}], 'gate': 'PauliX', 'target': {'index': 3}}}, {'Gate': {'control': [{'index': 3}], 'gate': 'PauliX', 'target': {'index': 2}}}, {'Measure': {'index': 0, 'qubits': [{'index': 3}, {'index': 1}, {'index': 0}, {'index': 2}]}}]
- Returns:
A list of dictionaries containing quantum instructions extracted from the process if the process has been transpiled, otherwise None.
- get_metadata() dict[str, Any] ¶
Retrieve metadata from the quantum process.
Example
>>> n = 4 >>> coupling_graph = [(0, 1), (1, 2), (2, 3), (3, 0)] >>> p = Process(num_qubits=n, coupling_graph=coupling_graph) >>> q = p.alloc(n) >>> ctrl(H(q[0]), X)(q[1:]) >>> m = measure(q) >>> p.prepare_for_execution() >>> pprint(p.get_mapped_instructions()) {'allocated_qubits': 4, 'decomposition': {'NoAuxCX': 3}, 'logical_circuit_depth': 3, 'logical_gate_count': {'1': 1, '2': 3}, 'physical_circuit_depth': 5, 'physical_gate_count': {'1': 1, '2': 4}, 'terminated': True}
- Returns:
A dictionary containing metadata information extracted from the process.
- param(*param) list[Parameter] | Parameter ¶
Register a parameter for gradient calculation.
- Parameters:
*param – Variable-length argument list of floats.
- Returns:
A list of
Parameter
objects.
- save()¶
Save the quantum simulation state.
This method saves the current state of the quantum simulation. It works only in simulated execution, provided that the simulator supports state saving. If state saving is not available, no error will be raised.
The structure of the saved state depends on the simulator and is not interchangeable between different simulators. Note that the saved state does not retain information about the order of qubit allocation. Using the saved state may result in unintended behavior if the qubit allocation order differs when the state is loaded.
- load(data)¶
Loads the given data into the simulation state.
The data must be generated by a call to the method save with the same simulator. If the state load fails in the simulator, the state is not altered, and it may raise no error.
- Parameters:
data – Quantum state. The data format depends on the simulator.
- class Quant(*, qubits: list[int], process: Process)¶
List of qubits.
This class represents a list of qubit indices within a quantum process. Direct instantiation of this class is not recommended. Instead, it should be created by calling the
alloc
method.A
Quant
serves as a fundamental quantum object where quantum operations should be applied.Example
from ket import * # Create a quantum process p = Process() # Allocate 2 qubits q1 = p.alloc(2) # Apply a Hadamard gates on the first qubit of `q1` H(q1[0]) # Allocate more 2 qubits q2 = p.alloc(2) # Concatenate two Quant objects result_quant = q1 + q2 print(result_quant) # <Ket 'Quant' [0, 1, 2, 3] pid=0x...> # Use the fist qubit to control the application of # a Pauli X gate on the other qubits ctrl(result_quant[0], X)(result_quant[1:]) # Select qubits at specific indexes selected_quant = result_quant.at([0, 1]) print(selected_quant) # <Ket 'Quant' [0, 1] pid=0x...>
Supported operations:
Addition (
+
): Concatenates twoQuant
objects. The processes must be the same.Indexing (
[index]
): Returns a newQuant
object with selected qubits based on the provided index.Iteration (
for q in qubits
): Allows iterating over qubits in aQuant
object.Reversal (
reversed(qubits)
): Returns a newQuant
object with reversed qubits.Length (
len(qubits)
): Returns the number of qubits in theQuant
object.
- at(index: list[int]) Quant ¶
Return a subset of qubits at specified indices.
Create a new
Quant
object with qubit references at the positions defined by the providedindex
list.Example
from ket import * # Create a quantum process p = Process() # Allocate 5 qubits q = p.alloc(5) # Select qubits at odd indices (1, 3) odd_qubits = q.at([1, 3])
- class Samples(qubits: Quant, shots: int = 2048)¶
Quantum state measurement samples.
This class holds a reference for a measurement sample result. The result may not be available right after the sample call, especially in batch execution.
To read the value, access the attribute
value
. If the value is not available, the measurement will return None; otherwise, it will return a dictionary mapping measurement outcomes to their respective counts.You can instantiate this class by calling the
sample
function.Example
from ket import * p = Process() q = p.alloc(2) CNOT(H(q[0]), q[1]) results = sample(q) print(results.value) # {0: 1042, 3: 1006}
- Parameters:
qubits – Qubits for which the measurement samples are obtained.
shots – Number of measurement shots (default is 2048).
- get() dict[int, int] ¶
Retrieve the measurement samples.
If the value is not available, the quantum process will execute to get the result.
- histogram(**kwargs) go.Figure ¶
Generate a histogram representing the sample.
This method creates a histogram visualizing the probability distribution of the sample.
Note
This method requires additional dependencies from
ket-lang[plot]
.Install with:
pip install ket-lang[plot]
.- Returns:
Histogram of sample measurement.