Skip to content

Commit

Permalink
Merge branch 'master' into dependabot/pip/doc/pygments-2.15.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lillian542 authored Dec 14, 2023
2 parents 12108e0 + bf64212 commit 3babbdf
Show file tree
Hide file tree
Showing 20 changed files with 223 additions and 159 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8
python-version: 3.9

- name: Install dependencies
run: pip install black
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

strategy:
matrix:
python-version: [3.8, 3.9, '3.10', '3.11']
python-version: [3.9, '3.10', '3.11']

steps:
- name: Cancel Previous Runs
Expand Down
20 changes: 13 additions & 7 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
requirements_file: doc/requirements.txt
version: 2

build:
image: latest
sphinx:
configuration: doc/conf.py

python:
version: 3.8
install:
- requirements: doc/requirements.txt
- method: pip
path: .

# Don't build any extra formats
formats:
- none
build:
os: ubuntu-22.04
tools:
python: "3.9"
apt_packages:
- graphviz
80 changes: 79 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Release 0.32.0-dev
# Release 0.34.0-dev

### New features since last release

Expand All @@ -12,10 +12,88 @@

### Bug fixes 🐛

* The kwargs `job_tags` and `session_id` are passed to the correct arguments in the
`circuit_runner` device so that they will be used in the Qiskit backend; these
were previously ignored.
[(#358)](https://github.com/PennyLaneAI/pennylane-qiskit/pull/358)

* In `IBMQSamplerDevice` the `generate_samples` function:
1. gets counts from the nearest probability distribution because
the quasi-distribution may contain negative probabilities.
2. Avoid indexing error.
3. Returns the qubit with Pennylane convention instead of Qiskit convention.
[(#357)](https://github.com/PennyLaneAI/pennylane-qiskit/pull/357)


### Contributors ✍️

This release contains contributions from (in alphabetical order):

Lillian Frederiksen
Francesco Scala


---
# Release 0.33.1

### Improvements 🛠

* Stop using the now-deprecated `tape.is_sampled` property.
[(#348)](https://github.com/PennyLaneAI/pennylane-qiskit/pull/348)

### Bug fixes 🐛

* Update conversion of PennyLane to Qiskit operators to accommodate
the addition of Singleton classes in the newest version of Qiskit.
[(#347)](https://github.com/PennyLaneAI/pennylane-qiskit/pull/347)

### Contributors ✍️

This release contains contributions from (in alphabetical order):

Lillian Frederiksen,
Matthew Silverman

---
# Release 0.33.0

### Improvements 🛠

* Logic updated to support Aer V2 device naming conventions.
[(#343)](https://github.com/PennyLaneAI/pennylane-qiskit/pull/343)

### Breaking changes 💔

* The old return type system has been removed.
[(#331)](https://github.com/PennyLaneAI/pennylane-qiskit/pull/331)

### Contributors ✍️

This release contains contributions from (in alphabetical order):

Mudit Pandey,
Matthew Silverman

---
# Release 0.32.0

### Improvements 🛠

* Added support for `qml.StatePrep` as a state preparation operation.
[(#326)](https://github.com/PennyLaneAI/pennylane-qiskit/pull/326)

### Breaking changes 💔

* Support for Python 3.8 has been removed.
[(#328)](https://github.com/PennyLaneAI/pennylane-qiskit/pull/328)

### Contributors ✍️

This release contains contributions from (in alphabetical order):

Mudit Pandey,
Jay Soni,

---
# Release 0.31.0

Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PennyLane-Qiskit Plugin
#######################

.. image:: https://img.shields.io/github/workflow/status/PennyLaneAI/pennylane-qiskit/Tests/master?logo=github&style=flat-square
.. image:: https://img.shields.io/github/actions/workflow/status/PennyLaneAI/pennylane-qiskit/tests.yml?branch=master&logo=github&style=flat-square
:alt: GitHub Workflow Status (branch)
:target: https://github.com/PennyLaneAI/pennylane-qiskit/actions?query=workflow%3ATests

Expand Down Expand Up @@ -53,7 +53,7 @@ Features
Installation
============

This plugin requires Python version 3.8 and above, as well as PennyLane and Qiskit.
This plugin requires Python version 3.9 and above, as well as PennyLane and Qiskit.
Installation of this plugin, as well as all dependencies, can be done using ``pip``:

.. code-block:: bash
Expand Down
3 changes: 1 addition & 2 deletions doc/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ dc-qiskit-algorithms==0.0.14
docutils==0.19
ipykernel==6.22.0
jinja2==3.0.3
mthree==1.1.0
nbsphinx==0.9.1
pennylane==0.30.0
pybind11==2.9.2
pygments==2.15.0
pygments==2.17.2
pygments-github-lexers==0.0.5
qiskit==0.44.0
qiskit-aer==0.12.2
Expand Down
2 changes: 1 addition & 1 deletion pennylane_qiskit/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "0.32.0-dev"
__version__ = "0.34.0-dev"
7 changes: 4 additions & 3 deletions pennylane_qiskit/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,15 @@ def execute_supported_operation(operation_name: str, parameters: list, wires: li
"""Utility function that executes an operation that is natively supported by PennyLane.
Args:
operation_name (str): wires specified for the template
operation_name (str): Name of the PL operator to be executed
parameters (str): parameters of the operation that will be executed
wires (list): wires of the operation
"""
operation = getattr(pennylane_ops, operation_name)

if not parameters:
operation(wires=wires)
elif operation_name == "QubitStateVector":
elif operation_name in ["QubitStateVector", "StatePrep"]:
operation(np.array(parameters), wires=wires)
else:
operation(*parameters, wires=wires)
Expand Down Expand Up @@ -179,7 +179,8 @@ def _function(params: dict = None, wires: list = None):

# Processing the dictionary of parameters passed
for op, qargs, cargs in qc.data:
instruction_name = op.__class__.__name__
# the new Singleton classes have different names than the objects they represent, but base_class.__name__ still matches
instruction_name = getattr(op, "base_class", op.__class__).__name__

operation_wires = [wire_map[hash(qubit)] for qubit in qargs]

Expand Down
84 changes: 52 additions & 32 deletions pennylane_qiskit/qiskit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,19 @@
import warnings

import numpy as np
import pennylane
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
from qiskit import extensions as ex
from qiskit.compiler import transpile
from qiskit.converters import circuit_to_dag, dag_to_circuit
from qiskit.providers import Backend, QiskitBackendNotFoundError

from pennylane import QubitDevice, DeviceError
from pennylane.measurements import SampleMP, CountsMP, ClassicalShadowMP, ShadowExpvalMP

from ._version import __version__

SAMPLE_TYPES = (SampleMP, CountsMP, ClassicalShadowMP, ShadowExpvalMP)


QISKIT_OPERATION_MAP_SELF_ADJOINT = {
# native PennyLane operations also native to qiskit
Expand All @@ -54,6 +56,7 @@
"CRZ": ex.CRZGate,
"PhaseShift": ex.PhaseGate,
"QubitStateVector": ex.Initialize,
"StatePrep": ex.Initialize,
"Toffoli": ex.CCXGate,
"QubitUnitary": ex.UnitaryGate,
"U1": ex.U1Gate,
Expand Down Expand Up @@ -155,13 +158,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 +177,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 +228,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 +301,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 @@ -328,12 +351,12 @@ def apply_operations(self, operations):
split_op = operation.split("Adjoint(")

if adjoint:
if split_op[1] in ("QubitUnitary)", "QubitStateVector)"):
if split_op[1] in ("QubitUnitary)", "QubitStateVector)", "StatePrep)"):
# Need to revert the order of the quantum registers used in
# Qiskit such that it matches the PennyLane ordering
qregs = list(reversed(qregs))
else:
if split_op[0] in ("QubitUnitary", "QubitStateVector"):
if split_op[0] in ("QubitUnitary", "QubitStateVector", "StatePrep"):
# Need to revert the order of the quantum registers used in
# Qiskit such that it matches the PennyLane ordering
qregs = list(reversed(qregs))
Expand All @@ -348,18 +371,18 @@ def apply_operations(self, operations):
return circuits

def qubit_state_vector_check(self, operation):
"""Input check for the the QubitStateVector operation.
"""Input check for the StatePrepBase operations.
Args:
operation (pennylane.Operation): operation to be checked
Raises:
DeviceError: If the operation is QubitStateVector
DeviceError: If the operation is QubitStateVector or StatePrep
"""
if operation == "QubitStateVector":
if "unitary" in self.backend_name:
if operation in ("QubitStateVector", "StatePrep"):
if self._is_unitary_backend:
raise DeviceError(
"The QubitStateVector operation "
f"The {operation} operation "
"is not supported on the unitary simulator backend."
)

Expand All @@ -382,7 +405,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 +418,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 +445,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,22 +514,19 @@ 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
if self.shots is not None or circuit.is_sampled:
if self.shots is not None or any(
isinstance(m, SAMPLE_TYPES) for m in circuit.measurements
):
self._samples = self.generate_samples(circuit_obj)

if not pennylane.active_return():
res = self._statistics_legacy(circuit)
res = np.asarray(res)
results.append(res)
else:
res = self.statistics(circuit)
single_measurement = len(circuit.measurements) == 1
res = res[0] if single_measurement else tuple(res)
results.append(res)
res = self.statistics(circuit)
single_measurement = len(circuit.measurements) == 1
res = res[0] if single_measurement else tuple(res)
results.append(res)

if self.tracker.active:
self.tracker.update(batches=1, batch_len=len(circuits))
Expand Down
Loading

0 comments on commit 3babbdf

Please sign in to comment.