.. _KetRuntime: ######################## Ket Runtime Architecture ######################## .. image:: _static/runtime.svg :width: 100% :class: only-light, no-scaled-link :alt: Ket applications communicate with the runtime library Libket, and Libket communicates with the quantum simulator KBW .. image:: _static/runtime_dark.svg :width: 100% :class: only-dark, no-scaled-link :alt: Ket applications communicate with the runtime library Libket, and Libket communicates with the quantum simulator KBW Ket is a hybrid classical-quantum programming language designed to run on a classical computer coordinating a cloud-based quantum computer. Ket's runtime architecture assumes that quantum computers process in batch (without interaction during the execution) to reduce the decoherence effects. Ket also provides a live execution mode, that facilitates the analyses and debugging of quantum applications on simulators. Components ========== Ket has three components, the language Ket, the runtime library Libket, and the quantum simulator Ket Bitwise Simulator (KBW). * **Ket** is a Python-embedded classical-quantum programming language that friendly exposes the Libket functionality. A `ctypes `_ wrapper of Libket's C API provides Ket's built-in types and functions. * **Libket** is a Rust runtime library designed for quantum programming, offering all the essential tools to develop quantum applications. It operates independently of the Ket language, allowing direct linkage of quantum applications to Libket, thereby eliminating Python overhead. Additionally, Libket provides a C API for integration with other programming languages. Libket does not execute the generated quantum code but passes it to a quantum executor. For the Ket language, the default quantum executor is the KBW simulator. It is possible to change the simulator at runtime. * **KBW** is a quantum simulator based on the `Bitwise Representation `_ that can execute all of the instructions issued by Libket. KBW's Sparse simulation time is independent of the number of qubits, allowing the simulation of 30+ qubits when working with a low amount of superposition. For example, the code below presents the execution time to prepare a GHZ state with 80 qubits on a Intel® Core™ i5-1340P. .. code-block:: py from time import time import ket begin = time() p = ket.Process(num_qubits=80, simulator="sparse") q = p.alloc(80) ket.ctrl(ket.H(q[0]), ket.X)(q[1:]) d = ket.dump(q) end = time() print(d.show()) print(f"Execution Time = {end-begin}s") # |00000000000000000000000000000000000000000000000000000000000000000000000000000000⟩ (50.00%) # 0.707107 ≅ 1/√2 # |11111111111111111111111111111111111111111111111111111111111111111111111111111111⟩ (50.00%) # 0.707107 ≅ 1/√2 # Execution Time = 0.0004601478576660156s Runtime ======= The result of a measurement in Ket, with batch execution, is not immediately computed, enabling Libket to append multiple measurements within the same quantum execution. This enables a division of the Ket runtime into classical and quantum runtime. At the classical runtime, the classical computer executes operations that do not depend on the yet to be available measurement results. At the same time, quantum instructions generate calls to Libket. Libket then uses those calls to build a quantum code with every information needed for quantum execution. The quantum runtime begins when the classical computer needs a result from the quantum computer. At this time, Libket sends the quantum code for execution and waits for the results. Libket is agnostic of the quantum compputer and cannot communicate with it during its execution when using batch execution mode. At the end of the quantum runtime, Libket gets the results from the quantum computer and sends them to the classical runtime, that continues on with its execution until the need for another result from a quantum operation. A quantum execution has three possible types of results, measurement from a :func:`~ket.operations.measure` or :func:`~ket.operations.sample`, expectation value from :func:`~ket.operations.exp_value`, and :class:`~ket.base.QuantumState` from :func:`~ket.operations.dump`, with the last, only possible on simulated quantum executions. Process ======= Every quantum operation communicates with a :class:`~ket.base.Process` inside Libket, which handles the references to the quantum computer and the creation of the quantum code. So every :class:`~ket.base.Quant`, :class:`~ket.base.Measurement`, :class:`~ket.base.Samples`, :class:`~ket.expv.ExpValue`, and :class:`~ket.base.QuantumState` variable belongs to a process. Interaction between processes is not possible. Measurements ============ Ket's :func:`~ket.operations.measure` function returns a :class:`~ket.base.Measurement` variable that holds a reference for the measurement result in the quantum computer. The classical computer can request this information by calling the function :attr:`~ket.base.Measurement.get`, which triggers the quantum execution. After the quantum execution, the :attr:`~ket.base.Measurement.get` attribute can be accessed without triggering another quantum execution. Likewise, the results of :class:`~ket.base.Samples`, :class:`~ket.expv.ExpValue`, and :class:`~ket.base.QuantumState` variables are only available after the quantum execution, and calling a function to read the result will trigger the quantum execution.