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

Extend the basis gates of BasicSimulator #12186

Merged
merged 19 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from 11 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
4 changes: 2 additions & 2 deletions qiskit/circuit/library/standard_gates/x.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,8 +584,8 @@ def __init__(

Args:
label: An optional label for the gate [Default: ``None``]
ctrl_state: control state expressed as integer,
string (e.g.``'110'``), or ``None``. If ``None``, use all 1s.
ctrl_state: control state expressed as integer, string (e.g.``"110"``), or ``None``.
ElePT marked this conversation as resolved.
Show resolved Hide resolved
If ``None``, use all 1s.
Copy link
Member

Choose a reason for hiding this comment

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

This will have broken the formatting because the continuation line is unindented, and I don't think it'll have actually fixed the problem, which is that there's no space betwen e.g. and the opening ``.

Copy link
Member Author

Choose a reason for hiding this comment

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

let's try in c35b9cf

"""
from .sx import SXGate

Expand Down
111 changes: 91 additions & 20 deletions qiskit/providers/basic_provider/basic_provider_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,30 @@
from qiskit.exceptions import QiskitError

# Single qubit gates supported by ``single_gate_params``.
SINGLE_QUBIT_GATES = ("U", "u", "h", "p", "u1", "u2", "u3", "rz", "sx", "x")
SINGLE_QUBIT_GATES = (
"U",
"u",
"u1",
"u2",
"u3",
"h",
"p",
"s",
"sdg",
"sx",
"sxdg",
"t",
"tdg",
"x",
"y",
"z",
"id",
"i",
"r",
"rx",
"ry",
"rz",
)


def single_gate_matrix(gate: str, params: list[float] | None = None) -> np.ndarray:
Expand All @@ -40,42 +63,90 @@ def single_gate_matrix(gate: str, params: list[float] | None = None) -> np.ndarr
"""
if params is None:
params = []

if gate == "U":
if gate in ("U", "u"):
gc = gates.UGate
elif gate == "u1":
gc = gates.U1Gate
elif gate == "u2":
gc = gates.U2Gate
elif gate == "u3":
gc = gates.U3Gate
elif gate == "h":
gc = gates.HGate
elif gate == "u":
gc = gates.UGate
elif gate == "p":
gc = gates.PhaseGate
Copy link
Member

Choose a reason for hiding this comment

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

If we're going to add this many new gates, please can we switch to using a dict lookup to retrieve the gate classes?

Copy link
Member Author

@1ucian0 1ucian0 Apr 26, 2024

Choose a reason for hiding this comment

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

done in 5cddee7

elif gate == "u2":
gc = gates.U2Gate
elif gate == "u1":
gc = gates.U1Gate
elif gate == "rz":
gc = gates.RZGate
elif gate == "id":
gc = gates.IGate
elif gate == "s":
gc = gates.SGate
elif gate == "sdg":
gc = gates.SdgGate
elif gate == "sx":
gc = gates.SXGate
elif gate == "sxdg":
gc = gates.SXdgGate
elif gate == "t":
gc = gates.TGate
elif gate == "tdg":
gc = gates.TdgGate
elif gate == "x":
gc = gates.XGate
elif gate == "y":
gc = gates.YGate
elif gate == "z":
gc = gates.ZGate
elif gate in ("id", "i"):
gc = gates.IGate
elif gate == "r":
gc = gates.RGate
elif gate == "rx":
gc = gates.RXGate
elif gate == "ry":
gc = gates.RYGate
elif gate == "rz":
gc = gates.RZGate
else:
raise QiskitError("Gate is not a valid basis gate for this simulator: %s" % gate)

return gc(*params).to_matrix()


# Cache CX matrix as no parameters.
_CX_MATRIX = gates.CXGate().to_matrix()


def cx_gate_matrix() -> np.ndarray:
"""Get the matrix for a controlled-NOT gate."""
return _CX_MATRIX
# Two qubit gates WITHOUT parameters
TWO_QUBIT_GATES = {
"CX": gates.CXGate().to_matrix(),
"cx": gates.CXGate().to_matrix(),
"ecr": gates.ECRGate().to_matrix(),
"cy": gates.CYGate().to_matrix(),
"cz": gates.CZGate().to_matrix(),
"swap": gates.SwapGate().to_matrix(),
"iswap": gates.iSwapGate().to_matrix(),
"ch": gates.CHGate().to_matrix(),
"cs": gates.CSGate().to_matrix(),
"csdg": gates.CSdgGate().to_matrix(),
"csx": gates.CSXGate().to_matrix(),
"dcx": gates.DCXGate().to_matrix(),
}

# Two qubit gates WITH parameters, supported by _two_gate_matrix
TWO_QUBIT_GATES_WITH_PARAMETERS = {
"cp": gates.CPhaseGate,
"crx": gates.CRXGate,
"cry": gates.CRYGate,
"crz": gates.CRZGate,
"cu": gates.CUGate,
"cu1": gates.CU1Gate,
"cu3": gates.CU3Gate,
"rxx": gates.RXXGate,
"ryy": gates.RYYGate,
"rzz": gates.RZZGate,
}


# Three qubit gates.
THREE_QUBIT_GATES = {
"ccx": gates.CCXGate().to_matrix(),
"ccz": gates.CCZGate().to_matrix(),
"rccx": gates.RCCXGate().to_matrix(),
"cswap": gates.CSwapGate().to_matrix(),
}


def einsum_matmul_index(gate_indices: list[int], number_of_qubits: int) -> str:
Expand Down
93 changes: 77 additions & 16 deletions qiskit/providers/basic_provider/basic_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import UnitaryGate
from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping
from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping, GlobalPhaseGate
from qiskit.providers import Provider
from qiskit.providers.backend import BackendV2
from qiskit.providers.models import BackendConfiguration
Expand All @@ -51,8 +51,12 @@

from .basic_provider_job import BasicProviderJob
from .basic_provider_tools import single_gate_matrix
from .basic_provider_tools import SINGLE_QUBIT_GATES
from .basic_provider_tools import cx_gate_matrix
from .basic_provider_tools import (
SINGLE_QUBIT_GATES,
TWO_QUBIT_GATES,
TWO_QUBIT_GATES_WITH_PARAMETERS,
THREE_QUBIT_GATES,
)
from .basic_provider_tools import einsum_vecmul_index
from .exceptions import BasicProviderError

Expand Down Expand Up @@ -138,21 +142,61 @@ def _build_basic_target(self) -> Target:
num_qubits=None,
)
basis_gates = [
"c3sx",
"ccx",
"ccz",
"ch",
"cp",
"crx",
"cry",
"crz",
"cs",
"csdg",
"cswap",
"csx",
"cu",
"cu1",
"cu3",
"cx",
"cy",
"cz",
"dcx",
"delay",
"ecr",
"global_phase",
"h",
"u",
"id",
"iswap",
"measure",
"p",
"r",
"rcccx",
"rccx",
"reset",
"rx",
"rxx",
"ry",
"ryy",
"rz",
"rzx",
"rzz",
"s",
"sdg",
"swap",
"sx",
"sxdg",
"t",
"tdg",
"u",
"u1",
"u2",
"u3",
"rz",
"sx",
"x",
"cx",
"id",
"unitary",
"measure",
"delay",
"reset",
"x",
"xx_minus_yy",
"xx_plus_yy",
"y",
"z",
]
inst_mapping = get_standard_gate_name_mapping()
for name in basis_gates:
Expand Down Expand Up @@ -617,24 +661,41 @@ def run_experiment(self, experiment: QasmQobjExperiment) -> dict[str, ...]:
value >>= 1
if value != int(operation.conditional.val, 16):
continue
# Check if single gate
if operation.name == "unitary":
qubits = operation.qubits
gate = operation.params[0]
self._add_unitary(gate, qubits)
elif operation.name in ("id", "u0"):
pass
Copy link
Contributor

