qiskit-aer/qiskit_aer/backends/backend_utils.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

561 lines
13 KiB
Python
Raw Normal View History

# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
# pylint: disable=invalid-name
"""
Qiskit Aer simulator backend utils
"""
import os
from math import log2
from qiskit.utils import local_hardware_info
from qiskit.circuit import QuantumCircuit
from qiskit.compiler import assemble
2021-08-24 06:32:20 +08:00
from qiskit.qobj import QasmQobjInstruction
from qiskit.result import ProbDistribution
from qiskit.quantum_info import Clifford
from .compatibility import Statevector, DensityMatrix, StabilizerState, Operator, SuperOp
# Available system memory
SYSTEM_MEMORY_GB = local_hardware_info()["memory"]
# Max number of qubits for complex double statevector
# given available system memory
MAX_QUBITS_STATEVECTOR = int(log2(SYSTEM_MEMORY_GB * (1024**3) / 16))
# Location where we put external libraries that will be
# loaded at runtime by the simulator extension
LIBRARY_DIR = os.path.dirname(__file__)
2021-08-24 06:32:20 +08:00
LEGACY_METHOD_MAP = {
"statevector_cpu": ("statevector", "CPU"),
"statevector_gpu": ("statevector", "GPU"),
"statevector_thrust": ("statevector", "Thrust"),
"density_matrix_cpu": ("density_matrix", "CPU"),
"density_matrix_gpu": ("density_matrix", "GPU"),
"density_matrix_thrust": ("density_matrix", "Thrust"),
"unitary_cpu": ("unitary", "CPU"),
"unitary_gpu": ("unitary", "GPU"),
"unitary_thrust": ("unitary", "Thrust"),
}
BASIS_GATES = {
"statevector": sorted(
[
"u1",
"u2",
"u3",
"u",
"p",
"r",
"rx",
"ry",
"rz",
"id",
"x",
"y",
"z",
"h",
"s",
"sdg",
"sx",
"sxdg",
"t",
"tdg",
"swap",
"cx",
"cy",
"cz",
"csx",
"cp",
"cu",
"cu1",
"cu2",
"cu3",
"rxx",
"ryy",
"rzz",
"rzx",
"ccx",
"cswap",
"mcx",
"mcy",
"mcz",
"mcsx",
"mcp",
"mcphase",
"mcu",
"mcu1",
"mcu2",
"mcu3",
"mcrx",
"mcry",
"mcrz",
"mcr",
"mcswap",
"unitary",
"diagonal",
"multiplexer",
"initialize",
"delay",
"pauli",
"mcx_gray",
"ecr",
]
),
"density_matrix": sorted(
[
"u1",
"u2",
"u3",
"u",
"p",
"r",
"rx",
"ry",
"rz",
"id",
"x",
"y",
"z",
"h",
"s",
"sdg",
"sx",
"sxdg",
"t",
"tdg",
"swap",
"cx",
"cy",
"cz",
"cp",
"cu1",
"rxx",
"ryy",
"rzz",
"rzx",
"ccx",
"unitary",
"diagonal",
"delay",
"pauli",
"ecr",
]
),
"matrix_product_state": sorted(
[
"u1",
"u2",
"u3",
"u",
"p",
"cp",
"cx",
"cy",
"cz",
"id",
"x",
"y",
"z",
"h",
"s",
"sdg",
"sx",
"sxdg",
"t",
"tdg",
"swap",
"ccx",
"unitary",
"roerror",
"delay",
"pauli",
"r",
"rx",
"ry",
"rz",
"rxx",
"ryy",
"rzz",
"rzx",
"csx",
"cswap",
"diagonal",
"initialize",
]
),
"stabilizer": sorted(
[
"id",
"x",
"y",
"z",
"h",
"s",
"sdg",
"sx",
"sxdg",
"cx",
"cy",
"cz",
"swap",
"delay",
"pauli",
"ecr",
]
),
"extended_stabilizer": sorted(
[
"cx",
"cz",
"id",
"x",
"y",
"z",
"h",
"s",
"sdg",
"sx",
"sxdg",
"swap",
"u0",
"t",
"tdg",
"u1",
"p",
"ccx",
"ccz",
"delay",
"pauli",
]
),
"unitary": sorted(
[
"u1",
"u2",
"u3",
"u",
"p",
"r",
"rx",
"ry",
"rz",
"id",
"x",
"y",
"z",
"h",
"s",
"sdg",
"sx",
"sxdg",
"t",
"tdg",
"swap",
"cx",
"cy",
"cz",
"csx",
"cp",
"cu",
"cu1",
"cu2",
"cu3",
"rxx",
"ryy",
"rzz",
"rzx",
"ccx",
"cswap",
"mcx",
"mcy",
"mcz",
"mcsx",
"mcp",
"mcphase",
"mcu",
"mcu1",
"mcu2",
"mcu3",
"mcrx",
"mcry",
"mcrz",
"mcr",
"mcswap",
"unitary",
"diagonal",
"multiplexer",
"delay",
"pauli",
"ecr",
]
),
"superop": sorted(
[
"u1",
"u2",
"u3",
"u",
"p",
"r",
"rx",
"ry",
"rz",
"id",
"x",
"y",
"z",
"h",
"s",
"sdg",
"sx",
"sxdg",
"t",
"tdg",
"swap",
"cx",
"cy",
"cz",
"cp",
"cu1",
"rxx",
"ryy",
"rzz",
"rzx",
"ccx",
"unitary",
"diagonal",
"delay",
"pauli",
]
),
"tensor_network": sorted(
[
"u1",
"u2",
"u3",
"u",
"p",
"r",
"rx",
"ry",
"rz",
"id",
"x",
"y",
"z",
"h",
"s",
"sdg",
"sx",
"sxdg",
"t",
"tdg",
"swap",
"cx",
"cy",
"cz",
"csx",
"cp",
"cu",
"cu1",
"cu2",
"cu3",
"rxx",
"ryy",
"rzz",
"rzx",
"ccx",
"cswap",
"mcx",
"mcy",
"mcz",
"mcsx",
"mcp",
"mcphase",
"mcu",
"mcu1",
"mcu2",
"mcu3",
"mcrx",
"mcry",
"mcrz",
"mcr",
"mcswap",
"unitary",
"diagonal",
"multiplexer",
"initialize",
"delay",
"pauli",
"mcx_gray",
]
),
}
# Automatic method basis gates are the union of statevector,
# density matrix, and stabilizer methods
BASIS_GATES[None] = BASIS_GATES["automatic"] = sorted(
set(BASIS_GATES["statevector"])
.union(BASIS_GATES["stabilizer"])
.union(BASIS_GATES["density_matrix"])
.union(BASIS_GATES["matrix_product_state"])
.union(BASIS_GATES["unitary"])
.union(BASIS_GATES["superop"])
.union(BASIS_GATES["tensor_network"])
)
Simulate `QuantumCircuit` without QObj (#1717) With this commit, Aer simulates `QuantumCircuit` without converting it to QObj. Previously, QObj is generated from `QuantumCircuit` objects in python, and then C++ parses QObj to construct own circuit representation `AER::Circuit` for simulation. Now, Aer binds this `AER::Circuit` with a python class `AerCircuit` and directly generates from `QuantumCircuit` to `AerCircuit`. In addition, configuration for simulation is changed from json to `AerConfig` that be bound to `AER::Config`. This commit will improve performance of low-qubit simulation without any modification of application codes. * add AerCircuit and a path to run simulation without QObj * Remove AerOp from AerCircuit * fix lint errors * revert qobj deprecation * fix executor specification in AerBackend * fix bugs in direct execution * set final operation in AerCircuit * fix lint errors * use AerJob and add reno * support directly-added qubits * fix qobj execution * fix qobj execution, contd. * fix set state with a matrix * inline malloc in matrix * rename malloc_array in AER::Vector to resolve conflicts of signature * rename methods to handle QuantumCircuit in AerBackend and deprecate AerJob.qobj() * simplify AerCircuit * avoid pickling of AerCircuit in assemble_circuits * back _execute_circuits as abstract method * introduce AER::Config to reduce JSON overheads for configuration * fix a bug in get_value to load config * enable AerConfig * fix lint * deprecate backend.run(validate=True) and clean codes in AerBackend * add assertion in test_auto_method * fix bugs in last commits * correct test cases to test auto option
2023-03-09 00:21:15 +08:00
def cpp_execute_qobj(controller, qobj):
"""Execute qobj on C++ controller wrapper"""
# Location where we put external libraries that will be
# loaded at runtime by the simulator extension
qobj.config.library_dir = LIBRARY_DIR
return controller(qobj)
Simulate `QuantumCircuit` without QObj (#1717) With this commit, Aer simulates `QuantumCircuit` without converting it to QObj. Previously, QObj is generated from `QuantumCircuit` objects in python, and then C++ parses QObj to construct own circuit representation `AER::Circuit` for simulation. Now, Aer binds this `AER::Circuit` with a python class `AerCircuit` and directly generates from `QuantumCircuit` to `AerCircuit`. In addition, configuration for simulation is changed from json to `AerConfig` that be bound to `AER::Config`. This commit will improve performance of low-qubit simulation without any modification of application codes. * add AerCircuit and a path to run simulation without QObj * Remove AerOp from AerCircuit * fix lint errors * revert qobj deprecation * fix executor specification in AerBackend * fix bugs in direct execution * set final operation in AerCircuit * fix lint errors * use AerJob and add reno * support directly-added qubits * fix qobj execution * fix qobj execution, contd. * fix set state with a matrix * inline malloc in matrix * rename malloc_array in AER::Vector to resolve conflicts of signature * rename methods to handle QuantumCircuit in AerBackend and deprecate AerJob.qobj() * simplify AerCircuit * avoid pickling of AerCircuit in assemble_circuits * back _execute_circuits as abstract method * introduce AER::Config to reduce JSON overheads for configuration * fix a bug in get_value to load config * enable AerConfig * fix lint * deprecate backend.run(validate=True) and clean codes in AerBackend * add assertion in test_auto_method * fix bugs in last commits * correct test cases to test auto option
2023-03-09 00:21:15 +08:00
def cpp_execute_circuits(controller, aer_circuits, noise_model, config):
"""Execute aer circuits on C++ controller wrapper"""
# Location where we put external libraries that will be
# loaded at runtime by the simulator extension
config.library_dir = LIBRARY_DIR
noise_model = noise_model.to_dict(serializable=True) if noise_model else {}
return controller.execute(aer_circuits, noise_model, config)
def available_methods(controller, methods, devices):
"""Check available simulation methods by running a dummy circuit."""
# Test methods are available using the controller
dummy_circ = QuantumCircuit(1)
dummy_circ.i(0)
valid_methods = []
for device in devices:
for method in methods:
if method not in valid_methods:
qobj = assemble(
dummy_circ, optimization_level=0, shots=1, method=method, device=device
)
Simulate `QuantumCircuit` without QObj (#1717) With this commit, Aer simulates `QuantumCircuit` without converting it to QObj. Previously, QObj is generated from `QuantumCircuit` objects in python, and then C++ parses QObj to construct own circuit representation `AER::Circuit` for simulation. Now, Aer binds this `AER::Circuit` with a python class `AerCircuit` and directly generates from `QuantumCircuit` to `AerCircuit`. In addition, configuration for simulation is changed from json to `AerConfig` that be bound to `AER::Config`. This commit will improve performance of low-qubit simulation without any modification of application codes. * add AerCircuit and a path to run simulation without QObj * Remove AerOp from AerCircuit * fix lint errors * revert qobj deprecation * fix executor specification in AerBackend * fix bugs in direct execution * set final operation in AerCircuit * fix lint errors * use AerJob and add reno * support directly-added qubits * fix qobj execution * fix qobj execution, contd. * fix set state with a matrix * inline malloc in matrix * rename malloc_array in AER::Vector to resolve conflicts of signature * rename methods to handle QuantumCircuit in AerBackend and deprecate AerJob.qobj() * simplify AerCircuit * avoid pickling of AerCircuit in assemble_circuits * back _execute_circuits as abstract method * introduce AER::Config to reduce JSON overheads for configuration * fix a bug in get_value to load config * enable AerConfig * fix lint * deprecate backend.run(validate=True) and clean codes in AerBackend * add assertion in test_auto_method * fix bugs in last commits * correct test cases to test auto option
2023-03-09 00:21:15 +08:00
result = cpp_execute_qobj(controller, qobj)
if result.get("success", False):
valid_methods.append(method)
2021-08-24 06:32:20 +08:00
return tuple(valid_methods)
def available_devices(controller, devices):
"""Check available simulation devices by running a dummy circuit."""
# Test methods are available using the controller
dummy_circ = QuantumCircuit(1)
dummy_circ.i(0)
valid_devices = []
for device in devices:
qobj = assemble(
dummy_circ, optimization_level=0, shots=1, method="statevector", device=device
)
Simulate `QuantumCircuit` without QObj (#1717) With this commit, Aer simulates `QuantumCircuit` without converting it to QObj. Previously, QObj is generated from `QuantumCircuit` objects in python, and then C++ parses QObj to construct own circuit representation `AER::Circuit` for simulation. Now, Aer binds this `AER::Circuit` with a python class `AerCircuit` and directly generates from `QuantumCircuit` to `AerCircuit`. In addition, configuration for simulation is changed from json to `AerConfig` that be bound to `AER::Config`. This commit will improve performance of low-qubit simulation without any modification of application codes. * add AerCircuit and a path to run simulation without QObj * Remove AerOp from AerCircuit * fix lint errors * revert qobj deprecation * fix executor specification in AerBackend * fix bugs in direct execution * set final operation in AerCircuit * fix lint errors * use AerJob and add reno * support directly-added qubits * fix qobj execution * fix qobj execution, contd. * fix set state with a matrix * inline malloc in matrix * rename malloc_array in AER::Vector to resolve conflicts of signature * rename methods to handle QuantumCircuit in AerBackend and deprecate AerJob.qobj() * simplify AerCircuit * avoid pickling of AerCircuit in assemble_circuits * back _execute_circuits as abstract method * introduce AER::Config to reduce JSON overheads for configuration * fix a bug in get_value to load config * enable AerConfig * fix lint * deprecate backend.run(validate=True) and clean codes in AerBackend * add assertion in test_auto_method * fix bugs in last commits * correct test cases to test auto option
2023-03-09 00:21:15 +08:00
result = cpp_execute_qobj(controller, qobj)
if result.get("success", False):
valid_devices.append(device)
2021-08-24 06:32:20 +08:00
return tuple(valid_devices)
def add_final_save_instruction(qobj, state):
"""Add final save state instruction to all experiments in a qobj."""
def save_inst(num_qubits):
"""Return n-qubit save statevector inst"""
return QasmQobjInstruction(
name=f"save_{state}",
qubits=list(range(num_qubits)),
label=f"{state}",
snapshot_type="single",
)
for exp in qobj.experiments:
num_qubits = exp.config.n_qubits
exp.instructions.append(save_inst(num_qubits))
return qobj
Simulate `QuantumCircuit` without QObj (#1717) With this commit, Aer simulates `QuantumCircuit` without converting it to QObj. Previously, QObj is generated from `QuantumCircuit` objects in python, and then C++ parses QObj to construct own circuit representation `AER::Circuit` for simulation. Now, Aer binds this `AER::Circuit` with a python class `AerCircuit` and directly generates from `QuantumCircuit` to `AerCircuit`. In addition, configuration for simulation is changed from json to `AerConfig` that be bound to `AER::Config`. This commit will improve performance of low-qubit simulation without any modification of application codes. * add AerCircuit and a path to run simulation without QObj * Remove AerOp from AerCircuit * fix lint errors * revert qobj deprecation * fix executor specification in AerBackend * fix bugs in direct execution * set final operation in AerCircuit * fix lint errors * use AerJob and add reno * support directly-added qubits * fix qobj execution * fix qobj execution, contd. * fix set state with a matrix * inline malloc in matrix * rename malloc_array in AER::Vector to resolve conflicts of signature * rename methods to handle QuantumCircuit in AerBackend and deprecate AerJob.qobj() * simplify AerCircuit * avoid pickling of AerCircuit in assemble_circuits * back _execute_circuits as abstract method * introduce AER::Config to reduce JSON overheads for configuration * fix a bug in get_value to load config * enable AerConfig * fix lint * deprecate backend.run(validate=True) and clean codes in AerBackend * add assertion in test_auto_method * fix bugs in last commits * correct test cases to test auto option
2023-03-09 00:21:15 +08:00
def add_final_save_op(aer_circuits, state):
"""Add final save state op to all experiments in a qobj."""
for aer_circuit in aer_circuits:
num_qubits = aer_circuit.num_qubits
aer_circuit.save_state(list(range(num_qubits)), f"save_{state}", "single", state)
return aer_circuits
2021-08-24 06:32:20 +08:00
def map_legacy_method_options(qobj):
"""Map legacy method names of qasm simulator to aer simulator options"""
method = getattr(qobj.config, "method", None)
if method in LEGACY_METHOD_MAP:
qobj.config.method, qobj.config.device = LEGACY_METHOD_MAP[method]
return qobj
Simulate `QuantumCircuit` without QObj (#1717) With this commit, Aer simulates `QuantumCircuit` without converting it to QObj. Previously, QObj is generated from `QuantumCircuit` objects in python, and then C++ parses QObj to construct own circuit representation `AER::Circuit` for simulation. Now, Aer binds this `AER::Circuit` with a python class `AerCircuit` and directly generates from `QuantumCircuit` to `AerCircuit`. In addition, configuration for simulation is changed from json to `AerConfig` that be bound to `AER::Config`. This commit will improve performance of low-qubit simulation without any modification of application codes. * add AerCircuit and a path to run simulation without QObj * Remove AerOp from AerCircuit * fix lint errors * revert qobj deprecation * fix executor specification in AerBackend * fix bugs in direct execution * set final operation in AerCircuit * fix lint errors * use AerJob and add reno * support directly-added qubits * fix qobj execution * fix qobj execution, contd. * fix set state with a matrix * inline malloc in matrix * rename malloc_array in AER::Vector to resolve conflicts of signature * rename methods to handle QuantumCircuit in AerBackend and deprecate AerJob.qobj() * simplify AerCircuit * avoid pickling of AerCircuit in assemble_circuits * back _execute_circuits as abstract method * introduce AER::Config to reduce JSON overheads for configuration * fix a bug in get_value to load config * enable AerConfig * fix lint * deprecate backend.run(validate=True) and clean codes in AerBackend * add assertion in test_auto_method * fix bugs in last commits * correct test cases to test auto option
2023-03-09 00:21:15 +08:00
def map_legacy_method_config(config):
"""Map legacy method names of qasm simulator to aer simulator options"""
method = config.method
if method in LEGACY_METHOD_MAP:
config.method, config.device = LEGACY_METHOD_MAP[method]
return config
def format_save_type(data, save_type, save_subtype):
"""Format raw simulator result data based on save type."""
init_fns = {
"save_statevector": Statevector,
"save_density_matrix": DensityMatrix,
"save_unitary": Operator,
"save_superop": SuperOp,
"save_stabilizer": (lambda data: StabilizerState(Clifford.from_dict(data))),
"save_clifford": Clifford.from_dict,
"save_probabilities_dict": ProbDistribution,
}
# Non-handled cases return raw data
if save_type not in init_fns:
return data
if save_subtype in ["list", "c_list"]:
def func(data):
init_fn = init_fns[save_type]
return [init_fn(i) for i in data]
else:
func = init_fns[save_type]
# Conditional save
if save_subtype[:2] == "c_":
return {key: func(val) for key, val in data.items()}
return func(data)
def circuit_optypes(circuit):
"""Return set of all operation types and parent types in a circuit."""
if not isinstance(circuit, QuantumCircuit):
return set()
optypes = set()
for inst, _, _ in circuit._data:
optypes.update(type(inst).mro())
optypes.discard(object)
return optypes