Skip to content

Commit

Permalink
Merge branch 'main' into feature/dataframe-pr2
Browse files Browse the repository at this point in the history
  • Loading branch information
nkanazawa1989 authored Sep 22, 2023
2 parents a0bcded + c8362f3 commit 92b384a
Show file tree
Hide file tree
Showing 31 changed files with 175 additions and 157 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cron-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: [3.8, 3.9, "3.10", "3.11"]
python-version: [3.8, "3.11"]
os: ["ubuntu-latest", "macOS-latest", "windows-latest"]
steps:
- name: Print Concurrency Group
Expand Down
31 changes: 13 additions & 18 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: [3.8, 3.9, "3.10", "3.11"]
python-version: [3.8, "3.11"]
os: ["ubuntu-latest", "macOS-latest", "windows-latest"]
steps:
- name: Print Concurrency Group
Expand All @@ -39,25 +39,20 @@ jobs:
${{ runner.os }}-${{ matrix.python-version }}-pip-tests-
${{ runner.os }}-${{ matrix.python-version }}-pip-
${{ runner.os }}-${{ matrix.python-version }}
- name: Stestr cache
uses: actions/cache@v3
with:
path: .stestr
key: stestr-${{ runner.os }}-${{ matrix.python-version }}
restore-keys: |
stestr-${{ runner.os }}-
stestr-
- name: Install Deps
run: python -m pip install -U "tox==3.27.1" setuptools virtualenv wheel
- name: Install and Run Tests (Windows and Linux)
run: python -m pip install -U tox setuptools virtualenv wheel stestr
- name: Install and Run Tests
run: tox -e py
if: runner.os != 'macOS'
- name: Install and Run Tests (Macs only)
run: tox -e cover
if: runner.os == 'macOS'
env:
OMP_NUM_THREADS: 1
- name: Report coverage to coveralls.io (Macs only)
if: runner.os == 'macOS'
uses: coverallsapp/github-action@v2
env:
ACTIONS_RUNNER_DEBUG: 1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: unit-tests_python${{ matrix.python-version }}-${{ matrix.os }}
path-to-lcov: coverage.lcov
- name: Clean up stestr cache
run: stestr history remove all

