Skip to content
Open
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
9 changes: 4 additions & 5 deletions opensquirrel/circuit_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from opensquirrel.circuit import Circuit
from opensquirrel.default_instructions import default_instruction_set
from opensquirrel.ir import IR, AsmDeclaration, Bit, BitLike, Instruction, Measure, Qubit, QubitLike
from opensquirrel.ir import IR, AsmDeclaration, Bit, BitLike, Instruction, Qubit, QubitLike
from opensquirrel.register_manager import BitRegister, QubitRegister, RegisterManager

_builder_dynamic_attributes = (*default_instruction_set, "asm")
Expand Down Expand Up @@ -75,12 +75,11 @@ def _check_bit_out_of_bounds_access(self, bit: BitLike) -> None:
raise IndexError(msg)

def _check_out_of_bounds_access(self, instruction: Instruction) -> None:
for qubit in instruction.get_qubit_operands():
for qubit in instruction.qubit_operands:
self._check_qubit_out_of_bounds_access(qubit)

if isinstance(instruction, Measure):
for bit in instruction.get_bit_operands():
self._check_bit_out_of_bounds_access(bit)
for bit in instruction.bit_operands:
self._check_bit_out_of_bounds_access(bit)

def _add_statement(self, attr: str, *args: Any) -> Self:
if attr == "asm":
Expand Down
11 changes: 8 additions & 3 deletions opensquirrel/ir/control_instruction.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from abc import ABC, abstractmethod
from typing import Any, SupportsInt

from opensquirrel.ir.expression import Expression, Int, Qubit, QubitLike
from opensquirrel.ir.expression import Bit, Expression, Int, Qubit, QubitLike
from opensquirrel.ir.ir import IRVisitor
from opensquirrel.ir.statement import Instruction

Expand All @@ -16,8 +16,13 @@ def __init__(self, qubit: QubitLike, name: str) -> None:
def arguments(self) -> tuple[Expression, ...]:
pass

def get_qubit_operands(self) -> list[Qubit]:
return [self.qubit]
@property
def qubit_operands(self) -> tuple[Qubit, ...]:
return (self.qubit,)

@property
def bit_operands(self) -> tuple[Bit, ...]:
return ()


class Barrier(ControlInstruction):
Expand Down
7 changes: 0 additions & 7 deletions opensquirrel/ir/default_gates/two_qubit_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ def __init__(self, qubit_0: QubitLike, qubit_1: QubitLike) -> None:
self.qubit_0 = Qubit(qubit_0)
self.qubit_1 = Qubit(qubit_1)

@property
def arguments(self) -> tuple[Expression, ...]:
return self.qubit_0, self.qubit_1

def get_qubit_operands(self) -> list[Qubit]:
return [self.qubit_0, self.qubit_1]


class CNOT(TwoQubitGate):
def __init__(self, control_qubit: QubitLike, target_qubit: QubitLike) -> None:
Expand Down
14 changes: 10 additions & 4 deletions opensquirrel/ir/non_unitary.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ def __init__(self, qubit: QubitLike, name: str) -> None:
def arguments(self) -> tuple[Expression, ...]:
pass

def get_qubit_operands(self) -> list[Qubit]:
return [self.qubit]
@property
def qubit_operands(self) -> tuple[Qubit, ...]:
return (self.qubit,)

@property
def bit_operands(self) -> tuple[Bit, ...]:
return ()

def accept(self, visitor: IRVisitor) -> Any:
return visitor.visit_non_unitary(self)
Expand Down Expand Up @@ -49,8 +54,9 @@ def accept(self, visitor: IRVisitor) -> Any:
non_unitary_visit = super().accept(visitor)
return non_unitary_visit if non_unitary_visit is not None else visitor.visit_measure(self)

def get_bit_operands(self) -> list[Bit]:
return [self.bit]
@property
def bit_operands(self) -> tuple[Bit, ...]:
return (self.bit,)


class Init(NonUnitary):
Expand Down
14 changes: 10 additions & 4 deletions opensquirrel/ir/single_qubit_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
from functools import cached_property
from typing import TYPE_CHECKING, Any

from opensquirrel.ir import Float, Gate, GateSemantic, Qubit, QubitLike
from opensquirrel.ir import Bit, Float, Gate, GateSemantic, Qubit, QubitLike
from opensquirrel.ir.semantics import BlochSphereRotation, MatrixGateSemantic

if TYPE_CHECKING:
from opensquirrel.ir.expression import Expression
from opensquirrel.ir.ir import IRVisitor


