Skip to content
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
6 changes: 2 additions & 4 deletions qiskit_experiments/library/tomography/qpt_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,9 @@ def _default_options(cls) -> Options:
rescale_trace (bool): If True rescale the state returned by the fitter have either
trace 1 (Default: True).
target (Union[str, :class:`~qiskit.quantum_info.operators.channel.quantum_channel`,
:class:`~qiskit.quantum_info.Operator`]): Set a custom target quantum
:class:`~qiskit.quantum_info.Operator`]): Optional, Set a custom target quantum
channel for computing the :func:~qiskit.quantum_info.process_fidelity` of the
fitted process against. If ``"default"`` the ideal process corresponding for
the input circuit will be used. If ``None`` no fidelity will be computed
(Default: "default").
fitted process against (Default: None).
"""
options = super()._default_options()
options.measurement_basis = PauliMeasurementBasis()
Expand Down
50 changes: 49 additions & 1 deletion qiskit_experiments/library/tomography/qpt_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
"""

from typing import Union, Optional, Iterable, List, Tuple, Sequence
import numpy as np
from qiskit.circuit import QuantumCircuit, Instruction
from qiskit.quantum_info.operators.base_operator import BaseOperator
from qiskit.quantum_info import Choi, Operator, Statevector, partial_trace
from qiskit_experiments.exceptions import QiskitError
from .tomography_experiment import TomographyExperiment
from .qpt_analysis import ProcessTomographyAnalysis
from . import basis
Expand Down Expand Up @@ -88,5 +91,50 @@ def __init__(
preparation_qubits=preparation_qubits,
basis_indices=basis_indices,
qubits=qubits,
analysis=ProcessTomographyAnalysis(),
)
self.analysis = ProcessTomographyAnalysis()

# Set target quantum channel
self.analysis.set_options(target=self._target_quantum_channel())

def _target_quantum_channel(self) -> Union[Choi, Operator]:
"""Return the process tomography target"""
# Check if circuit contains measure instructions
# If so we cannot return target state
circuit_ops = self._circuit.count_ops()
if "measure" in circuit_ops:
return None
perm_circ = self._permute_circuit()
try:
if "reset" in circuit_ops or "kraus" in circuit_ops or "superop" in circuit_ops:
channel = Choi(perm_circ)
else:
channel = Operator(perm_circ)
except QiskitError:
# Circuit couldn't be simulated
return None

total_qubits = self._circuit.num_qubits
if self._meas_qubits:
num_meas = len(self._meas_qubits)
else:
num_meas = total_qubits
if self._prep_qubits:
num_prep = len(self._prep_qubits)
else:
num_prep = total_qubits

if num_prep == total_qubits and num_meas == total_qubits:
return channel

# Trace out non-measurement subsystems
tr_qargs = []
if self._prep_qubits:
tr_qargs += list(range(num_prep, total_qubits))
if self._meas_qubits:
tr_qargs += list(range(total_qubits + num_meas, 2 * total_qubits))

chan_state = Statevector(np.ravel(channel, order="F"))
chan_state = partial_trace(chan_state, tr_qargs) / 2 ** (total_qubits - num_meas)
channel = Choi(chan_state.data, input_dims=[2] * num_prep, output_dims=[2] * num_meas)
return channel
8 changes: 3 additions & 5 deletions qiskit_experiments/library/tomography/qst_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,9 @@ def _default_options(cls) -> Options:
rescale_trace (bool): If True rescale the state returned by the fitter have either
trace 1 (Default: True).
target (Union[str, :class:`~qiskit.quantum_info.DensityMatrix`,
:class:`~qiskit.quantum_info.Statevector`]): Set a custom target quantum
state for computing the :func:~qiskit.quantum_info.state_fidelity` of the
fitted state against. If ``"default"`` the ideal state corresponding for
the input circuit will be used. If ``None`` no fidelity will be computed
(Default: "default").
:class:`~qiskit.quantum_info.Statevector`]): Optional, et a custom target
quantum state for computing the :func:~qiskit.quantum_info.state_fidelity`
of the fitted state against (Default: None).
"""
options = super()._default_options()
options.measurement_basis = PauliMeasurementBasis()
Expand Down
38 changes: 36 additions & 2 deletions qiskit_experiments/library/tomography/qst_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
from typing import Union, Optional, Iterable, List, Sequence
from qiskit.circuit import QuantumCircuit, Instruction
from qiskit.quantum_info.operators.base_operator import BaseOperator
from qiskit.quantum_info import Statevector
from qiskit.quantum_info import Statevector, DensityMatrix, partial_trace
from qiskit_experiments.exceptions import QiskitError
from .tomography_experiment import TomographyExperiment
from .qst_analysis import StateTomographyAnalysis
from . import basis
Expand Down Expand Up @@ -87,5 +88,38 @@ def __init__(
measurement_qubits=measurement_qubits,
basis_indices=basis_indices,
qubits=qubits,
analysis=StateTomographyAnalysis(),
)
self.analysis = StateTomographyAnalysis()

# Set target quantum state
self.analysis.set_options(target=self._target_quantum_state())

def _target_quantum_state(self) -> Union[Statevector, DensityMatrix]:
"""Return the state tomography target"""
# Check if circuit contains measure instructions
# If so we cannot return target state
circuit_ops = self._circuit.count_ops()
if "measure" in circuit_ops:
return None

perm_circ = self._permute_circuit()
try:
if "reset" in circuit_ops or "kraus" in circuit_ops or "superop" in circuit_ops:
state = DensityMatrix(perm_circ)
else:
state = Statevector(perm_circ)
except QiskitError:
# Circuit couldn't be simulated
return None

total_qubits = self._circuit.num_qubits
if self._meas_qubits:
num_meas = len(self._meas_qubits)
else:
num_meas = total_qubits
if num_meas == total_qubits:
return state

# Trace out non-measurement qubits
tr_qargs = range(num_meas, total_qubits)
return partial_trace(state, tr_qargs)
13 changes: 4 additions & 9 deletions qiskit_experiments/library/tomography/tomography_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ def _default_options(cls) -> Options:
rescale_trace (bool): If True rescale the state returned by the fitter
have either trace 1 for :class:`~qiskit.quantum_info.DensityMatrix`,
or trace dim for :class:`~qiskit.quantum_info.Choi` matrices (Default: True).
target (Any): depends on subclass.
target (Any): Optional, target object for fidelity comparison of the fit
(Default: None).
"""
options = super()._default_options()

Expand All @@ -87,7 +88,7 @@ def _default_options(cls) -> Options:
options.fitter_options = {}
options.rescale_positive = True
options.rescale_trace = True
options.target = "default"
options.target = None
return options

@classmethod
Expand All @@ -107,12 +108,6 @@ def _run_analysis(self, experiment_data):
experiment_data.data()
)

# Get target state
target_state = self.options.target
if target_state == "default":
metadata = experiment_data.metadata
target_state = metadata.get("target", None)

# Get tomography fitter function
fitter = self._get_fitter(self.options.fitter)
try:
Expand All @@ -136,7 +131,7 @@ def _run_analysis(self, experiment_data):
analysis_results = self._postprocess_fit(
state,
metadata=fitter_metadata,
target_state=target_state,
target_state=self.options.target,
rescale_positive=self.options.rescale_positive,
rescale_trace=self.options.rescale_trace,
qpt=bool(self.options.preparation_basis),
Expand Down
Loading