Choose a reason for hiding this comment

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

What about a message like this one?

Suggested change
pass
if operation.name == "delay":
warnings.warn(
"BasicSimulator cannot simulate gate durations, "
"treating delay operation as an identity.",
UserWarning,
stacklevel=2,
)
pass

Copy link
Member

Choose a reason for hiding this comment

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

I think we're fine without a warning; it's completely valid to simulate a delay as an identity if there's no noise in the system.

elif operation.name == "global_phase":
params = getattr(operation, "params", None)
gate = GlobalPhaseGate(*params).to_matrix()
self._add_unitary(gate, [])
# Check if single qubit gate
elif operation.name in SINGLE_QUBIT_GATES:
params = getattr(operation, "params", None)
qubit = operation.qubits[0]
gate = single_gate_matrix(operation.name, params)
self._add_unitary(gate, [qubit])
# Check if CX gate
elif operation.name in TWO_QUBIT_GATES_WITH_PARAMETERS:
params = getattr(operation, "params", None)
qubit0 = operation.qubits[0]
qubit1 = operation.qubits[1]
gate = TWO_QUBIT_GATES_WITH_PARAMETERS[operation.name](*params).to_matrix()
self._add_unitary(gate, [qubit0, qubit1])
elif operation.name in ("id", "u0"):
pass
elif operation.name in ("CX", "cx"):
elif operation.name in TWO_QUBIT_GATES:
qubit0 = operation.qubits[0]
qubit1 = operation.qubits[1]
gate = cx_gate_matrix()
gate = TWO_QUBIT_GATES[operation.name]
self._add_unitary(gate, [qubit0, qubit1])
elif operation.name in THREE_QUBIT_GATES:
qubit0 = operation.qubits[0]
qubit1 = operation.qubits[1]
qubit2 = operation.qubits[2]
gate = THREE_QUBIT_GATES[operation.name]
self._add_unitary(gate, [qubit0, qubit1, qubit2])
# Check if reset
elif operation.name == "reset":
qubit = operation.qubits[0]
Expand Down
43 changes: 43 additions & 0 deletions releasenotes/notes/fixes_10852-e197344c5f44b4f1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
upgrade_providers:
- |
The :class:`.BasicSimulator` python-based simulator included in :mod:`qiskit.providers.basic_provider`
now includes all the standard gates (:mod:`qiskit.circuit.library .standard_gates`) up to 3 qubits. The new basis support includes:
Copy link
Member

