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

fix qiskit_device to support Aer v2 conventions #343

Merged
merged 1 commit into from
Oct 27, 2023
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
50 changes: 35 additions & 15 deletions pennylane_qiskit/qiskit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,6 @@ class QiskitDevice(QubitDevice, abc.ABC):
def __init__(self, wires, provider, backend, shots=1024, **kwargs):
super().__init__(wires=wires, shots=shots)

# Keep track if the user specified analytic to be True
if shots is None and backend not in self._state_backends:
# Raise a warning if no shots were specified for a hardware device
warnings.warn(self.hw_analytic_warning_message.format(backend), UserWarning)

self.shots = 1024

self.provider = provider

if isinstance(backend, Backend):
Expand All @@ -181,7 +174,14 @@ def __init__(self, wires, provider, backend, shots=1024, **kwargs):

self.backend_name = _get_backend_name(self._backend)

self._capabilities["returns_state"] = self.backend_name in self._state_backends
# Keep track if the user specified analytic to be True
if shots is None and not self._is_state_backend:
# Raise a warning if no shots were specified for a hardware device
warnings.warn(self.hw_analytic_warning_message.format(backend), UserWarning)

self.shots = 1024

self._capabilities["returns_state"] = self._is_state_backend

# Perform validation against backend
b = self.backend
Expand Down Expand Up @@ -225,6 +225,26 @@ def process_kwargs(self, kwargs):
# Consider the remaining kwargs as keyword arguments to run
self.run_args.update(kwargs)

@property
def _is_state_backend(self):
"""Returns whether this device has a state backend."""
return self.backend_name in self._state_backends or self.backend.options.get("method") in {
"unitary",
"statevector",
}

@property
def _is_statevector_backend(self):
"""Returns whether this device has a statevector backend."""
method = "statevector"
return method in self.backend_name or self.backend.options.get("method") == method

@property
def _is_unitary_backend(self):
"""Returns whether this device has a unitary backend."""
method = "unitary"
return method in self.backend_name or self.backend.options.get("method") == method

def set_transpile_args(self, **kwargs):
"""The transpile argument setter.

Expand Down Expand Up @@ -278,7 +298,7 @@ def create_circuit_object(self, operations, **kwargs):
for circuit in applied_operations:
self._circuit &= circuit

if self.backend_name not in self._state_backends:
if not self._is_state_backend:
# Add measurements if they are needed
for qr, cr in zip(self._reg, self._creg):
self._circuit.measure(qr, cr)
Expand Down Expand Up @@ -357,7 +377,7 @@ def qubit_state_vector_check(self, operation):
DeviceError: If the operation is QubitStateVector or StatePrep
"""
if operation in ("QubitStateVector", "StatePrep"):
if "unitary" in self.backend_name:
if self._is_unitary_backend:
raise DeviceError(
f"The {operation} operation "
"is not supported on the unitary simulator backend."
Expand All @@ -382,7 +402,7 @@ def run(self, qcirc):
self._current_job = self.backend.run(qcirc, shots=self.shots, **self.run_args)
result = self._current_job.result()

if self.backend_name in self._state_backends:
if self._is_state_backend:
self._state = self._get_state(result)

def _get_state(self, result, experiment=None):
Expand All @@ -395,10 +415,10 @@ def _get_state(self, result, experiment=None):
Returns:
array[float]: size ``(2**num_wires,)`` statevector
"""
if "statevector" in self.backend_name:
if self._is_statevector_backend:
state = np.asarray(result.get_statevector(experiment))

elif "unitary" in self.backend_name:
elif self._is_unitary_backend:
unitary = np.asarray(result.get_unitary(experiment))
initial_state = np.zeros([2**self.num_wires])
initial_state[0] = 1
Expand All @@ -422,7 +442,7 @@ def generate_samples(self, circuit=None):
"""

# branch out depending on the type of backend
if self.backend_name in self._state_backends:
if self._is_state_backend:
# software simulator: need to sample from probabilities
return super().generate_samples()

Expand Down Expand Up @@ -491,7 +511,7 @@ def batch_execute(self, circuits, timeout: int = None):
self.tracker.update(executions=1, shots=self.shots)
self.tracker.record()

if self.backend_name in self._state_backends:
if self._is_state_backend:
self._state = self._get_state(result, experiment=circuit_obj)

# generate computational basis samples
Expand Down
4 changes: 2 additions & 2 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ def test_rotation(self, init_state, state_vector_device, shots, tol):

dev = state_vector_device(1)

if "unitary" in dev.backend_name:
if dev._is_unitary_backend:
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(1)
Expand Down Expand Up @@ -480,7 +480,7 @@ def test_noise_applied(self):
bit_flip = aer.noise.pauli_error([("X", 1), ("I", 0)])

# Create a noise model where the RX operation always flips the bit
noise_model.add_all_qubit_quantum_error(bit_flip, ["z"])
noise_model.add_all_qubit_quantum_error(bit_flip, ["z", "rz"])

dev = qml.device("qiskit.aer", wires=2, noise_model=noise_model)

Expand Down
Loading