Expand Down Expand Up @@ -84,11 +85,16 @@ def __mul__(self, other: SingleQubitGate) -> SingleQubitGate:
return SingleQubitGate(self.qubit, self.bsr * other.bsr)

@property
def arguments(self) -> tuple[Qubit, ...]:
def arguments(self) -> tuple[Expression, ...]:
return ()

@property
def qubit_operands(self) -> tuple[Qubit, ...]:
return (self.qubit,)

def get_qubit_operands(self) -> list[Qubit]:
return [self.qubit]
@property
def bit_operands(self) -> tuple[Bit, ...]:
return ()

def is_identity(self) -> bool:
if self.bsr is not None:
Expand Down
14 changes: 12 additions & 2 deletions opensquirrel/ir/statement.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from abc import ABC, abstractmethod
from typing import Any

from opensquirrel.ir.expression import Expression, Qubit, String, SupportsStr
from opensquirrel.ir.expression import Bit, Expression, Qubit, String, SupportsStr
from opensquirrel.ir.ir import IRNode, IRVisitor


Expand Down Expand Up @@ -40,8 +40,18 @@ def __init__(self, name: str) -> None:
def arguments(self) -> tuple[Expression, ...]:
pass

@property
@abstractmethod
def qubit_operands(self) -> tuple[Qubit, ...]:
pass

@property
def qubit_indices(self) -> list[int]:
return [qubit.index for qubit in self.qubit_operands]

@property
@abstractmethod
def get_qubit_operands(self) -> list[Qubit]:
def bit_operands(self) -> tuple[Bit, ...]:
pass

def accept(self, visitor: IRVisitor) -> Any:
Expand Down
13 changes: 9 additions & 4 deletions opensquirrel/ir/two_qubit_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import numpy as np

