Overview

The functionals module provides high-level quantum execution procedures by combining tools from the analog, digital, and core modules. Currently, it includes the following execution functionals:

  • Digital Propagation: Propagates a digital quantum circuit through the backend.

  • Analog Evolution: Simulates analog time evolution of one or more Hamiltonians according to a time-dependent schedule.

  • Quantum Reservoirs: Runs a quantum reservoir pipeline (pre-processing, reservoir dynamics, post-processing) across multiple input layers.

Moreover, it provides more complex functionals that are used to execute more complex algorithms:

  • Variational Programs: Builds parameterized program to be optimized in a hybrid quantum-classical environment.

Architecture Overview

Every functional conforms to the abstract Functional interface. Primitive functionals such as DigitalPropagation and AnalogEvolution also inherit from PrimitiveFunctional, which mixes in the Parameterizable contract. This lets backends query and update symbolic parameters consistently before execution.

Readout is decoupled from functionals: measurement details (shots, observables, state tomography) are specified via readout objects passed to the backend’s execute() method. All primitive functionals return a unified FunctionalResult.

Result Objects

  • FunctionalResult

    The unified result type for all primitive functionals. Access results through: samples for shot counts, probabilities for measurement probabilities, state for the terminal QTensor state (when using with_state_tomography()), and expectation_values for expectation values (when using with_expectation()). When store_intermediate_results=True, intermediate results are available via intermediate_states, intermediate_samples, intermediate_probabilities, and intermediate_expectation_values.

  • VariationalProgramResult

    bundles the optimizer trajectory (optimal cost, parameters, intermediate steps) together with the functional result obtained at convergence.

These objects make post-processing workflows ergonomic. For example, after a digital propagation you can surface the most likely bitstrings:

from qilisdk.digital import Circuit
from qilisdk.backends import QiliSim
from qilisdk.functionals import DigitalPropagation
from qilisdk.readout import Readout

backend = QiliSim()
circuit = Circuit(2)
result = backend.execute(DigitalPropagation(circuit), Readout().with_sampling(nshots=1_000))
print("Most likely outcomes:", result.get_probabilities())