Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for dependency issues caused by 0.14 release #2094

Merged
merged 23 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta"
[tool.cibuildwheel]
manylinux-x86_64-image = "manylinux2014"
manylinux-i686-image = "manylinux2014"
skip = "pp* cp36* cp37* cp38* *musllinux*"
skip = "pp* cp36* cp37* *musllinux*"
test-skip = "cp3*-win32 cp3*-manylinux_i686"
test-command = "python {project}/tools/verify_wheels.py"
# We need to use pre-built versions of Numpy and Scipy in the tests; they have a
Expand Down
20 changes: 16 additions & 4 deletions qiskit_aer/backends/aer_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ def generate_aer_config(
return config


def assemble_circuit(circuit: QuantumCircuit):
def assemble_circuit(circuit: QuantumCircuit, basis_gates=None):
"""assemble circuit object mapped to AER::Circuit"""

num_qubits = circuit.num_qubits
Expand Down Expand Up @@ -687,6 +687,7 @@ def assemble_circuit(circuit: QuantumCircuit):
is_conditional,
conditional_reg,
conditional_expr,
basis_gates,
)
index_map.append(num_of_aer_ops - 1)

Expand Down Expand Up @@ -792,6 +793,7 @@ def _assemble_op(
is_conditional,
conditional_reg,
conditional_expr,
basis_gates,
):
operation = inst.operation
qubits = [qubit_indices[qubit] for qubit in inst.qubits]
Expand All @@ -812,7 +814,7 @@ def _assemble_op(

num_of_aer_ops = 1
# fmt: off
if name in {
if basis_gates is None and name in {
"ccx", "ccz", "cp", "cswap", "csx", "cx", "cy", "cz", "delay", "ecr", "h",
"id", "mcp", "mcphase", "mcr", "mcrx", "mcry", "mcrz", "mcswap", "mcsx",
"mcu", "mcu1", "mcu2", "mcu3", "mcx", "mcx_gray", "mcy", "mcz", "p", "r",
Expand Down Expand Up @@ -912,6 +914,9 @@ def _assemble_op(
aer_circ.mark(qubits, params)
elif name == "qerror_loc":
aer_circ.set_qerror_loc(qubits, label if label else name, conditional_reg, aer_cond_expr)
elif basis_gates is not None and name in basis_gates:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aer C++ library supports only the following gates natively.

"ccx", "ccz", "cp", "cswap", "csx", "cx", "cy", "cz", "delay", "ecr", "h",
"id", "mcp", "mcphase", "mcr", "mcrx", "mcry", "mcrz", "mcswap", "mcsx",
"mcu", "mcu1", "mcu2", "mcu3", "mcx", "mcx_gray", "mcy", "mcz", "p", "r"

If basis_gates is not subset of the above set, simulation will fail. I think it is better to check name is in the above set.

Also, I guess backend.configuration().basis_gate is list and not set. basis_gates should be set because this is one of hot loops.

I think that at the beginning of assemble_circuit(), basis_gates should be re-created as a set (while reducing measure, reset and etc). If None is passed, we can use a default set.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When AerSimulator is made by from_backend() given basis_gates does not contain all the gates Aer supports, Aer should return error

aer_circ.gate(name, qubits, params, [], conditional_reg, aer_cond_expr,
label if label else name)
elif name in ("for_loop", "while_loop", "if_else"):
raise AerError(
"control-flow instructions must be converted " f"to jump and mark instructions: {name}"
Expand All @@ -923,11 +928,12 @@ def _assemble_op(
return num_of_aer_ops


def assemble_circuits(circuits: List[QuantumCircuit]) -> List[AerCircuit]:
def assemble_circuits(circuits: List[QuantumCircuit], basis_gates: list = None) -> List[AerCircuit]:
"""converts a list of Qiskit circuits into circuits mapped AER::Circuit

Args:
circuits: circuit(s) to be converted
basis_gates (list): supported gates to be converted
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned the above, list should be converted to set here.


Returns:
a list of circuits to be run on the Aer backends and
Expand All @@ -947,5 +953,11 @@ def assemble_circuits(circuits: List[QuantumCircuit]) -> List[AerCircuit]:
# Generate AerCircuit from the input circuit
aer_qc_list, idx_maps = assemble_circuits(circuits=[qc])
"""
aer_circuits, idx_maps = zip(*[assemble_circuit(circuit) for circuit in circuits])
if basis_gates is not None:
basis_gates_set = set(basis_gates)
aer_circuits, idx_maps = zip(
*[assemble_circuit(circuit, basis_gates_set) for circuit in circuits]
)
else:
aer_circuits, idx_maps = zip(*[assemble_circuit(circuit) for circuit in circuits])
return list(aer_circuits), list(idx_maps)
4 changes: 3 additions & 1 deletion qiskit_aer/backends/aer_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import copy
import logging
from qiskit.providers import convert_to_target
from qiskit.providers.options import Options
from qiskit.providers.models import QasmBackendConfiguration
from qiskit.providers.backend import BackendV2, BackendV1
Expand All @@ -33,6 +34,7 @@

# pylint: disable=import-error, no-name-in-module, abstract-method
from .controller_wrappers import aer_controller_execute
from .name_mapping import NAME_MAPPING

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -856,7 +858,7 @@ def from_backend(cls, backend, **options):
name = configuration.backend_name
configuration.backend_name = f"aer_simulator_from({name})"

target = None
target = convert_to_target(configuration, properties, None, NAME_MAPPING)
else:
raise TypeError(
"The backend argument requires a BackendV2 or BackendV1 object, "
Expand Down
10 changes: 9 additions & 1 deletion qiskit_aer/backends/aerbackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,11 @@ def target(self):
tgt._coupling_graph = self._coupling_map.graph.copy()
return tgt

def set_max_qubits(self, max_qubits):
"""Set maximun number of qubits to be used for this backend."""
if self._target is not None:
self._configuration.n_qubits = max_qubits

def clear_options(self):
"""Reset the simulator options to default values."""
self._options = self._default_options()
Expand Down Expand Up @@ -445,7 +450,10 @@ def _execute_circuits_job(
# Compile circuits
circuits, noise_model = self._compile(circuits, **run_options)

aer_circuits, idx_maps = assemble_circuits(circuits)
if self._target is not None:
aer_circuits, idx_maps = assemble_circuits(circuits, self.configuration().basis_gates)
else:
aer_circuits, idx_maps = assemble_circuits(circuits)
if parameter_binds:
run_options["parameterizations"] = self._convert_binds(
circuits, parameter_binds, idx_maps
Expand Down
8 changes: 6 additions & 2 deletions qiskit_aer/primitives/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@
Estimator
"""

import qiskit

from .estimator import Estimator
from .estimator_v2 import EstimatorV2
from .sampler import Sampler
from .sampler_v2 import SamplerV2

if not qiskit.__version__.startswith("0."):
from .estimator_v2 import EstimatorV2
from .sampler_v2 import SamplerV2
1 change: 1 addition & 0 deletions qiskit_aer/primitives/estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,7 @@ def _transpile_circuits(self, circuits):
circuit = self._circuits[i].copy()
circuit.measure_all()
num_qubits = circuit.num_qubits
self._backend.set_max_qubits(num_qubits)
circuit = self._transpile(circuit)
bit_map = {bit: index for index, bit in enumerate(circuit.qubits)}
layout = [bit_map[qr[0]] for _, qr, _ in circuit[-num_qubits:]]
Expand Down
15 changes: 10 additions & 5 deletions qiskit_aer/primitives/sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,15 @@ def _preprocess_circuit(circuit: QuantumCircuit):
circuit.save_probabilities_dict(qargs)
return circuit

def _transpile_circuit(self, circuit):
self._backend.set_max_qubits(circuit.num_qubits)
transpiled = transpile(
circuit,
self._backend,
**self._transpile_options,
)
return transpiled

def _transpile(self, circuit_indices: Sequence[int], is_shots_none: bool):
to_handle = [
i for i in set(circuit_indices) if (i, is_shots_none) not in self._transpiled_circuits
Expand All @@ -191,11 +200,7 @@ def _transpile(self, circuit_indices: Sequence[int], is_shots_none: bool):
if is_shots_none:
circuits = (self._preprocess_circuit(circ) for circ in circuits)
if not self._skip_transpilation:
circuits = transpile(
list(circuits),
self._backend,
**self._transpile_options,
)
circuits = (self._transpile_circuit(circ) for circ in circuits)
for i, circuit in zip(to_handle, circuits):
self._transpiled_circuits[(i, is_shots_none)] = circuit

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
fixes:
- |
Fixes for dependency issues caused by release 0.14.

Fix for issue in samplingVector.allocate() when > 63 qubits

Use basis_gates in AerCompiler when AerBackend is made by from_backend

Setting number of qubits before transpile for Primitives V1 (issue #2084)

4 changes: 2 additions & 2 deletions src/simulators/matrix_product_state/matrix_product_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ State::sample_measure_using_apply_measure(const reg_t &qubits, uint_t shots,
for (int_t i = 0; i < static_cast<int_t>(shots); i++) {
temp.initialize(qreg_);
auto single_result = temp.apply_measure_internal(qubits, rnds_list[i]);
all_samples[i] = single_result;
all_samples[i].from_vector(single_result);
}
}
return all_samples;
Expand All @@ -811,7 +811,7 @@ std::vector<SampleVector> State::sample_measure_all(uint_t shots,
#pragma omp parallel for if (getenv("PRL_PROB_MEAS"))
for (int_t i = 0; i < static_cast<int_t>(shots); i++) {
auto single_result = qreg_.sample_measure(shots, rng);
all_samples[i] = single_result;
all_samples[i].from_vector(single_result);
}
return all_samples;
}
Expand Down
5 changes: 1 addition & 4 deletions src/simulators/sample_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,7 @@ void SampleVector::allocate(uint_t n, uint_t base) {
elem_mask_ = (1ull << (elem_shift_bits_ + 1)) - 1;
vec_mask_ = (1ull << vec_shift_bits_) - 1;

uint_t size = n >> vec_shift_bits_;
if (size == 0)
size = 1;
uint_t size = (n + (REG_SIZE >> elem_shift_bits_) - 1) >> vec_shift_bits_;
bits_.resize(size, 0ull);
size_ = n;
}
Expand Down Expand Up @@ -185,7 +183,6 @@ void SampleVector::from_vector_with_map(const reg_t &src, const reg_t &map,
uint_t pos = 0;
uint_t n = REG_SIZE >> elem_shift_bits_;
for (uint_t i = 0; i < bits_.size(); i++) {
uint_t n = REG_SIZE;
uint_t val = 0;
if (n > size_ - pos)
n = size_ - pos;
Expand Down
2 changes: 1 addition & 1 deletion src/simulators/stabilizer/stabilizer_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ std::vector<SampleVector> State::sample_measure(const reg_t &qubits,
auto qreg_cache = BaseState::qreg_;
std::vector<SampleVector> samples(shots);
for (int_t ishot = 0; ishot < shots; ishot++) {
samples[ishot] = apply_measure_and_update(qubits, rng);
samples[ishot].from_vector(apply_measure_and_update(qubits, rng));
BaseState::qreg_ = qreg_cache; // restore pre-measurement data from cache
}
return samples;
Expand Down
19 changes: 19 additions & 0 deletions test/terra/backends/aer_simulator/test_measure.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from test.terra.reference import ref_measure
from qiskit import QuantumCircuit
from qiskit import transpile
import qiskit.quantum_info as qi
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel
from qiskit_aer.noise.errors import ReadoutError, depolarizing_error
Expand Down Expand Up @@ -265,6 +266,24 @@ def test_measure_stablizer_64bit(self, method, device):

self.assertDictAlmostEqual(output, targets, delta=delta * shots)

@supported_methods(["stabilizer"], [65, 127, 433])
def test_measure_sampling_large_ghz_stabilizer(self, method, device, num_qubits):
"""Test sampling measure for large stabilizer circuit"""
shots = 1000
delta = 0.05
qc = QuantumCircuit(num_qubits)
qc.h(0)
for q in range(1, num_qubits):
qc.cx(q - 1, q)
qc.measure_all()
backend = self.backend(method=method)
result = backend.run(qc, shots=shots).result()
counts = result.get_counts()
targets = {}
targets["0" * num_qubits] = shots / 2
targets["1" * num_qubits] = shots / 2
self.assertDictAlmostEqual(counts, targets, delta=delta * shots)

# ---------------------------------------------------------------------
# Test MPS algorithms for measure
# ---------------------------------------------------------------------
Expand Down
Loading