from opensquirrel.ir import Gate, IRVisitor, Qubit, QubitLike
from opensquirrel.ir import Bit, Gate, IRVisitor, Qubit, QubitLike
from opensquirrel.ir.expression import Expression
from opensquirrel.ir.semantics import CanonicalGateSemantic, ControlledGateSemantic, MatrixGateSemantic
from opensquirrel.ir.semantics.gate_semantic import GateSemantic
Expand All @@ -27,7 +27,7 @@ def __init__(
msg = "the qubit from the target gate does not match with 'qubit1'."
raise ValueError(msg)

if self._check_repeated_qubit_operands([self.qubit0, self.qubit1]):
if self._check_repeated_qubit_operands(self.qubit_operands):
msg = "qubit0 and qubit1 cannot be the same"
raise ValueError(msg)

Expand Down Expand Up @@ -63,10 +63,15 @@ def accept(self, visitor: IRVisitor) -> Any:

@property
def arguments(self) -> tuple[Expression, ...]:
return ()

@property
def qubit_operands(self) -> tuple[Qubit, ...]:
return (self.qubit0, self.qubit1)

def get_qubit_operands(self) -> list[Qubit]:
return [self.qubit0, self.qubit1]
@property
def bit_operands(self) -> tuple[Bit, ...]:
return ()

def is_identity(self) -> bool:
if self.controlled:
Expand Down
6 changes: 1 addition & 5 deletions opensquirrel/ir/unitary.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ def __init__(self, name: str) -> None:
def _check_repeated_qubit_operands(qubits: Sequence[Qubit]) -> bool:
return len(qubits) != len(set(qubits))

@abstractmethod
def get_qubit_operands(self) -> list[Qubit]:
pass

@abstractmethod
def is_identity(self) -> bool:
pass
Expand All @@ -43,7 +39,7 @@ def __eq__(self, other: object) -> bool:


def compare_gates(g1: Gate, g2: Gate) -> bool:
union_mapping = [q.index for q in list(set(g1.get_qubit_operands()) | set(g2.get_qubit_operands()))]
union_mapping = [q.index for q in list(set(g1.qubit_operands) | set(g2.qubit_operands))]

from opensquirrel.circuit_matrix_calculator import get_circuit_matrix
from opensquirrel.reindexer import get_reindexed_circuit
Expand Down
2 changes: 1 addition & 1 deletion opensquirrel/passes/decomposer/cnot2cz_decomposer.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def decompose(self, gate: Gate) -> list[Gate]:
if gate.name != "CNOT":
return [gate]

control_qubit, target_qubit = gate.get_qubit_operands()
control_qubit, target_qubit = gate.qubit_operands
return [
Ry(target_qubit, -pi / 2),
CZ(control_qubit, target_qubit),
Expand Down
2 changes: 1 addition & 1 deletion opensquirrel/passes/decomposer/cz_decomposer.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def decompose(self, g: Gate) -> list[Gate]:
# - decomposing MatrixGate is currently not supported.
return [g]

control_qubit, target_qubit = g.get_qubit_operands()
control_qubit, target_qubit = g.qubit_operands
target_gate = g.controlled.target_gate

# Perform XYX decomposition on the target gate.
Expand Down
6 changes: 3 additions & 3 deletions opensquirrel/passes/decomposer/general_decomposer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ def decompose(self, gate: Gate) -> list[Gate]:


def check_gate_replacement(gate: Gate, replacement_gates: Iterable[Gate]) -> None:
gate_qubit_indices = [q.index for q in gate.get_qubit_operands()]
gate_qubit_indices = gate.qubit_indices
replacement_gates_qubit_indices = set()
replaced_matrix = get_circuit_matrix(get_reindexed_circuit([gate], gate_qubit_indices))

if is_identity_matrix_up_to_a_global_phase(replaced_matrix):
return

for g in replacement_gates:
replacement_gates_qubit_indices.update([q.index for q in g.get_qubit_operands()])
replacement_gates_qubit_indices.update(g.qubit_indices)

if set(gate_qubit_indices) != replacement_gates_qubit_indices:
msg = f"replacement for gate {gate.name} does not seem to operate on the right qubits"
Expand Down Expand Up @@ -70,7 +70,7 @@ def __init__(self, gate_type: type[Gate], replacement_gates_function: Callable[.
def decompose(self, gate: Gate) -> list[Gate]:
if is_anonymous_gate(gate.name) or type(gate) is not self.gate_type:
return [gate]
return self.replacement_gates_function(*gate.arguments)
return self.replacement_gates_function(*gate.qubit_operands, *gate.arguments)


def replace(ir: IR, gate: type[Gate], replacement_gates_function: Callable[..., list[Gate]]) -> None:
Expand Down
2 changes: 1 addition & 1 deletion opensquirrel/passes/decomposer/swap2cnot_decomposer.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class SWAP2CNOTDecomposer(Decomposer):
def decompose(self, gate: Gate) -> list[Gate]:
if gate.name != "SWAP":
return [gate]
qubit0, qubit1 = gate.get_qubit_operands()
qubit0, qubit1 = gate.qubit_operands
return [
CNOT(qubit0, qubit1),
CNOT(qubit1, qubit0),
Expand Down
2 changes: 1 addition & 1 deletion opensquirrel/passes/decomposer/swap2cz_decomposer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class SWAP2CZDecomposer(Decomposer):
def decompose(self, gate: Gate) -> list[Gate]:
if gate.name != "SWAP":
return [gate]
qubit0, qubit1 = gate.get_qubit_operands()
qubit0, qubit1 = gate.qubit_operands
return [
Ry(qubit1, -pi / 2),
CZ(qubit0, qubit1),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,11 @@ def visit_two_qubit_gate(self, gate: TwoQubitGate) -> Any:
qubit_operand_0 = gate.qubit0.accept(self)
qubit_operand_1 = gate.qubit1.accept(self)

if len(gate.arguments) == 2:
self.output += f"{gate.name.lower()} {qubit_operand_0}, {qubit_operand_1}\n"
elif len(gate.arguments) == 3:
_, _, arg = gate.arguments
argument = arg.accept(self)
self.output += f"{gate.name.lower()}({argument}) {qubit_operand_0}, {qubit_operand_1}\n"
if gate.arguments:
arguments = ", ".join(arg.accept(self) for arg in gate.arguments)
self.output += f"{gate.name.lower()}({arguments}) {qubit_operand_0}, {qubit_operand_1}\n"
else:
raise UnsupportedGateError(gate)
self.output += f"{gate.name.lower()} {qubit_operand_0}, {qubit_operand_1}\n"

def visit_cr(self, gate: CR) -> None:
control_qubit_operand = gate.control_qubit.accept(self)
Expand Down
24 changes: 11 additions & 13 deletions opensquirrel/passes/exporter/quantify_scheduler_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,10 @@ def operation_record(self) -> OperationRecord:
return self._operation_record

def visit_gate(self, gate: Gate) -> None:
qubit_indices = [qubit.index for qubit in gate.get_qubit_operands()]
self._operation_record.set_schedulable_timing_constraints(qubit_indices)
self._operation_record.set_schedulable_timing_constraints(gate.qubit_indices)

def visit_non_unitary(self, non_unitary: NonUnitary) -> None:
qubit_indices = [qubit.index for qubit in non_unitary.get_qubit_operands()]
self._operation_record.set_schedulable_timing_constraints(qubit_indices)
self._operation_record.set_schedulable_timing_constraints(non_unitary.qubit_indices)

def visit_control_instruction(self, control_instruction: ControlInstruction) -> None:
if isinstance(control_instruction, Wait):
Expand Down Expand Up @@ -228,7 +226,7 @@ def visit_single_qubit_gate(self, gate: SingleQubitGate) -> None:
# Hadamard gate.
self.schedule.add(
quantify_scheduler.operations.gate_library.H(self._get_qubit_string(gate.qubit)),
label=self._get_operation_label("H", gate.get_qubit_operands()),
label=self._get_operation_label("H", gate.qubit_operands),
)
return
if abs(gate.bsr.axis[2]) < ATOL:
Expand All @@ -240,15 +238,15 @@ def visit_single_qubit_gate(self, gate: SingleQubitGate) -> None:
quantify_scheduler.operations.gate_library.Rxy(
theta=theta, phi=phi, qubit=self._get_qubit_string(gate.qubit)
),
label=self._get_operation_label("Rxy", gate.get_qubit_operands()),
label=self._get_operation_label("Rxy", gate.qubit_operands),
)
return
if abs(gate.bsr.axis[0]) < ATOL and abs(gate.bsr.axis[1]) < ATOL:
# Rz rotation.
theta = round(math.degrees(gate.bsr.angle), FIXED_POINT_DEG_PRECISION)
self.schedule.add(
quantify_scheduler.operations.gate_library.Rz(theta=theta, qubit=self._get_qubit_string(gate.qubit)),
label=self._get_operation_label("Rz", gate.get_qubit_operands()),
label=self._get_operation_label("Rz", gate.qubit_operands),
)
return
raise UnsupportedGateError(gate)
Expand All @@ -257,23 +255,23 @@ def visit_two_qubit_gate(self, gate: TwoQubitGate) -> Any:
if gate.name not in ["CNOT", "CZ"]:
raise UnsupportedGateError(gate)

control_qubit, target_qubit = gate.get_qubit_operands()
control_qubit, target_qubit = gate.qubit_operands

if gate.name == "CNOT":
self.schedule.add(
quantify_scheduler.operations.gate_library.CNOT(
qC=self._get_qubit_string(control_qubit),
qT=self._get_qubit_string(target_qubit),
),
label=self._get_operation_label("CNOT", gate.get_qubit_operands()),
label=self._get_operation_label("CNOT", gate.qubit_operands),
)
if gate.name == "CZ":
self.schedule.add(
quantify_scheduler.operations.gate_library.CZ(
qC=self._get_qubit_string(control_qubit),
qT=self._get_qubit_string(target_qubit),
),
label=self._get_operation_label("CZ", gate.get_qubit_operands()),
label=self._get_operation_label("CZ", gate.qubit_operands),
)

def visit_measure(self, gate: Measure) -> None:
Expand All @@ -286,7 +284,7 @@ def visit_measure(self, gate: Measure) -> None:
acq_index=acq_index,
acq_protocol="ThresholdedAcquisition",
),
label=self._get_operation_label("Measure", gate.get_qubit_operands()),
label=self._get_operation_label("Measure", gate.qubit_operands),
)
self.measurement_index_record[qubit_index] += 1

Expand All @@ -296,12 +294,12 @@ def visit_init(self, gate: Init) -> None:
def visit_reset(self, gate: Reset) -> None:
self.schedule.add(
quantify_scheduler.operations.gate_library.Reset(self._get_qubit_string(gate.qubit)),
label=self._get_operation_label("Reset", gate.get_qubit_operands()),
label=self._get_operation_label("Reset", gate.qubit_operands),
)

def _get_qubit_string(self, qubit: Qubit) -> str:
return f"{self.circuit.qubit_register_name}[{qubit.index}]"

def _get_operation_label(self, name: str, qubits: list[Qubit]) -> str:
def _get_operation_label(self, name: str, qubits: tuple[Qubit, ...]) -> str:
qubit_operands = ", ".join([self._get_qubit_string(qubit) for qubit in qubits])
return f"{name} {qubit_operands} | " + str(uuid4())
Loading