Choose a reason for hiding this comment

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

This is maybe a feature rather than an upgrade? Fwiw, I probably wouldn't bother listing all the gates below - "includes all the standard gates in :mod:`qiskit.circuit.library`" is descriptive enough.

Copy link
Member Author

Choose a reason for hiding this comment

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

done in e81740e

``ccx`` (:class:`.CCXGate`),
``ccz`` (:class:`.CCZGate`),
``ch`` (:class:`.CHGate`),
``cp`` (:class:`.CPhaseGate`),
``crx`` (:class:`.CRXGate`),
``cry`` (:class:`.CRYGate`),
``crz`` (:class:`.CRZGate`),
``cs`` (:class:`.CSGate`),
``csdg`` (:class:`.CSdgGate`),
``cswap`` (:class:`.CSwapGate`),
``csx`` (:class:`.CSXGate`),
``cu`` (:class:`.CUGate`),
``cu1`` (:class:`.CU1Gate`),
``cu3`` (:class:`.CU3Gate`),
``cy`` (:class:`.CYGate`),
``cz`` (:class:`.CZGate`),
``dcx`` (:class:`.DCXGate`),
``ecr`` (:class:`.ECRGate`),
``global_phase`` (:class:`.GlobalPhaseGate`),
``id`` (:class:`.IGate`),
``iswap`` (:class:`.iSwapGate`),
``r`` (:class:`.RGate`),
``rccx`` (:class:`.RCCXGate`),
``rx`` (:class:`.RXGate`),
``rxx`` (:class:`.RXXGate`),
``ry`` (:class:`.RYGate`),
``ryy`` (:class:`.RYYGate`),
``rz`` (:class:`.RZGate`),
``rzz`` (:class:`.RZZGate`),
``s`` (:class:`.SGate`),
``sdg`` (:class:`.SdgGate`),
``swap`` (:class:`.SwapGate`),
``sx`` (:class:`.SXGate`),
``sdgx`` (:class:`.SdgXGate`),
``t`` (:class:`.TGate`),
``tdg`` (:class:`.TdgGate`),
``y`` (:class:`.YGate`), and
``z`` (:class:`.ZGate`).
Loading
Loading