Infrastructure#
Infrastructure concerns components of qlbm
that do not directly
implement functionality related to QLBM quantum circuits.
This includes the circuits’ integration with quantum simulators,
compilers, and external tools.
Making good use of such tools and their rapidly expanding ecosystems
is crucial for accelerating QLBM research, as it allows
researchers to focus on algorithm design rather than simulation techniques.
qlbm
currently integrates the core quantum components with the following infrastructure:
Runners allow users to efficiently simulate quantum circuits. In addition to basic simulation,
qlbm
offers features that allow for reinitialization between time steps, among other Performance improvements.Compilers enable users to convert high-level quantum circuits into hardware- or simulator-specific formats, as well as analyze the scalability of available methods.
Results provide an interface between the counts generated by the quantum simulator and Paraview. Information is parsed into standard formats that increase the accessibility of QLBMs.
Simulation Config provides a convenient interface that ties together simulators, compilers, and quantum circuits.
Runners#
- class qlbm.infra.runner.base.CircuitRunner(config, lattice, logger=<Logger qlbm (WARNING)>, device='CPU')[source]#
Base class for all simulator-specific runners.
A
CircuitRunner
object uses the information provided in aSimulationConfig
to efficiently simulate the QLBM circuit. This includes converting the initial conditions into a suitable format, concatenating circuits together, performing reinitialization, and processing results.Attribute
Summary
config
The
SimulationConfig
containing the simulation information.lattice
The
Lattice
of the simulated system.reinitializer
The
Reinitializer
that performs the transition between time steps.device
Currently ignored.
logger
The performance logger, by default
getLogger("qlbm")
.- Parameters:
config (SimulationConfig)
lattice (Lattice)
logger (Logger)
device (str)
- abstract run(num_steps, num_shots, output_directory, output_file_name='step', statevector_snapshots=False)[source]#
Simulates the provided configuration.
- Parameters:
num_steps (int) – The number of time steps to simulate the system for.
num_shots (int) – The number of shots to perform for each time step.
output_directory (str) – The directory to which output will be stored.
output_file_name (str, optional) – The root name for files containing time step artifacts, by default “step”.
statevector_snapshots (bool, optional) – Whether to utilize statevector snapshots, by default False.
- Returns:
The parsed result of the simulation.
- Return type:
- new_result(output_directory, output_file_name)[source]#
Get a new result object for the current runner.
- Parameters:
output_directory (str) – The directory where the result data will be stored.
output_file_name (str) – The file name of the result data within the directory.
- Returns:
An empty result object.
- Return type:
- Raises:
ResultsException – If there is no matching result object for the runner’s lattice.
- new_reinitializer()[source]#
Creates a new reinitializer for a simulated algorithm.
- Returns:
A suitable reinitializer.
- Return type:
- Raises:
ResultsException – If the underlying algorithm does not support reinitialization.
- statevector_to_circuit(statevector)[source]#
Converts a given statevector to a qiskit quantum circuit representation for seamless circuit assembly.
- Parameters:
statevector (Statevector) – The initial condition statevector.
- Returns:
The quantum circuit representation of the statevector.
- Return type:
QiskitQC
- class qlbm.infra.runner.qiskit_runner.QiskitRunner(config, lattice, logger=<Logger qlbm (WARNING)>, device='CPU')[source]#
Qiskit-specific implementation of the
CircuitRunner
.A provided simulation configuration is compatible with this runner if the following conditions are met:
The
initial_conditions
is either aqlbm
QuantumComponent
, a QiskitStatevector
or a Qiskit``QuantumCircuit``.The
execution_backend
is a QiskitAerBackend
.If enabled, the
sampling_backend
is a QiskitAerBackend
.
Attribute
Summary
config
The
SimulationConfig
containing the simulation information.lattice
The
Lattice
of the simulated system.reinitializer
The
Reinitializer
that performs the transition between time steps.device
Currently ignored.
logger
The performance logger, by default
getLogger("qlbm")
.Any simulator with a Qiskit
AerBackend
interface can be used as eitherexecution_backend
orsampling_backend
in the config interface.- Parameters:
config (SimulationConfig)
lattice (Lattice)
logger (Logger)
device (str)
- run(num_steps, num_shots, output_directory, output_file_name='step', statevector_snapshots=False)[source]#
Simulates the provided configuration.
- Parameters:
num_steps (int) – The number of time steps to simulate the system for.
num_shots (int) – The number of shots to perform for each time step.
output_directory (str) – The directory to which output will be stored.
output_file_name (str, optional) – The root name for files containing time step artifacts, by default “step”.
statevector_snapshots (bool, optional) – Whether to utilize statevector snapshots, by default False.
- Returns:
The parsed result of the simulation.
- Return type:
- class qlbm.infra.runner.qulacs_runner.QulacsRunner(config, lattice, logger=<Logger qlbm (WARNING)>, device='CPU')[source]#
Qulacs-specific implementation of the
CircuitRunner
.A provided simulation configuration is compatible with this runner if the following conditions are met:
The
initial_conditions
is either aqlbm
QuantumComponent
, a QulacsQuantumState
or a QulacsQuantumCircuit
.The
execution_backend
isNone
. A QulacsQuantumSimulator
object is automatically built from the config.If enabled, the
sampling_backend
is a QiskitAerBackend
. The QulacsQuantumState
is automatically converted to the appropriate Qiskit interface when performing sampling.
Attribute
Summary
config
The
SimulationConfig
containing the simulation information.lattice
The
Lattice
of the simulated system.reinitializer
The
Reinitializer
that performs the transition between time steps.device
Currently ignored.
logger
The performance logger, by default
getLogger("qlbm")
.- Parameters:
config (SimulationConfig)
lattice (Lattice)
logger (Logger)
device (str)
- run(num_steps, num_shots, output_directory, output_file_name='step', statevector_snapshots=False)[source]#
Simulates the provided configuration.
- Parameters:
num_steps (int) – The number of time steps to simulate the system for.
num_shots (int) – The number of shots to perform for each time step.
output_directory (str) – The directory to which output will be stored.
output_file_name (str, optional) – The root name for files containing time step artifacts, by default “step”.
statevector_snapshots (bool, optional) – Whether to utilize statevector snapshots, by default False.
- Returns:
The parsed result of the simulation.
- Return type:
- get_counts(qulacs_samples, num_bits)[source]#
Converts qulacs samples to qiskit
Counts
.- Parameters:
qulacs_samples (List[int]) – The samples generated through qulacs sampling.
num_bits (int) – The number of bits each sample contains.
- Returns:
The qiskit
Counts
representation of the object.- Return type:
Counts
Performance#
- class qlbm.infra.reinitialize.base.Reinitializer(lattice, compiler, logger=<Logger qlbm (WARNING)>)[source]#
Base class for all algorithm-specific reinitializers.
A
Reinitializer
uses the information at information available at the end of the simulation of 1 or more time steps to new initial conditions for the following time steps. Such information includes the quantum state and counts extracted from it. Novel initial conditions are inferred automatically based on the requirements of the algorithm under simulation, and an on-the-flyCircuitCompiler
automatically converts them to the appropriate format to enable compatibility with the already transpiled circuits. For convenience, all reinitializers provide a uniformreinitialize()
interface, which takes as input both the quantum state and the counts performed during simulation. Its implementation may choose to ignore one of those inputs, depending on the algorithm and implementation.Attribute
Summary
lattice
The
Lattice
of the simulated system.compiler
The compiler that converts the novel initial conditions circuits.
logger
The performance logger, by default
getLogger("qlbm")
- Parameters:
lattice (Lattice)
compiler (CircuitCompiler)
logger (Logger)
- abstract reinitialize(statevector, counts, backend, optimization_level=0)[source]#
Parses the input statevector and counts, constructs a new initial conditions circuit, and transpiles it to the given backend.
- Parameters:
statevector (Statevector) – The statevector at the end of the simulation.
counts (Counts) – The counts extracted from the statevector at the end of the simulation.
backend (AerBackend | None) – The backend to compile to.k
optimization_level (int, optional) – The optimization level to pass to the circuit compiler, by default 0.
- Returns:
The compiled initial conditions circuit to use for the next time step.
- Return type:
QiskitQC | QulacsQC
- class qlbm.infra.reinitialize.collisionless_reinitializer.CollisionlessReinitializer(lattice, compiler, logger=<Logger qlbm (WARNING)>)[source]#
CQLBM
-specific implementation of theReinitializer
.Compatible with both
QiskitRunner
s andQulacsRunner
s. To generate a new set of initial conditions for the CQLBM algorithm, the reinitializer simply returns the quantum state computed at the end of the previous simulation. This allows the reuse of a single quantum circuit for the simulation of arbitrarily many time steps. No copy of the statevector is required.Attribute
Summary
lattice
The
CollisionlessLattice
of the simulated system.compiler
The compiler that converts the novel initial conditions circuits.
logger
The performance logger, by default
getLogger("qlbm")
- Parameters:
lattice (CollisionlessLattice)
compiler (CircuitCompiler)
logger (Logger)
- reinitialize(statevector, counts, backend=None, optimization_level=0)[source]#
Returns the provided
statevector
as a new QiskitInitialize
object that can be prepended to the time step circuit to resume simulation.- Parameters:
statevector (Statevector) – The statevector at the end of the simulation.
counts (Counts) – Ignored.
backend (AerBackend | None) – Ignored.
optimization_level (int, optional) – Ignored.
- Returns:
A Qiskit
Initialize
object.- Return type:
QiskitQC | QulacsQC
- class qlbm.infra.reinitialize.spacetime_reinitializer.SpaceTimeReinitializer(lattice, compiler, logger=<Logger qlbm (WARNING)>)[source]#
SpaceTimeQLBM
-specific implementation of theReinitializer
.Compatible with both
QiskitRunner
s andQulacsRunner
s. To generate a new set of initial conditions for the CQLBM algorithm, the reinitializer simply returns the quantum state computed at the end of the previous simulation. This allows the reuse of a single quantum circuit for the simulation of arbitrarily many time steps. No copy of the statevector is required.Attribute
Summary
lattice
The
SpaceTimeLattice
of the simulated system.compiler
The compiler that converts the novel initial conditions circuits.
logger
The performance logger, by default
getLogger("qlbm")
- Parameters:
lattice (SpaceTimeLattice)
compiler (CircuitCompiler)
logger (Logger)
- reinitialize(statevector, counts, backend, optimization_level=0)[source]#
Converts the input
counts
into a newPointWiseSpaceTimeInitialConditions
object that can be prepended to the time step circuit to resume simulation.- Parameters:
statevector (Statevector) – Ignored.
counts (Counts) – The counts obtained from
SpacetimeGridVelocityMeasurement
at the end of the simulation.backend (AerBackend | None) – The backend used for simulation.
optimization_level (int, optional) – The compiler optimization level.
- Returns:
The suitably compiles initial conditions circuit.
- Return type:
QiskitQC | QulacsQC
- counts_to_velocity_pairs(counts)[source]#
Converts all counts into their grid and velocity components.
- Parameters:
counts (Counts) – The Qiskit
Count
output of the simulation.- Returns:
The input counts split into their grid position and velocity profile.
- Return type:
List[Tuple[Tuple[int, int], Tuple[bool, bool, bool, bool]]]
- split_count(count)[source]#
Splits a given
Count
into its position and velocity components.Counts are assumed to be obtained from
SpacetimeGridVelocityMeasurement
objects, and split format is the same as the input toPointWiseSpaceTimeInitialConditions
.- Parameters:
count (str) – The Qiskit
Count
output of the simulation.- Returns:
The input count split into its grid position and velocity profile.
- Return type:
Tuple[Tuple[int, int], Tuple[bool, bool, bool, bool]]
Compilers#
- class qlbm.infra.compiler.CircuitCompiler(compiler_type, compiler_target, logger=<Logger qlbm (WARNING)>)[source]#
Wrapper for Qiskit and Tket transpilers with flexible targets.
This class provides a uniform interface for compiling
qlbm
circuits to any Qiskit backend, as well as Qulacs.Attribute
Summary
compiler_type
Which transpiler platform to use. Should be either
"QISKIT"
or"TKET"
.compiler_target
The platform to which the circuit should adhere. Should be either
"QISKIT"
or"QULACS"
.logger
The performance logger, by default
getLogger("qlbm")
.Example usage: we will construct an end-to-end QLBM algorithm and compile it to a qiskit simulator using Tket. We begin by constructing a
SpaceTimeQLBM
algorithm for a \(4 \\times 8\) lattice, with one time step.from qlbm.components.spacetime import SpaceTimeQLBM from qlbm.infra import CircuitCompiler from qlbm.lattice import SpaceTimeLattice # Build an example lattice lattice = SpaceTimeLattice( num_timesteps=1, lattice_data={ "lattice": {"dim": {"x": 4, "y": 8}, "velocities": {"x": 2, "y": 2}}, "geometry": [], }, )
We can first visualize the high-level quantum circuit the
qlbm
infers:# Build a complex quantum circuit and visualize it component = SpaceTimeQLBM(lattice=lattice) component.draw("mpl")
(
Source code
,png
,hires.png
,pdf
)To construct the compiler, we only need to specify that we intend to use Tket to compile to a Qiskit simulator:
# Construct a compiler that uses Tket to target Qiskit compiler = CircuitCompiler("TKET", "QISKIT")
Compilation takes a single call to the
compile()
method:from qiskit_aer import AerSimulator # Compiler the circuit to the qiskit AerSimulator compiled_circuit = compiler.compile(component, backend=AerSimulator())
The result is a Qiskit quantum circuit, which we can visualize the same way we would any
qlbm
component:compiled_circuit.draw("mpl")
- Raises:
CompilerException – If the compiler type is not supported.
CompilerException – If the compiler target is not supported.
- Parameters:
compiler_type (str)
compiler_target (str)
logger (Logger)
- compile(compile_object, backend, optimization_level=0)[source]#
Compiles the provided object to the appropriate backend.
- Parameters:
compile_object (QiskitQC | QuantumComponent) – The object (
qlbm
component or quantum) circuit to compile.backend (AerBackend | None) – The backend to compile to.
optimization_level (int, optional) – The compiler optimization level, by default 0.
- Returns:
The compiled circuit.
- Return type:
QulacsQC | QiskitQC
- Raises:
CompilerException – If the optimization level is not available.
CompilerException – If the compiler target and backend are incompatible.
CompilerException – If the compiler platform is not supported.
Results#
- class qlbm.infra.result.base.QBMResult(lattice, directory, output_file_name='step')[source]#
Base class for all algorithm-specific results.
A
Result
object parses the counts extracted from the quantum state at the end of the simulation of some number of time steps. This information is then either translated into a visual representation of the encoded flow field or parsed into a format that is suitable for reinitialization. Results can additionally create visual representations of lattice geometry and save data to disk in compressed formats.Attribute
Summary
lattice
The
Lattice
of the simulated system.directory
The directory to which the results outputs data to.
paraview_dir
The subdirectory under
directory
which stores the Paraview files.output_file_name
The root name for files containing time step artifacts, by default “step”.
- Parameters:
lattice (Lattice)
directory (str)
output_file_name (str)
- visualize_geometry()[source]#
Creates
stl
files for each block in the lattice.Output files are formatted as
output_dir/paraview_dir/cube_<x>.stl
. The output is created through theBlock
’sBlock.stl_mesh()
method.
- save_timestep_array(numpy_res, timestep, create_vis=True, save_counts_array=False)[source]#
Saves the time step array to a file.
- Parameters:
numpy_res (np.ndarray) – The result in array format.
timestep (int) – The time step to which the result corresponds.
create_vis (bool, optional) – Whether to create the visualization, by default True.
save_counts_array (bool, optional) – Whether to save the raw counts object to a CSV file, by default False.
- create_visualization(data, timestep)[source]#
Creates a
vtk
visual representation of the data.- Parameters:
data (np.ndarray | None) – The
np.ndarray
representation of the population density at each grid location.timestep (int) – The time step to which the data corresponds.
- abstract save_timestep_counts(counts, timestep, create_vis=True, save_array=False)[source]#
Saves the time step counts to a file.
- Parameters:
counts (Dict[str, float]) – The result in Qiskit
Counts
format.timestep (int) – The time step to which the result corresponds.k
create_vis (bool, optional) – Whether to create the visualization, by default True.
save_array (bool, optional) – Whether to save the raw counts object to a CSV file, by default False.
- class qlbm.infra.result.collisionless_result.CollisionlessResult(lattice, directory, output_file_name='step')[source]#
CQLBM
-specific implementation of theQBMResult
.Processes counts sampled from
GridMeasurement
primitives.Attribute
Summary
lattice
The
CollisionlessLattice
of the simulated system.directory
The directory to which the results outputs data to.
paraview_dir
The subdirectory under
directory
which stores the Paraview files.output_file_name
The root name for files containing time step artifacts, by default “step”.
- Parameters:
lattice (CollisionlessLattice)
directory (str)
output_file_name (str)
- save_timestep_counts(counts, timestep, create_vis=True, save_array=False)[source]#
Saves the time step counts to a file.
- Parameters:
counts (Dict[str, float]) – The result in Qiskit
Counts
format.timestep (int) – The time step to which the result corresponds.k
create_vis (bool, optional) – Whether to create the visualization, by default True.
save_array (bool, optional) – Whether to save the raw counts object to a CSV file, by default False.
- class qlbm.infra.result.spacetime_result.SpaceTimeResult(lattice, directory, output_file_name='step')[source]#
SpaceTimeQLBM
-specific implementation of theQBMResult
.Processes counts sampled from
SpaceTimeGridVelocityMeasurement
primitives.Attribute
Summary
lattice
The
SpaceTimeLattice
of the simulated system.directory
The directory to which the results outputs data to.
paraview_dir
The subdirectory under
directory
which stores the Paraview files.output_file_name
The root name for files containing time step artifacts, by default “step”.
- Parameters:
lattice (SpaceTimeLattice)
directory (str)
output_file_name (str)
- save_timestep_counts(counts, timestep, create_vis=True, save_array=False)[source]#
Saves the time step counts to a file.
- Parameters:
counts (Dict[str, float]) – The result in Qiskit
Counts
format.timestep (int) – The time step to which the result corresponds.k
create_vis (bool, optional) – Whether to create the visualization, by default True.
save_array (bool, optional) – Whether to save the raw counts object to a CSV file, by default False.
Simulation Config#
- class qlbm.infra.runner.simulation_config.SimulationConfig(initial_conditions, algorithm, postprocessing, measurement, target_platform, compiler_platform, optimization_level, statevector_sampling, execution_backend, sampling_backend, logger=<Logger qlbm (WARNING)>)[source]#
A
SimulationConfig
ties together algorithmic quantum components, circuit compilers, runners, and performance optimizations.This is the most convenient access point for performing simulations with
qlbm
. In total, the config contains 11 relevant class attributes that together allow users to customize their simulations in a declarative manner. For convenience, we split these attributes by the purpose they serve for the simulation workflow.Algorithmic attributes specify the complete, end-to-end, QLBM algorithm. This includes initial conditions, the time step circuit, an optional postprocessing step, and a final measurement procedure.
Algorithmic attributes# Attribute
Description
initial_conditions
The initial conditions of the simulations. For example,
CollisionlessInitialConditions
orPointWiseSpaceTimeInitialConditions
.algorithm
The algorithm that performs the QLBM time step computation. For example,
CQLBM
orSpaceTimeQLBM
.postprocessing
The quantum component concataned to the
algorithm
. UsuallyEmptyPrimitive
.measurement
The circuit that samples the quantum state. For example,
GridMeasurement
orSpaceTimeGridVelocityMeasurement
.Compiler-related attributes govern how compilers convert algorithmic attributes to the appropriate format. All quantum circuits will be compiled using the same settings.
Compiler-related attributes# Attribute
Description
target_platform
The platform that the simulation will be carried out on. Either
"QISKIT"
or"QULACS"
.compiler_platform
The platform of the compiler to use. Either
"QISKIT"
or"TKET"
.optimization_level
The compiler optimization level.
Runner-related attributes prescribe how the simulation should proceede. This includes the specific simulators that will execute the circuits, and performance optimization settings.
Runner-related attributes# Attribute
Description
execution_backend
The specific
AerSimulator
use (if using Qiskit) orNone
if using Qulacs.sampling_backend
The specific
AerSimulator
to use ifstatevector_sampling
is enabled.statevector_sampling
Whether statevector sampling should be utilized.
Note
Example configuration: simulating
SpaceTimeQLBM
with Qiskit. First, we set up the config with the circuits we want to simulate, and the infrastructure we want to use.SimulationConfig( initial_conditions=SpaceTimeInitialConditions( lattice, grid_data=[((1, 5), (True, True, True, True))] ), algorithm=SpaceTimeQLBM(lattice), postprocessing=EmptyPrimitive(lattice), measurement=SpaceTimeGridVelocityMeasurement(lattice), target_platform="QISKIT", compiler_platform="QISKIT", optimization_level=0, statevector_sampling=True, execution_backend=AerSimulator(method="statevector"), sampling_backend=AerSimulator(method="statevector"), )
Once constructed, the
cfg
will figure out the appropriate compiler calls to convert the circuit to the appropriate format. All the user needs to do is call theprepare_for_simulation()
method:cfg.prepare_for_simulation()
The circuits are compiled in-place, which makes it easy to plug in the
cfg
object into aQiskitRunner
:# Create a runner object to simulate the circuit runner = QiskitRunner( cfg, lattice, ) # Simulate the circuits runner.run( 10 2**12, "output_dir", False )
Note
Example configuration: simulating
CQLBM
with Qulacs and Tket.cfg = SimulationConfig( initial_conditions=CollisionlessInitialConditions(lattice, logger), algorithm=CQLBM(lattice, logger), postprocessing=EmptyPrimitive(lattice, logger), measurement=GridMeasurement(lattice, logger), target_platform="QULACS", compiler_platform="TKET", optimization_level=0, statevector_sampling=statevector_sampling, execution_backend=None, sampling_backend=AerSimulator(method="statevector"), logger=logger, )
Once constructed, the
cfg
will figure out the appropriate compiler calls to convert the circuit to the appropriate format. All the user needs to do is call theprepare_for_simulation()
method:cfg.prepare_for_simulation()
The circuits are compiled in-place, which makes it easy to plug in the
cfg
object into aQulacsRunner
:# Create a runner object to simulate the circuit runner = QulacsRunner( cfg, lattice, ) # Simulate the circuits runner.run( 10 2**12, "output_dir", True )
- Parameters:
initial_conditions (Statevector | QuantumCircuit | QuantumState | QuantumCircuit | QuantumComponent)
algorithm (QuantumCircuit | QuantumCircuit | QuantumComponent)
postprocessing (QuantumCircuit | QuantumCircuit | QuantumComponent)
measurement (QuantumCircuit | QuantumComponent)
target_platform (str)
compiler_platform (str)
optimization_level (int)
statevector_sampling (bool)
execution_backend (AerBackend | None)
sampling_backend (AerBackend)
logger (Logger)
- validate()[source]#
Validates the configuration.
This includes the following checks:
The algorithmic attributes are of compatible types.
The target platform is available.
The execution backend (if enabled) is compatible with the target platform.
The sampling backend (if enabled) is compatible with the target platform.
This function simply checks that the provided attributes are suitable - it does not perform any conversions.
- prepare_for_simulation()[source]#
Converts all algorithmic components to the target platform according to the specification, in place.
- Return type:
None
- get_execution_compiler()[source]#
Get the
CircuitCompiler
that can converts the algorithmic attributes to the targetsampling_backend
simulator.- Returns:
A compatible circuit compiler.
- Return type: