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

HEAT experiments #625

Open
wants to merge 54 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
7b2bfc1
cleanup old PR #460
nkanazawa1989 Jan 19, 2022
fccf94c
write release note
nkanazawa1989 Jan 19, 2022
6e64321
serialization unittest
nkanazawa1989 Jan 20, 2022
49a7845
fix projection angle of Z measure
nkanazawa1989 Jan 24, 2022
b766f56
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into expe…
nkanazawa1989 Jan 24, 2022
d32444f
add unittest for running experiments and minor doc fix
nkanazawa1989 Jan 25, 2022
c0e0da5
Update qiskit_experiments/library/hamiltonian/__init__.py
nkanazawa1989 Jan 27, 2022
423dad4
Update qiskit_experiments/library/hamiltonian/__init__.py
nkanazawa1989 Jan 27, 2022
8adcca2
Update qiskit_experiments/library/hamiltonian/heat_analysis.py
nkanazawa1989 Jan 27, 2022
942e558
Update qiskit_experiments/library/hamiltonian/heat_analysis.py
nkanazawa1989 Jan 27, 2022
4f70f6e
Update qiskit_experiments/library/hamiltonian/heat_base.py
nkanazawa1989 Jan 27, 2022
9cc247f
Update qiskit_experiments/library/hamiltonian/heat_base.py
nkanazawa1989 Jan 27, 2022
e8a11f7
Update qiskit_experiments/library/hamiltonian/heat_base.py
nkanazawa1989 Jan 27, 2022
00a991a
Update qiskit_experiments/library/hamiltonian/heat_base.py
nkanazawa1989 Jan 27, 2022
7c49da1
Update qiskit_experiments/library/hamiltonian/heat_base.py
nkanazawa1989 Jan 27, 2022
4a3c645
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 27, 2022
ca871ac
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 27, 2022
8ced3c2
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 27, 2022
52a1439
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 27, 2022
42f0768
Update releasenotes/notes/add-heat-experiment-047a73818407e733.yaml
nkanazawa1989 Jan 27, 2022
0cec011
Merge branch 'main' into experiment/heat
nkanazawa1989 Jan 27, 2022
16fb9ea
document overhaul for ZXHeat class
nkanazawa1989 Jan 27, 2022
6175036
document overhaul for HeatElement class
nkanazawa1989 Jan 27, 2022
532f855
black
nkanazawa1989 Jan 27, 2022
e379b49
update test tolerance
nkanazawa1989 Jan 27, 2022
c7318b8
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 31, 2022
9a59715
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 31, 2022
ef8c56c
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 31, 2022
30f9200
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 31, 2022
c4333fb
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 31, 2022
6524858
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 31, 2022
cf47445
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 31, 2022
077d217
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Jan 31, 2022
a773faa
Update qiskit_experiments/library/hamiltonian/heat_base.py
nkanazawa1989 Jan 31, 2022
9819c16
update test tolerance to be more precise
nkanazawa1989 Jan 31, 2022
678af55
Merge branch 'experiment/heat' of github.com:nkanazawa1989/qiskit-exp…
nkanazawa1989 Jan 31, 2022
1ceff09
Update heat_zx.py
nkanazawa1989 Jan 31, 2022
e540446
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into expe…
nkanazawa1989 Feb 2, 2022
e103640
udpate analysis constructor and remove BatchHeatHelper
nkanazawa1989 Feb 2, 2022
d918470
Merge branch 'experiment/heat' of github.com:nkanazawa1989/qiskit-exp…
nkanazawa1989 Feb 2, 2022
280cae1
fix lint
nkanazawa1989 Feb 2, 2022
4f7cd81
Update qiskit_experiments/library/hamiltonian/heat_base.py
nkanazawa1989 Feb 8, 2022
5c40d7d
Update qiskit_experiments/library/hamiltonian/heat_base.py
nkanazawa1989 Feb 8, 2022
4882e9e
Update qiskit_experiments/library/hamiltonian/heat_base.py
nkanazawa1989 Feb 8, 2022
a62cc8f
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Feb 8, 2022
5d4945e
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Feb 8, 2022
c908105
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Feb 8, 2022
6c1a556
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into expe…
nkanazawa1989 Feb 8, 2022
995a009
Update qiskit_experiments/library/hamiltonian/heat_zx.py
nkanazawa1989 Feb 9, 2022
caf945a
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into expe…
nkanazawa1989 Feb 10, 2022
c400186
remove usage of fitval
nkanazawa1989 Feb 10, 2022
aba80ca
Merge branch 'experiment/heat' of github.com:nkanazawa1989/qiskit-exp…
nkanazawa1989 Feb 10, 2022
fec3997
lint
nkanazawa1989 Feb 10, 2022
1e21e36
fix bug due to #662
nkanazawa1989 Feb 10, 2022
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: 2 additions & 0 deletions qiskit_experiments/framework/composite/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@
# Composite experiment classes
from .parallel_experiment import ParallelExperiment
from .batch_experiment import BatchExperiment

