Skip to content

Commit 9d60f2c

Browse files
rares1609Oanceaelenbaasc
authored
[CQT-309] Create native gate checker (#427)
* Added native gate checker * Implemented Feedback * Implemented Feedback * Update CHANGELOG.md Co-authored-by: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> * Update opensquirrel/passes/validator/general_validator.py Co-authored-by: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> * Update opensquirrel/passes/validator/native_gate_validator.py Co-authored-by: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> * Update opensquirrel/passes/validator/native_gate_validator.py Co-authored-by: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> * Update test/test_integration.py Co-authored-by: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> * Update test/test_integration.py Co-authored-by: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> * Implemented feedback * . * . * Change fixture names * Resolve previous comments and modify tests --------- Co-authored-by: Oancea <rares.oancea@tno.nl> Co-authored-by: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com>
1 parent 09ba895 commit 9d60f2c

File tree

7 files changed

+115
-4
lines changed

7 files changed

+115
-4
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1212

1313
## [ 0.3.0 ] - [ xxxx-yy-zz ]
1414

15+
### Added
16+
17+
- `NativeGateValidator` validator pass
18+
1519

1620
## [ 0.2.0 ] - [ 2025-01-21 ]
1721

opensquirrel/circuit.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
from opensquirrel.ir import IR, Gate
1010
from opensquirrel.passes.decomposer import Decomposer
1111
from opensquirrel.passes.mapper import Mapper
12-
from opensquirrel.passes.merger.general_merger import Merger
13-
from opensquirrel.passes.router.general_router import Router
12+
from opensquirrel.passes.merger import Merger
13+
from opensquirrel.passes.router import Router
14+
from opensquirrel.passes.validator import Validator
1415
from opensquirrel.register_manager import RegisterManager
1516

1617

@@ -87,8 +88,12 @@ def qubit_register_name(self) -> str:
8788
def bit_register_name(self) -> str:
8889
return self.register_manager.get_bit_register_name()
8990

91+
def validate(self, validator: Validator) -> None:
92+
"""Generic validator pass. It applies the given validator to the circuit."""
93+
validator.validate(self.ir)
94+
9095
def route(self, router: Router) -> None:
91-
"""Generic router pass. It applies the given Router to the circuit."""
96+
"""Generic router pass. It applies the given router to the circuit."""
9297
router.route(self.ir)
9398

9499
def merge(self, merger: Merger) -> None:
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""Init file for the validator passes."""
2+
3+
from opensquirrel.passes.validator.general_validator import Validator
4+
from opensquirrel.passes.validator.native_gate_validator import NativeGateValidator
5+
6+
__all__ = ["NativeGateValidator", "Validator"]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from abc import ABC, abstractmethod
2+
3+
from opensquirrel.ir import IR
4+
5+
6+
class Validator(ABC):
7+
@abstractmethod
8+
def validate(self, ir: IR) -> None:
9+
"""Base validate method to be implemented by inheriting validator classes."""
10+
raise NotImplementedError
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from opensquirrel.ir import IR, Unitary
2+
from opensquirrel.passes.validator import Validator
3+
4+
5+
class NativeGateValidator(Validator):
6+
def __init__(self, native_gate_set: list[str]) -> None:
7+
self.native_gate_set = native_gate_set
8+
9+
def validate(self, ir: IR) -> None:
10+
"""
11+
Check if all unitary gates in the circuit are part of the native gate set.
12+
13+
Args:
14+
ir (IR): The intermediate representation of the circuit to be checked.
15+
16+
Raises:
17+
ValueError: If any unitary gate in the circuit is not part of the native gate set.
18+
"""
19+
gates_not_in_native_gate_set = [
20+
statement.name
21+
for statement in ir.statements
22+
if isinstance(statement, Unitary) and statement.name not in self.native_gate_set
23+
]
24+
if gates_not_in_native_gate_set:
25+
error_message = f"The following gates are not in the native gate set: {set(gates_not_in_native_gate_set)}"
26+
raise ValueError(error_message)

test/test_integration.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from opensquirrel.passes.exporter import ExportFormat
1818
from opensquirrel.passes.merger import SingleQubitGatesMerger
1919
from opensquirrel.passes.router import RoutingChecker
20+
from opensquirrel.passes.validator import NativeGateValidator
2021

2122

2223
def test_spin2plus_backend() -> None:
@@ -47,8 +48,12 @@ def test_spin2plus_backend() -> None:
4748

4849
# Check whether the above algorithm can be mapped to a dummy chip topology
4950
connectivity = {"0": [1], "1": [0]}
51+
native_gate_set = ["I", "X90", "mX90", "Y90", "mY90", "Rz", "CZ"]
5052

51-
qc.route(router=RoutingChecker(connectivity=connectivity))
53+
qc.route(router=RoutingChecker(connectivity))
54+
55+
# Decompose 2-qubit gates to a decomposition where the 2-qubit interactions are captured by CNOT gates
56+
qc.decompose(decomposer=CNOTDecomposer())
5257

5358
qc.decompose(decomposer=SWAP2CNOTDecomposer())
5459

@@ -64,6 +69,9 @@ def test_spin2plus_backend() -> None:
6469
# Decompose single-qubit gates to spin backend native gates with McKay decomposer
6570
qc.decompose(decomposer=McKayDecomposer())
6671

72+
# Check whether the gates in the circuit match the native gate set of the backend
73+
qc.validate(validator=NativeGateValidator(native_gate_set))
74+
6775
assert (
6876
str(qc)
6977
== """version 3.0
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Tests for native gate checker pass
2+
import pytest
3+
4+
from opensquirrel import CircuitBuilder
5+
from opensquirrel.circuit import Circuit
6+
from opensquirrel.passes.validator import NativeGateValidator
7+
8+
9+
@pytest.fixture(name="validator")
10+
def validator_fixture() -> NativeGateValidator:
11+
native_gate_set = ["I", "X90", "mX90", "Y90", "mY90", "Rz", "CZ"]
12+
return NativeGateValidator(native_gate_set)
13+
14+
15+
@pytest.fixture
16+
def circuit_with_matching_gate_set() -> Circuit:
17+
builder = CircuitBuilder(5)
18+
builder.I(0)
19+
builder.X90(1)
20+
builder.mX90(2)
21+
builder.Y90(3)
22+
builder.mY90(4)
23+
builder.Rz(0, 2)
24+
builder.CZ(1, 2)
25+
return builder.to_circuit()
26+
27+
28+
@pytest.fixture
29+
def circuit_with_unmatching_gate_set() -> Circuit:
30+
builder = CircuitBuilder(5)
31+
builder.I(0)
32+
builder.X90(1)
33+
builder.mX90(2)
34+
builder.Y90(3)
35+
builder.mY90(4)
36+
builder.Rz(0, 2)
37+
builder.CZ(1, 2)
38+
builder.H(0)
39+
builder.CNOT(1, 2)
40+
return builder.to_circuit()
41+
42+
43+
def test_matching_gates(validator: NativeGateValidator, circuit_with_matching_gate_set: Circuit) -> None:
44+
try:
45+
validator.validate(circuit_with_matching_gate_set.ir)
46+
except ValueError:
47+
pytest.fail("validate() raised ValueError unexpectedly")
48+
49+
50+
def test_non_matching_gates(validator: NativeGateValidator, circuit_with_unmatching_gate_set: Circuit) -> None:
51+
with pytest.raises(ValueError, match="The following gates are not in the native gate set:.*"):
52+
validator.validate(circuit_with_unmatching_gate_set.ir)

0 commit comments

Comments
 (0)