Skip to content

Commit

Permalink
0.4.2 patch release (#234)
Browse files Browse the repository at this point in the history
* adding sympy as an explicit requirement (#233)

* Add warning for JAX versions on import of Dynamics (#232)

* Add probability normalization to DynamicsBackend sampling routine (#239)

* Add warning if digital carrier exceeds Nyquist frequency in pulse -> signal conversion (#242)

* Fix bug with carrier_freq being a JAX tracer if envelope is constant in Signal (#247)

* Remove subsystem_labels option from DynamicsBackend (#248)

* Rename subsystem_dims Dict to subsystem_dims_dict (#250)

* Fix ClassicalRegister counting in DynamicsBackend (#252)

* temporary fix for docs (#253)

* Drop support for backendV2 in from_backend (#249)

* incrementing version number

* cleaning up reno files

---------

Co-authored-by: Kento Ueda <38037695+to24toro@users.noreply.github.com>
  • Loading branch information
DanPuzzuoli and to24toro authored Aug 8, 2023
1 parent 807edf9 commit d217616
Show file tree
Hide file tree
Showing 26 changed files with 447 additions and 121 deletions.
6 changes: 5 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# The short X.Y version
version = ''
# The full version, including alpha/beta/rc tags
release = '0.4.1'
release = '0.4.2'

extensions = [
'sphinx.ext.napoleon',
Expand Down Expand Up @@ -82,3 +82,7 @@
nbsphinx_execute = 'always'
nbsphinx_widgets_path = ''
exclude_patterns = ['_build', '**.ipynb_checkpoints']

# this is tied to the temporary restriction to JAX versions <=0.4.6. See issue #190
import os
os.environ["JAX_JIT_PJIT_API_MERGE"] = "0"
153 changes: 152 additions & 1 deletion docs/release_notes.rst
Original file line number Diff line number Diff line change
@@ -1 +1,152 @@
.. release-notes:: Release Notes
=============
Release Notes
=============

.. _Release Notes_0.4.1-12:

0.4.1-12
========

.. _Release Notes_0.4.1-12_Prelude:

Prelude
-------

.. releasenotes/notes/patch-0.4.2-6a7c7bf380e54187.yaml @ None
Qiskit Dynamics 0.4.2 is an incremental release with minor bug fixes and additional warnings to help guide users through issues.


.. _Release Notes_0.4.1-12_Upgrade Notes:

Upgrade Notes
-------------

.. releasenotes/notes/subsystem_labels-removal-9fcc71c310eff220.yaml @ b'cf256192ce1c0ef7c2f4c696d9be64234b48b68f'
- The ``subsystem_labels`` option has been removed from the :class:`.DynamicsBackend`. This
removal impacts some technical aspects of the backend returned by
:meth:`.DynamicsBackend.from_backend` when the ``subsystem_list`` argument is used. Using the
``subsystem_list`` argument with :meth:`.DynamicsBackend.from_backend` restricts the internally
constructed model to the qubits in ``subsystem_list``. When doing so previously, the option
``subsystem_labels`` would be set to ``subsystem_labels``, and ``subsystem_dims`` would record
only the dimensions for the systems in ``subsystem_labels``. To account for the fact that
``subsystem_labels`` no longer exists, :meth:`.DynamicsBackend.from_backend` now constructs
``subsystem_dims`` to list a dimension for all of the qubits in the original backend, however
now the dimensions of the removed systems are given as 1 (i.e. they are treated as trivial
quantum systems with a single state). This change is made only for technical bookkeping
purposes, and has no impact on the core simulation behaviour.


.. _Release Notes_0.4.1-12_Bug Fixes:

Bug Fixes
---------

.. releasenotes/notes/carrier-freq-0-19ad4362c874944f.yaml @ None
- In the case that ``envelope`` is a constant, the :meth:`.Signal.__init__` method has been
updated to not attempt to evaluate ``carrier_freq == 0.0`` if ``carrier_freq`` is a JAX tracer.
In this case, it is not possible to determine if the :class:`.Signal` instance is constant. This
resolves an error that was being raised during JAX tracing if ``carrier_freq`` is abstract.

.. releasenotes/notes/classical-registers-9bb117398a4d21d5.yaml @ None
- Fixes bug in :meth:`.DynamicsBackend.run` that caused miscounting of the number of classical
registers in a :class:`~qiskit.circuit.QuantumCircuit` (issue #251).

.. releasenotes/notes/normalize-probabilities-d729245bb3fe5f10.yaml @ b'6ede10a2bc8c61e8640db9085d4d1d9423341550'
- ``DynamicsBackend.options.normalize_states`` now also controls whether or not the probability
distribution over outcomes is normalized before sampling outcomes.


.. _Release Notes_0.4.1-12_Other Notes:

Other Notes
-----------

.. releasenotes/notes/patch-0.4.2-6a7c7bf380e54187.yaml @ None
- For users that have JAX installed, a warning has been added upon import of Qiskit Dynamics to
notify the user of issues with certain versions: JAX versions newer than ``0.4.6`` break the
``perturbation`` module, and to use ``perturbation`` module with versions ``0.4.4``, ``0.4.5``,
or ``0.4.6``, it is necessary to set ``os.environ['JAX_JIT_PJIT_API_MERGE'] = '0'`` before
importing JAX or Dynamics.

.. releasenotes/notes/patch-0.4.2-6a7c7bf380e54187.yaml @ None
- A warning has been added to :class:`.InstructionToSignals` class when converting pulse schedules
to signals to notify the user if the usage of ``SetFrequency`` or ``ShiftFrequency`` commands
result in a digital carrier frequency larger than the Nyquist frequency of the envelope sample
size ``dt``.


.. _Release Notes_0.4.1:

0.4.1
=====

.. _Release Notes_0.4.1_Prelude:

Prelude
-------

.. releasenotes/notes/0.4/patch-0.4.1-d339aa8669341341.yaml @ b'd6e280259d120d31723e0220a91cbd7dd8099298'
Qiskit Dynamics 0.4.1 is an incremental release with minor bug fixes, documentation updates, and usability features.

.. _Release Notes_0.4.1_New Features:

New Features
------------

.. releasenotes/notes/measurement_property_bug_fix-12461088823a943c.yaml @ b'807edf92d7f5d6f34715fff9d21614d77cd096d3'
- The :meth:`DynamicsBackend.from_backend` method has been updated to automatically populate the
``control_channel_map`` option based on the supplied backend if the user does not supply one.


.. _Release Notes_0.4.1_Known Issues:

Known Issues
------------

.. releasenotes/notes/0.4/diffrax-bound-0bd80c01b7f4b48f.yaml @ b'd6e280259d120d31723e0220a91cbd7dd8099298'
- Due to a bug in JAX, Dynamics can only be used with jax<=0.4.6. As they depend on newer versions
of JAX, Dynamics is also now only compatible with diffrax<=0.3.1 and equinox<=0.10.3.


.. _Release Notes_0.4.1_Bug Fixes:

Bug Fixes
---------

.. releasenotes/notes/0.4/multiset-order-bug-fix-1f1603ee1e230cba.yaml @ b'd6e280259d120d31723e0220a91cbd7dd8099298'
- Fixes a bug in the perturbation module with internal sorting of ``Multiset`` instances, which
caused incorrect computation of perturbation theory terms when ``>10`` perturbations are
present.

.. releasenotes/notes/measurement_property_bug_fix-12461088823a943c.yaml @ b'807edf92d7f5d6f34715fff9d21614d77cd096d3'
- A bug in :meth:`DynamicsBackend.__init__` causing existing measurement instructions for a
user-supplied :class:`Target` to be overwritten has been fixed.


.. _Release Notes_0.4.1_Other Notes:

Other Notes
-----------

.. releasenotes/notes/0.4/move-repo-c0b48ba3b0ced8db.yaml @ b'd6e280259d120d31723e0220a91cbd7dd8099298'
- The repository has been moved from
[github.com/Qiskit/qiskit-dynamics](https://github.com/Qiskit/qiskit-dynamics) to
[github.com/Qiskit-Extensions/qiskit-dynamics](https://github.com/Qiskit-Extensions/qiskit-dynamics),
and the documentation has been moved from
[qiskit.org/documentation/dynamics](https://qiskit.org/documentation/dynamics) to
[qiskit.org/ecosystem/dynamics](https://qiskit.org/ecosystem/dynamics/).


2 changes: 1 addition & 1 deletion qiskit_dynamics/VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.1
0.4.2
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,12 @@ def parse_backend_hamiltonian_dict(
# force keys in hamiltonian['qub'] to be ints
qub_dict = {int(key): val for key, val in hamiltonian_dict["qub"].items()}

subsystem_dims = {int(qubit): qub_dict[int(qubit)] for qubit in subsystem_list}
subsystem_dims_dict = {int(qubit): qub_dict[int(qubit)] for qubit in subsystem_list}

# Parse the Hamiltonian
system = _regex_parser(
operator_str=hamiltonian_dict["h_str"],
subsystem_dims=subsystem_dims,
subsystem_dims_dict=subsystem_dims_dict,
subsystem_list=subsystem_list,
)

Expand Down Expand Up @@ -227,7 +227,12 @@ def parse_backend_hamiltonian_dict(
*sorted(zip(reduced_channels, hamiltonian_operators))
)

return static_hamiltonian, list(hamiltonian_operators), list(reduced_channels), subsystem_dims
return (
static_hamiltonian,
list(hamiltonian_operators),
list(reduced_channels),
subsystem_dims_dict,
)


def _hamiltonian_pre_parse_exceptions(hamiltonian_dict: dict):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@


def _operator_from_string(
op_label: str, subsystem_label: int, subsystem_dims: Dict[int, int]
op_label: str, subsystem_label: int, subsystem_dims_dict: Dict[int, int]
) -> np.ndarray:
r"""Generates a dense operator acting on a single subsystem, tensoring
identities for remaining subsystems.
The single system operator is specified via a string in ``op_label``,
the list of subsystems and their corresponding dimensions are specified in the
dictionary ``subsystem_dims``, with system label being the keys specified as ``int``s,
dictionary ``subsystem_dims_dict``, with system label being the keys specified as ``int``s,
and system dimensions the values also specified as ``int``s, and ``subsystem_label``
indicates which subsystem the operator specified by ``op_label`` acts on.
Expand Down Expand Up @@ -61,7 +61,7 @@ def _operator_from_string(
Args:
op_label: The string labelling the single system operator.
subsystem_label: Index of the subsystem to apply the operator.
subsystem_dims: Dictionary of subsystem labels and dimensions.
subsystem_dims_dict: Dictionary of subsystem labels and dimensions.
Returns:
np.ndarray corresponding to the specified operator.
Expand All @@ -75,12 +75,12 @@ def _operator_from_string(
if op_func is None:
raise QiskitError(f"String {op_label} does not correspond to a known operator.")

dim = subsystem_dims[subsystem_label]
dim = subsystem_dims_dict[subsystem_label]
out = qi.Operator(op_func(dim), input_dims=[dim], output_dims=[dim])

# sort subsystem labels and dimensions according to subsystem label
sorted_subsystem_keys, sorted_subsystem_dims = zip(
*sorted(zip(subsystem_dims.keys(), subsystem_dims.values()))
*sorted(zip(subsystem_dims_dict.keys(), subsystem_dims_dict.values()))
)

# get subsystem location in ordered list
Expand Down
18 changes: 10 additions & 8 deletions qiskit_dynamics/backend/backend_string_parser/regex_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,20 @@


def _regex_parser(
operator_str: List[str], subsystem_dims: Dict[int, int], subsystem_list: List[int]
operator_str: List[str], subsystem_dims_dict: Dict[int, int], subsystem_list: List[int]
) -> List[Tuple[np.array, str]]:
"""Function wrapper for regex parsing object.
Args:
operator_str: List of strings in accepted format as described in
string_model_parser.parse_hamiltonian_dict.
subsystem_dims: Dictionary mapping subsystem labels to dimensions.
subsystem_dims_dict: Dictionary mapping subsystem labels to dimensions.
subsystem_list: List of subsystems on which the operators are to be constructed.
Returns:
List of tuples containing pairs operators and their string coefficients.
"""

return _HamiltonianParser(h_str=operator_str, subsystem_dims=subsystem_dims).parse(
return _HamiltonianParser(h_str=operator_str, subsystem_dims_dict=subsystem_dims_dict).parse(
subsystem_list
)

Expand All @@ -66,15 +66,17 @@ class _HamiltonianParser:
BrkR=re.compile(r"\)"),
)

def __init__(self, h_str, subsystem_dims):
def __init__(self, h_str, subsystem_dims_dict):
"""Create new quantum operator generator
Parameters:
h_str (list): list of Hamiltonian string
subsystem_dims (dict): dimension of subsystems
subsystem_dims_dict (dict): dimension of subsystems
"""
self.h_str = h_str
self.subsystem_dims = {int(label): int(dim) for label, dim in subsystem_dims.items()}
self.subsystem_dims_dict = {
int(label): int(dim) for label, dim in subsystem_dims_dict.items()
}
self.str2qopr = {}

def parse(self, qubit_list=None):
Expand Down Expand Up @@ -194,15 +196,15 @@ def _tokenizer(self, op_str, qubit_list=None):
if qubit_list is not None and idx not in qubit_list:
return 0, None
name = p.group("opr")
opr = _operator_from_string(name, idx, self.subsystem_dims)
opr = _operator_from_string(name, idx, self.subsystem_dims_dict)
self.str2qopr[p.group()] = opr
elif key == "PrjOpr":
_key = key
_name = p.group()
if p.group() not in self.str2qopr:
idx = int(p.group("idx"))
name = "P"
opr = _operator_from_string(name, idx, self.subsystem_dims)
opr = _operator_from_string(name, idx, self.subsystem_dims_dict)
self.str2qopr[p.group()] = opr
elif key in ["Func", "Ext"]:
_name = p.group("name")
Expand Down
12 changes: 11 additions & 1 deletion qiskit_dynamics/backend/backend_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,21 +146,31 @@ def _get_memory_slot_probabilities(


def _sample_probability_dict(
probability_dict: Dict, shots: int, seed: Optional[int] = None
probability_dict: Dict,
shots: int,
normalize_probabilities: bool = True,
seed: Optional[int] = None,
) -> List[str]:
"""Sample outcomes based on probability dictionary.
Args:
probability_dict: Dictionary representing probability distribution, with keys being
outcomes, values being probabilities.
shots: Number of shots.
normalize_probabilities: Whether or not to normalize the probabilities to sum to 1 before
sampling.
seed: Seed to use in rng construction.
Return:
List: of entries of probability_dict, sampled according to the probabilities.
"""
rng = np.random.default_rng(seed=seed)
alphabet, probs = zip(*probability_dict.items())

if normalize_probabilities:
probs = np.array(probs)
probs = probs / probs.sum()

return rng.choice(alphabet, size=shots, replace=True, p=probs)


Expand Down
Loading

0 comments on commit d217616

Please sign in to comment.