from .composite_experiment import sync_experiment_options, sync_transpile_options
75 changes: 74 additions & 1 deletion qiskit_experiments/framework/composite/composite_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
Composite Experiment abstract base class.
"""

from typing import List, Sequence, Optional, Union
from typing import List, Sequence, Optional, Union, Type
from abc import abstractmethod
import functools
import warnings
from qiskit.providers.backend import Backend
from qiskit_experiments.framework import BaseExperiment, ExperimentData
Expand Down Expand Up @@ -131,3 +132,75 @@ def _postprocess_transpiled_circuits(self, circuits, **run_options):
for expr in self._experiments:
if not isinstance(expr, CompositeExperiment):
expr._postprocess_transpiled_circuits(circuits, **run_options)


def sync_transpile_options(
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this needed in the first place? I wonder if this should be the default behavior of CompositeExperiment? Or why not have this as an extra function in the CompositeExperiment? I don't see why the decorator framework is needed when we only decorate a single method of a single class.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This aims at making a batch experiment to behave as if a single experiment (because user doesn't need to recognize its implementation to use). This SHOUD not be default behavior (unfortunately it is now) because we should be able to transpile batch (I believe also parallel) experiment with its own configuration.

composite_cls: Type[CompositeExperiment],
) -> Type[CompositeExperiment]:
"""A class decorator that overrides the transpile option setter method.

This method overrides the behavior of :meth:`set_transpile_options` method.
The option values set to the composite instance
will be propagated through all component experiments.

Args:
composite_cls: CompositeExperiment subclass to decorate.

Returns:
Composite experiment that implements option synchronization.

Raises:
TypeError: When class is not subclass of :class:`CompositeExperiment`
"""
if not issubclass(composite_cls, CompositeExperiment):
raise TypeError("Class is not composite experiment. Cannot override method.")

options_setter = getattr(composite_cls, "set_transpile_options")

@functools.wraps(options_setter)
def sync_opts(instance, **fields):
options_setter(instance, **fields)
# set the same options to component experiments
for comp in instance.component_experiment():
comp.set_transpile_options(**fields)

# override set method
setattr(composite_cls, "set_transpile_options", sync_opts)

return composite_cls


def sync_experiment_options(
composite_cls: Type[CompositeExperiment],
) -> Type[CompositeExperiment]:
Comment on lines +182 to +184
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment as above. Using decorators here only makes the code harder to follow.

"""A class decorator that overrides the experiment option setter method.

This method overrides the behavior of :meth:`set_experiment_options` method.
The option values set to the composite instance
will be propagated through all component experiments.

Args:
composite_cls: CompositeExperiment subclass to decorate.

Returns:
Composite experiment that implements option synchronization.

Raises:
TypeError: When class is not subclass of :class:`CompositeExperiment`
"""
if not issubclass(composite_cls, CompositeExperiment):
raise TypeError("Class is not composite experiment. Cannot override method.")

options_setter = getattr(composite_cls, "set_experiment_options")

@functools.wraps(options_setter)
def sync_opts(instance, **fields):
options_setter(instance, **fields)
# set the same options to component experiments
for comp in instance.component_experiment():
comp.set_experiment_options(**fields)

# override set method
setattr(composite_cls, "set_experiment_options", sync_opts)

return composite_cls
3 changes: 1 addition & 2 deletions qiskit_experiments/library/hamiltonian/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,10 @@
:template: autosummary/experiment.rst

HeatElement
BatchHeatHelper


"""

from .heat_base import HeatElement, BatchHeatHelper
from .heat_base import HeatElement
from .heat_zx import ZXHeat, ZX90HeatXError, ZX90HeatYError, ZX90HeatZError
from .heat_analysis import HeatElementAnalysis, HeatAnalysis
15 changes: 11 additions & 4 deletions qiskit_experiments/library/hamiltonian/heat_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import numpy as np

