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
8 changes: 8 additions & 0 deletions opensquirrel/default_instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@
**default_bsr_with_param_set,
}

default_two_qubit_gate_with_param_set: dict[str, type[TwoQubitGate]] = {
"CRk": CRk,
"CR": CR,
}

default_two_qubit_gate_set: dict[str, type[TwoQubitGate]] = {
"CNOT": CNOT,
"CR": CR,
Expand Down Expand Up @@ -116,6 +121,7 @@
"Identity": I,
"Toffoli": CCX,
}

default_gate_set: dict[str, type[Gate]] = {
**default_single_qubit_gate_set,
**default_two_qubit_gate_set,
Expand All @@ -128,10 +134,12 @@
"measure": Measure,
"reset": Reset,
}

default_control_instruction_set: dict[str, type[ControlInstruction]] = {
"barrier": Barrier,
"wait": Wait,
}

default_instruction_set: dict[str, type[Instruction]] = {
**default_gate_set,
**default_non_unitary_set,
Expand Down
54 changes: 51 additions & 3 deletions opensquirrel/ir/two_qubit_gate.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,60 @@
from __future__ import annotations

from functools import cached_property
from typing import Any
from typing import TYPE_CHECKING, Any

import numpy as np

from opensquirrel.ir import Gate, IRVisitor, Qubit, QubitLike
from opensquirrel.ir.semantics import CanonicalGateSemantic, ControlledGateSemantic, MatrixGateSemantic
from opensquirrel.ir.semantics import (
CanonicalGateSemantic,
ControlledGateSemantic,
MatrixGateSemantic,
)
from opensquirrel.ir.semantics.bsr import bsr_from_matrix
from opensquirrel.ir.semantics.gate_semantic import GateSemantic

if TYPE_CHECKING:
from opensquirrel.ir.semantics.gate_semantic import GateSemantic


def try_match_replace_with_default_two_qubit_gate(gate: TwoQubitGate) -> TwoQubitGate:
"""Tries to match a given two-qubit gate with a _default_ two-qubit gate.
It does that by checking if the two-qubit gates matches one of the _default_ two-qubit gates.

Note:
- The default (two-qubit) gates are defined in the
[cQASM standard gate set](https://qutech-delft.github.io/cQASM-spec/latest/standard_gate_set/index.html).
- If no specific match is found, the input gate is returned unmodified.
- The parameterized two-qubit gates (e.g., CR, CRk) are not included in the default two-qubit gate set.

Args:
gate: The two-qubit gate to be matched.

Returns:
A default two-qubit gate if this two-qubit gate matches it, otherwise return the input gate.

"""
from opensquirrel.default_instructions import (
default_two_qubit_gate_set,
default_two_qubit_gate_with_param_set,
)

if gate.name in default_two_qubit_gate_set:
return gate
Comment thread
elenbaasc marked this conversation as resolved.
Resolved

default_gates = {
gate_name: gate_type
for gate_name, gate_type in default_two_qubit_gate_set.items()
if gate_name not in default_two_qubit_gate_with_param_set
}

for gate_type in default_gates.values():
arguments: tuple[Any, ...] = (gate.qubit0, gate.qubit1)
possible_gate = gate_type(*arguments) # ty: ignore[missing-argument]
if possible_gate == gate:
return possible_gate

return gate


class TwoQubitGate(Gate):
Expand Down
3 changes: 2 additions & 1 deletion opensquirrel/writer/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
)
from opensquirrel.ir.single_qubit_gate import SingleQubitGate, try_match_replace_with_default_gate
from opensquirrel.ir.three_qubit_gate import ThreeQubitGate
from opensquirrel.ir.two_qubit_gate import TwoQubitGate
from opensquirrel.ir.two_qubit_gate import TwoQubitGate, try_match_replace_with_default_two_qubit_gate
from opensquirrel.register_manager import RegisterManager


Expand Down Expand Up @@ -88,6 +88,7 @@ def visit_single_qubit_gate(self, gate: SingleQubitGate) -> None:
self.output += f"{gate.name}{bsr_parameters} {qubit_operand}\n"

def visit_two_qubit_gate(self, gate: TwoQubitGate) -> Any:
gate = try_match_replace_with_default_two_qubit_gate(gate)
qubit_operand_0 = gate.qubit0.accept(self)
qubit_operand_1 = gate.qubit1.accept(self)