lint:
name: lint
Expand Down
1 change: 1 addition & 0 deletions .stestr.conf
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[DEFAULT]
test_path=./test
parallel_class=True
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ To run a method:
tox -- -n test.python.test_examples.TestPythonExamples.test_all_examples
```

Note that tests will fail automatically if they do not finish execution within 60 seconds.

#### STDOUT/STDERR and logging capture

When running tests in parallel using `stestr` either via tox, the Makefile (`make
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
[![License](https://img.shields.io/github/license/Qiskit-Extensions/qiskit-experiments.svg)](https://opensource.org/licenses/Apache-2.0)
[![Release](https://img.shields.io/github/release/Qiskit-Extensions/qiskit-experiments.svg)](https://github.com/Qiskit-Extensions/qiskit-experiments/releases)
![Python](https://img.shields.io/pypi/pyversions/qiskit-experiments.svg)
[![Coverage Status](https://coveralls.io/repos/github/Qiskit-Extensions/qiskit-experiments/badge.svg?branch=main)](https://coveralls.io/github/Qiskit-Extensions/qiskit-experiments?branch=main)
[![DOI](https://joss.theoj.org/papers/10.21105/joss.05329/status.svg)](https://doi.org/10.21105/joss.05329)

**Qiskit Experiments** is a repository that builds tools for building, running,
Expand Down
2 changes: 1 addition & 1 deletion qiskit_experiments/library/characterization/drag.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def circuits(self) -> List[QuantumCircuit]:
)

for beta_val in self.experiment_options.betas:
beta_val = np.round(beta_val, decimals=6)
beta_val = float(np.round(beta_val, decimals=6))

assigned_circuit = circuit.assign_parameters({beta: beta_val}, inplace=False)

Expand Down
61 changes: 45 additions & 16 deletions qiskit_experiments/library/characterization/half_angle.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,48 @@ class HalfAngle(BaseExperiment):
This sequence measures angle errors where the axis of the :code:`sx` and :code:`x`
rotation are not parallel. A similar experiment is described in Ref.~[1] where the
gate sequence :code:`x - y` is repeated to amplify errors caused by non-orthogonal
:code:`x` and :code:`y` rotation axes. Such errors can occur due to phase errors.
For example, the non-linearities in the mixer's skew for :math:`\pi/2` pulses may
be different from the :math:`\pi` pulse.
:code:`x` and :code:`y` rotation axes.
One cause of such errors is non-linearity in the microwave mixer used
to produce the pulses for the ``x`` and ``sx`` gates. Typically, these
gates are calibrated to have the same duration and so have different
pulse amplitudes. Non-linearities in the mixer's skew can cause the
angle to differ for these different pulse amplitudes.
The way the experiment works is that the initial ``Ry(π/2)`` puts the
qubit close to the :math:`+X` state, with a deviation :math:`δθ`, due
to the misalignment between ``sx`` and ``x`` (``Ry(π/2)`` is
implemented with ``sx`` as described below). The first ``sx - sx`` do
nothing as they should be rotations about the axis the qubit is
pointing along. The first ``y`` then mirrors the qubit about the
:math:`y` axis in the :math:`xy` plane of the Bloch sphere, so the
:math:`δθ` deviation from :math:`+X` becomes a :math:`-δθ` from
:math:`-X`. The next ``sx - sx`` sequence rotates about the axis that
is :math:`+δθ` rotated in the :math:`xy` plane from :math:`+X`, which
takes the deviation from :math:`-X` from :math:`-δθ` to :math:`+3 δθ`.
Then the next ``y`` mirrors this across the :math:`y` axis, taking the
state to :math:`-3 δθ` from :math:`+X`. This pattern continues with
each iteration, with the angular deviation in units of :math:`δθ`
following the sequence 1, 3, 5, 7, 9, etc. from :math:`+X` and
:math:`-X`. The final ``sx`` rotation serves mainly to rotate these
deviations from :math:`+X` and :math:`-X` in the :math:`xy` plane into
deviations out of the :math:`xy` plane, so that they appear as a signal
in the :math:`Z` basis. Because ``sx`` has a :math:`δθ` deviation from
``x``, the final ``sx`` adds an extra :math:`δθ` to the deviations, so
the pattern ends up as 2, 4, 6, 8, etc., meaning that each iteration
adds :math:`2 δθ` to the deviation from the equator of the Bloch sphere
(with the sign alternating due to the ``y`` gates, so the deviations
are really -2, 4, -6, 8, etc.).
For the implementation of the circuits, the experiment uses ``Rz(π/2) -
sx - Rz(-π/2)`` to implement the ``Ry(π/2)`` and ``Rz(π/2) - x -
Rz(-π/2)`` to implement the ``y``. So the experiment makes use of only
``sx``, ``x``, ``Rz(π/2)``, and ``Rz(-π/2)`` gates. For the
experiment's analysis to be valid, it is important that the ``sx`` and
``x`` gates are not replaced (such as by a transpiler pass that
replaces ``x`` with ``sx - sx``), as it is the angle between them which
is being inferred. It is assumed that the angle between ``x`` and
``Rz`` is exactly :math:`π/2`.
# section: analysis_ref
:class:`.ErrorAmplificationAnalysis`
Expand All @@ -66,18 +105,6 @@ def _default_experiment_options(cls) -> Options:
options.repetitions = list(range(15))
return options

@classmethod
def _default_transpile_options(cls) -> Options:
"""Default transpile options.
The basis gates option should not be changed since it will affect the gates and
the pulses that are run on the hardware.
"""
options = super()._default_transpile_options()
options.basis_gates = ["sx", "rz", "y"]
options.inst_map = None
return options

def __init__(self, physical_qubits: Sequence[int], backend: Optional[Backend] = None):
"""Setup a half angle experiment on the given qubit.
Expand Down Expand Up @@ -126,7 +153,9 @@ def circuits(self) -> List[QuantumCircuit]:
for _ in range(repetition):
circuit.sx(0)
circuit.sx(0)
circuit.y(0)
circuit.rz(np.pi / 2, 0)
circuit.x(0)
circuit.rz(-np.pi / 2, 0)

circuit.sx(0)
circuit.measure_all()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@

_CLIFFORD_COMPOSE_1Q = np.load(f"{_DATA_FOLDER}/clifford_compose_1q.npz")["table"]
_CLIFFORD_INVERSE_1Q = np.load(f"{_DATA_FOLDER}/clifford_inverse_1q.npz")["table"]
_CLIFFORD_COMPOSE_2Q = scipy.sparse.load_npz(f"{_DATA_FOLDER}/clifford_compose_2q_sparse.npz")
_CLIFFORD_COMPOSE_2Q = scipy.sparse.lil_matrix(
scipy.sparse.load_npz(f"{_DATA_FOLDER}/clifford_compose_2q_sparse.npz")
)
_CLIFFORD_INVERSE_2Q = np.load(f"{_DATA_FOLDER}/clifford_inverse_2q.npz")["table"]


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def __init__(
basis_indices: Optional, a list of basis indices for generating partial
tomography measurement data. Each item should be given as a pair of
lists of preparation and measurement basis configurations
``([p[0], p[1], ..], m[0], m[1], ...])``, where ``p[i]`` is the
``([p[0], p[1], ...], [m[0], m[1], ...])``, where ``p[i]`` is the
preparation basis index, and ``m[i]`` is the measurement basis index
for qubit-i. If not specified full tomography for all indices of the
preparation and measurement bases will be performed.
Expand Down
2 changes: 1 addition & 1 deletion qiskit_experiments/library/tomography/qpt_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def __init__(
basis_indices: Optional, a list of basis indices for generating partial
tomography measurement data. Each item should be given as a pair of
lists of preparation and measurement basis configurations
``([p[0], p[1], ..], m[0], m[1], ...])``, where ``p[i]`` is the
``([p[0], p[1], ...], [m[0], m[1], ...])``, where ``p[i]`` is the
preparation basis index, and ``m[i]`` is the measurement basis index
for qubit-i. If not specified full tomography for all indices of the
preparation and measurement bases will be performed.
Expand Down
10 changes: 10 additions & 0 deletions releasenotes/notes/half-angle-x-600debac368ce2c6.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
fixes:
- |
The :class:`.HalfAngle` experiment's circuits were changed so that they use
combinations of ``rz`` and ``x`` instead of the less standard ``y`` gate.
This change allows :class:`~HalfAngle` to be run on IBM backends directly.
Previously, it could only be run through the :class:`~HalfAngleCal`
subclass in combination with a :class:`~Calibrations` instance containing a
custom calibration for the ``y`` gate.
Fixes issue `#1233 <https://github.com/Qiskit-Extensions/qiskit-experiments/issues/1233>`_.
4 changes: 3 additions & 1 deletion releasenotes/notes/rabi-and-qv-bugfix-34636baee6651af1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ fixes:
`qiskit-ibm-provider` using custom amplitudes provided as a numpy array.
- |
Resolved an issue that caused QV experiments to fail when executed via `qiskit-ibm-provider` using
Qiskit Terra for calculating ideal probabilities, instead of Aer.
Qiskit Terra for calculating ideal probabilities, instead of Aer.
- |
Resolved a serialization issue that affected DRAG experiments with integral beta values specified.
9 changes: 9 additions & 0 deletions test/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
Qiskit Experiments test case class
"""

import os
import json
import pickle
import warnings
from typing import Any, Callable, Optional

import fixtures
import uncertainties
from qiskit.test import QiskitTestCase
from qiskit.utils.deprecation import deprecate_func
Expand All @@ -30,10 +32,17 @@
from qiskit_experiments.framework.experiment_data import ExperimentStatus
from .extended_equality import is_equivalent

# Fail tests that take longer than this
TEST_TIMEOUT = os.environ.get("TEST_TIMEOUT", 60)


class QiskitExperimentsTestCase(QiskitTestCase):
"""Qiskit Experiments specific extra functionality for test cases."""

def setUp(self):
super().setUp()
self.useFixture(fixtures.Timeout(TEST_TIMEOUT, gentle=True))

@classmethod
def setUpClass(cls):
"""Set-up test class."""
Expand Down
24 changes: 16 additions & 8 deletions test/database_service/test_db_experiment_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ def test_add_data_result(self):
def test_add_data_result_metadata(self):
"""Test add result metadata."""
exp_data = ExperimentData(backend=self.backend, experiment_type="qiskit_test")
result1 = self._get_job_result(1, has_metadata=False)
result2 = self._get_job_result(1, has_metadata=True)
result1 = self._get_job_result(1, no_metadata=True)
result2 = self._get_job_result(1)

exp_data.add_data(result1)
exp_data.add_data(result2)
Expand All @@ -119,12 +119,14 @@ def test_add_data_job(self):
"""Test add job data."""
a_job = mock.create_autospec(Job, instance=True)
a_job.result.return_value = self._get_job_result(3)
num_circs = 3
jobs = []
for _ in range(2):
job = mock.create_autospec(Job, instance=True)
job.result.return_value = self._get_job_result(2)
job.result.return_value = self._get_job_result(2, label_from=num_circs)
job.status.return_value = JobStatus.DONE
jobs.append(job)
num_circs = num_circs + 2

expected = a_job.result().get_counts()
for job in jobs:
Expand All @@ -135,7 +137,13 @@ def test_add_data_job(self):
self.assertExperimentDone(exp_data)
exp_data.add_jobs(jobs)
self.assertExperimentDone(exp_data)
self.assertEqual(expected, [sdata["counts"] for sdata in exp_data.data()])
self.assertEqual(
expected,
[
sdata["counts"]
for sdata in sorted(exp_data.data(), key=lambda x: x["metadata"]["label"])
],
)
self.assertIn(a_job.job_id(), exp_data.job_ids)

def test_add_data_job_callback(self):
Expand Down Expand Up @@ -1073,7 +1081,7 @@ def _job2_result():
exp_data.data(0)["counts"], [copied.data(0)["counts"], copied.data(1)["counts"]]
)

def _get_job_result(self, circ_count, has_metadata=False):
def _get_job_result(self, circ_count, label_from=0, no_metadata=False):
"""Return a job result with random counts."""
job_result = {
"backend_name": BackendData(self.backend).name,
Expand All @@ -1085,12 +1093,12 @@ def _get_job_result(self, circ_count, has_metadata=False):
}
circ_result_template = {"shots": 1024, "success": True, "data": {}}

for _ in range(circ_count):
for i_circ in range(circ_count):
counts = randrange(1024)
circ_result = copy.copy(circ_result_template)
circ_result["data"] = {"counts": {"0x0": counts, "0x3": 1024 - counts}}
if has_metadata:
circ_result["header"] = {"metadata": {"meas_basis": "pauli"}}
if not no_metadata:
circ_result["header"] = {"metadata": {"label": label_from + i_circ}}
job_result["results"].append(circ_result)

return Result.from_dict(job_result)
Expand Down
Loading

0 comments on commit 92b384a

Please sign in to comment.