from qiskit_experiments.curve_analysis import ErrorAmplificationAnalysis
from qiskit_experiments.curve_analysis import ErrorAmplificationAnalysis, ParameterRepr
from qiskit_experiments.exceptions import AnalysisError
from qiskit_experiments.framework import (
CompositeAnalysis,
Expand Down Expand Up @@ -97,22 +97,29 @@ def __init__(
Raises:
AnalysisError: When size of ``fit_params`` or ``out_params`` are not 2.
nkanazawa1989 marked this conversation as resolved.
Show resolved Hide resolved
"""
super().__init__()

if len(fit_params) != 2:
raise AnalysisError(
f"{self.__class__.__name__} assumes two fit parameters extracted from "
"a set of experiments with different control qubit state input. "
f"{len(fit_params)} input parameter names are specified."
)
self._fit_params = fit_params

if len(out_params) != 2:
raise AnalysisError(
f"{self.__class__.__name__} assumes two output parameters computed with "
"a set of experiment results with different control qubit state input. "
f"{len(out_params)} output parameter names are specified."
)

analyses = []
for fit_parm in fit_params:
sub_analysis = HeatElementAnalysis()
sub_analysis.set_options(result_parameters=[ParameterRepr("d_theta", fit_parm, "rad")])
analyses.append(sub_analysis)

super().__init__(analyses=analyses)

self._fit_params = fit_params
self._out_params = out_params

def _run_analysis(self, experiment_data: ExperimentData):
Expand Down
106 changes: 6 additions & 100 deletions qiskit_experiments/library/hamiltonian/heat_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@
Base Class for general Hamiltonian Error Amplifying Tomography experiments.
"""

from abc import ABC
from typing import List, Tuple, Optional

from qiskit import circuit, QuantumCircuit
from qiskit.providers import Backend
from qiskit_experiments.framework import BaseExperiment, BatchExperiment, Options
from qiskit_experiments.curve_analysis import ParameterRepr
from .heat_analysis import HeatElementAnalysis, HeatAnalysis

from qiskit_experiments.framework import BaseExperiment, Options
from .heat_analysis import HeatElementAnalysis


class HeatElement(BaseExperiment):
eggerdj marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -68,11 +67,8 @@ class HeatElement(BaseExperiment):
# section: note

This class is usually not exposed to end users.
Developer of new HEAT experiment must design amplification sequence and
instantiate the class implicitly in the batch experiment.
The :class:`BatchHeatHelper` provides a convenient wrapper class of
the :class:`qiskit_experiments.framework.BatchExperiment` for implementing a
typical HEAT experiment.
The developer of a new HEAT experiment must design the amplification sequences and
create instances of this class implicitly in the batch experiment.

# section: analysis_ref
:py:class:`HeatElementAnalysis`
Expand All @@ -88,7 +84,6 @@ def __init__(
echo_circ: QuantumCircuit,
meas_circ: QuantumCircuit,
backend: Optional[Backend] = None,
parameter_name: Optional[str] = "d_theta",
**kwargs,
):
"""Create new HEAT sub experiment.
Expand All @@ -99,17 +94,11 @@ def __init__(
echo_circ: A circuit to selectively amplify the specific error term.
meas_circ: A circuit to project target qubit onto the basis of interest.
backend: Optional, the backend to run the experiment on.
parameter_name: A name of :math:`d\\theta` parameter from the
amplification fit. The fit parameter is represented by this name
in the analysis result.

Keyword Args:
See :meth:`experiment_options` for details.
"""
analysis = HeatElementAnalysis()
analysis.set_options(result_parameters=[ParameterRepr("d_theta", parameter_name, "rad")])

super().__init__(qubits=qubits, backend=backend, analysis=analysis)
super().__init__(qubits=qubits, backend=backend, analysis=HeatElementAnalysis())
self.set_experiment_options(**kwargs)

# These are not user configurable options. Be frozen once assigned.
Expand Down Expand Up @@ -165,86 +154,3 @@ def circuits(self) -> List[QuantumCircuit]:
circs.append(circ)

return circs


class BatchHeatHelper(BatchExperiment, ABC):
"""A wrapper class of ``BatchExperiment`` to implement HEAT experiment.

# section: overview

This is a helper class for experiment developers of HEAT experiments.
This class overrides the :meth:`set_experiment_options` and :meth:`set_transpile_options`
methods of :class:`BatchExperiment` such that they set the options of the
individual amplification sub-experiments to the same values. Therefore, from
end user's perspective, this experiment behaves as if a single HEAT experiment.

# section: analysis_ref
:py:class:`HeatAnalysis`
"""

def __init__(
self,
heat_experiments: List[HeatElement],
heat_analysis: HeatAnalysis,
backend: Optional[Backend] = None,
):
"""Create new HEAT experiment.

Args:
heat_experiments: A list of error amplification sequence that might be
implemented as :class:``HeatElement`` instance.
heat_analysis: HEAT analysis instance.
backend: Optional, the backend to run the experiment on.
"""
super().__init__(experiments=heat_experiments, backend=backend)

# override analysis. we expect the instance is initialized with
# parameter names specific to child amplification experiments.
self.analysis = heat_analysis

@classmethod
def _default_experiment_options(cls) -> Options:
"""Default experiment options.

Experiment Options:
repetitions (Sequence[int]): A list of the number of echo repetitions.
heat_gate (Gate): A gate instance representing the entangling sequence.
"""
options = super()._default_experiment_options()
options.repetitions = list(range(21))
options.heat_gate = circuit.Gate("heat", num_qubits=2, params=[])

return options

def set_experiment_options(self, **fields):
"""Set the analysis options for :meth:`run` method.

Args:
fields: The fields to update the options
"""
# propagate options through all nested amplification experiments.
for comp_exp in self.component_experiment():
comp_exp.set_experiment_options(**fields)

super().set_experiment_options(**fields)

@classmethod
def _default_transpile_options(cls) -> Options:
"""Default transpile options."""
options = super()._default_transpile_options()
options.basis_gates = ["sx", "x", "rz", "heat"]
options.optimization_level = 1

return options

def set_transpile_options(self, **fields):
"""Set the transpiler options for :meth:`run` method.

Args:
fields: The fields to update the options
"""
# propagate options through all nested amplification experiments.
for comp_exp in self.component_experiment():
comp_exp.set_transpile_options(**fields)

super().set_transpile_options(**fields)
Loading