Expand Down
43 changes: 41 additions & 2 deletions tests/ir/test_two_qubit_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,52 @@
import pytest
from numpy.typing import NDArray

from opensquirrel import CNOT, CV, DCNOT, ISWAP, SWAP, InvSqrtSWAP, SqrtISWAP, SqrtSWAP
from opensquirrel import CNOT, CV, CY, CZ, DCNOT, ECR, ISWAP, MS, SWAP, InvSqrtSWAP, M, SqrtISWAP, SqrtSWAP
from opensquirrel.ir import Qubit
from opensquirrel.ir.semantics import BlochSphereRotation, CanonicalGateSemantic, MatrixGateSemantic
from opensquirrel.ir.two_qubit_gate import TwoQubitGate
from opensquirrel.ir.two_qubit_gate import TwoQubitGate, try_match_replace_with_default_two_qubit_gate
from opensquirrel.utils.matrix_expander import can2, get_matrix


@pytest.mark.parametrize(
("gate", "default_gate"),
[
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(CNOT(1, 0), 2))), CNOT(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(CV(1, 0), 2))), CV(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(CY(1, 0), 2))), CY(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(CZ(1, 0), 2))), CZ(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(DCNOT(1, 0), 2))), DCNOT(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(ECR(1, 0), 2))), ECR(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(InvSqrtSWAP(1, 0), 2))), InvSqrtSWAP(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(ISWAP(1, 0), 2))), ISWAP(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(M(1, 0), 2))), M(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(MS(1, 0), 2))), MS(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(SqrtISWAP(1, 0), 2))), SqrtISWAP(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(SqrtSWAP(1, 0), 2))), SqrtSWAP(0, 1)),
(TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic(get_matrix(SWAP(1, 0), 2))), SWAP(0, 1)),
],
ids=[
"CNOT",
"CV",
"CY",
"CZ",
"DCNOT",
"ECR",
"InvSqrtSWAP",
"ISWAP",
"M",
"MS",
"SqrtISWAP",
"SqrtSWAP",
"SWAP",
],
)
def test_default_gate_matching(gate: TwoQubitGate, default_gate: TwoQubitGate) -> None:
matched_gate = try_match_replace_with_default_two_qubit_gate(gate)
assert matched_gate == default_gate
assert matched_gate.name == default_gate.name


class TestTwoQubitGate:
@pytest.fixture
def gate(self) -> TwoQubitGate:
Expand Down
7 changes: 2 additions & 5 deletions tests/writer/test_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from opensquirrel import CircuitBuilder
from opensquirrel.ir.expression import Axis
from opensquirrel.ir.semantics import BlochSphereRotation, ControlledGateSemantic, MatrixGateSemantic
from opensquirrel.ir.semantics import BlochSphereRotation, ControlledGateSemantic
from opensquirrel.ir.single_qubit_gate import SingleQubitGate
from opensquirrel.ir.two_qubit_gate import TwoQubitGate
from opensquirrel.writer import writer
Expand Down Expand Up @@ -213,9 +213,7 @@ def test_anonymous_gate() -> None:
gate_semantic=ControlledGateSemantic(target_bsr=BlochSphereRotation(axis=(1, 1, 1), angle=1.23, phase=0.0)),
)
)
builder.ir.add_gate(
TwoQubitGate(0, 1, gate_semantic=MatrixGateSemantic([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]))
)

builder.CR(0, 1, 1.234)
assert (
str(builder.to_circuit())
Expand All @@ -227,7 +225,6 @@ def test_anonymous_gate() -> None:
H q[0]
Rn(0.57735027, 0.57735027, 0.57735027, 1.23, 0.0) q[0]
TwoQubitGate(qubits=[(Qubit[0], Qubit[1])], gate_semantic=ControlledGateSemantic(target_bsr=BlochSphereRotation(axis=[0.57735 0.57735 0.57735], angle=1.23, phase=0.0)))
TwoQubitGate(qubits=[(Qubit[0], Qubit[1])], gate_semantic=MatrixGateSemantic(matrix=[[1.+0.j 0.+0.j 0.+0.j 0.+0.j] [0.+0.j 1.+0.j 0.+0.j 0.+0.j] [0.+0.j 0.+0.j 0.+0.j 1.+0.j] [0.+0.j 0.+0.j 1.+0.j 0.+0.j]]))
CR(1.234) q[0], q[1]
""" # ruff: ignore[line-too-long]
)
Expand Down
Loading