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,
qlbmoffers 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
CircuitRunnerobject uses the information provided in aSimulationConfigto 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
configThe
SimulationConfigcontaining the simulation information.latticeThe
Latticeof the simulated system.reinitializerThe
Reinitializerthat performs the transition between time steps.deviceCurrently ignored.
loggerThe 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_conditionsis either aqlbmQuantumComponent, a QiskitStatevectoror a Qiskit``QuantumCircuit``.The
execution_backendis a QiskitAerBackend.If enabled, the
sampling_backendis a QiskitAerBackend.
Attribute
Summary
configThe
SimulationConfigcontaining the simulation information.latticeThe
Latticeof the simulated system.reinitializerThe
Reinitializerthat performs the transition between time steps.deviceCurrently ignored.
loggerThe performance logger, by default
getLogger("qlbm").Any simulator with a Qiskit
AerBackendinterface can be used as eitherexecution_backendorsampling_backendin 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, recompile_each_step=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.
recompile_each_step (bool)
- 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_conditionsis either aqlbmQuantumComponent, a QulacsQuantumStateor a QulacsQuantumCircuit.The
execution_backendisNone. A QulacsQuantumSimulatorobject is automatically built from the config.If enabled, the
sampling_backendis a QiskitAerBackend. The QulacsQuantumStateis automatically converted to the appropriate Qiskit interface when performing sampling.
Attribute
Summary
configThe
SimulationConfigcontaining the simulation information.latticeThe
Latticeof the simulated system.reinitializerThe
Reinitializerthat performs the transition between time steps.deviceCurrently ignored.
loggerThe 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
Countsrepresentation 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
Reinitializeruses 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-flyCircuitCompilerautomatically 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
latticeThe
Latticeof the simulated system.compilerThe compiler that converts the novel initial conditions circuits.
loggerThe 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.identity_reinitializer.IdentityReinitializer(lattice, compiler, logger=<Logger qlbm (WARNING)>)[source]#
Implementation of the
Reinitializerthat passes along the statevector to the following time step.Useful for the
CQLBMandLQLGAalgorithms. Compatible with bothQiskitRunners andQulacsRunners. 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
latticeThe
Latticeof the simulated system.compilerThe compiler that converts the novel initial conditions circuits.
loggerThe performance logger, by default
getLogger("qlbm")- Parameters:
lattice (Lattice)
compiler (CircuitCompiler)
logger (Logger)
- reinitialize(statevector, counts, backend=None, optimization_level=0)[source]#
Returns the provided
statevectoras a new QiskitInitializeobject 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
Initializeobject.- 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
QiskitRunners andQulacsRunners. 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
latticeThe
SpaceTimeLatticeof the simulated system.compilerThe compiler that converts the novel initial conditions circuits.
loggerThe performance logger, by default
getLogger("qlbm")- Parameters:
lattice (SpaceTimeLattice)
compiler (CircuitCompiler)
logger (Logger)
- reinitialize(statevector, counts, backend, optimization_level=0)[source]#
Converts the input
countsinto a newPointWiseSpaceTimeInitialConditionsobject that can be prepended to the time step circuit to resume simulation.- Parameters:
statevector (Statevector) – Ignored.
counts (Counts) – The counts obtained from
SpacetimeGridVelocityMeasurementat 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
Countoutput 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
Countinto its position and velocity components.Counts are assumed to be obtained from
SpacetimeGridVelocityMeasurementobjects, and split format is the same as the input toPointWiseSpaceTimeInitialConditions.- Parameters:
count (str) – The Qiskit
Countoutput 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
qlbmcircuits to any Qiskit backend, as well as Qulacs.Attribute
Summary
compiler_typeWhich transpiler platform to use. Should be either
"QISKIT"or"TKET".compiler_targetThe platform to which the circuit should adhere. Should be either
"QISKIT"or"QULACS".loggerThe 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
SpaceTimeQLBMalgorithm 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": "D2Q4"}, "geometry": [], }, )
We can first visualize the high-level quantum circuit the
qlbminfers:# 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
qlbmcomponent: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 (
qlbmcomponent 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
Resultobject 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
latticeThe
Latticeof the simulated system.directoryThe directory to which the results outputs data to.
paraview_dirThe subdirectory under
directorywhich stores the Paraview files.output_file_nameThe root name for files containing time step artifacts, by default “step”.
- Parameters:
lattice (Lattice)
directory (str)
output_file_name (str)
- visualize_geometry()[source]#
Creates
stlfiles for each block in the lattice.Output files are formatted as
output_dir/paraview_dir/cube_<x>.stl. The output is created through theShape’sShape.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
vtkvisual representation of the data.- Parameters:
data (np.ndarray | None) – The
np.ndarrayrepresentation 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
Countsformat.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
GridMeasurementprimitives.Attribute
Summary
The
CollisionlessLatticeof the simulated system.The directory to which the results outputs data to.
The root name for files containing time step artifacts, by default “step”.
- Parameters:
lattice (CollisionlessLattice)
directory (str)
output_file_name (str)
-
num_steps:
int# The time step to which this result corresponds.
-
directory:
str# The output directory for the results.
-
output_file_name:
str# The name of the file to output the artifacts to.
-
lattice:
CollisionlessLattice# The lattice the result corresponds to.
- 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
Countsformat.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
SpaceTimeGridVelocityMeasurementprimitives.Attribute
Summary
The
SpaceTimeLatticeof the simulated system.The directory to which the results outputs data to.
The root name for files containing time step artifacts, by default “step”.
- Parameters:
lattice (SpaceTimeLattice)
directory (str)
output_file_name (str)
-
num_steps:
int# The time step to which this result corresponds.
-
directory:
str# The output directory for the results.
-
output_file_name:
str# The name of the file to output the artifacts to.
-
lattice:
SpaceTimeLattice# The lattice the result corresponds to.
- 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
Countsformat.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
SimulationConfigties 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_conditionsThe initial conditions of the simulations. For example,
CollisionlessInitialConditionsorPointWiseSpaceTimeInitialConditions.algorithmThe algorithm that performs the QLBM time step computation. For example,
CQLBMorSpaceTimeQLBM.postprocessingThe quantum component concataned to the
algorithm. UsuallyEmptyPrimitive.measurementThe circuit that samples the quantum state. For example,
GridMeasurementorSpaceTimeGridVelocityMeasurement.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_platformThe platform that the simulation will be carried out on. Either
"QISKIT"or"QULACS".compiler_platformThe platform of the compiler to use. Either
"QISKIT"or"TKET".optimization_levelThe 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_backendThe specific
AerSimulatoruse (if using Qiskit) orNoneif using Qulacs.sampling_backendThe specific
AerSimulatorto use ifstatevector_samplingis enabled.statevector_samplingWhether statevector sampling should be utilized.
Note
Example configuration: simulating
SpaceTimeQLBMwith 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
cfgwill 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
cfgobject 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
CQLBMwith 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
cfgwill 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
cfgobject 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
CircuitCompilerthat can converts the algorithmic attributes to the targetsampling_backendsimulator.- Returns:
A compatible circuit compiler.
- Return type: