-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d2d6301
commit afe6c6c
Showing
8 changed files
with
306 additions
and
127 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
from typing import Dict, Optional | ||
import pytest | ||
from quam.components import Qubit, QubitPair | ||
from quam.components.channels import IQChannel | ||
from quam.core.quam_classes import QuamRoot, quam_dataclass | ||
from dataclasses import field | ||
|
||
|
||
@quam_dataclass | ||
class MockQubit(Qubit): | ||
xy: IQChannel | ||
resonator: Optional[IQChannel] = None | ||
|
||
|
||
@quam_dataclass | ||
class TestQUAM(QuamRoot): | ||
qubits: Dict[str, MockQubit] = field(default_factory=dict) | ||
qubit_pairs: Dict[str, QubitPair] = field(default_factory=dict) | ||
|
||
|
||
@pytest.fixture | ||
def mock_qubit(): | ||
"""Basic mock qubit with xy channel""" | ||
return MockQubit( | ||
id="q0", | ||
xy=IQChannel( | ||
opx_output_I=("con1", 1), | ||
opx_output_Q=("con1", 2), | ||
frequency_converter_up=None, | ||
), | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def mock_qubit_with_resonator(): | ||
"""Mock qubit with both xy and resonator channels""" | ||
return MockQubit( | ||
id="q1", | ||
xy=IQChannel( | ||
opx_output_I=("con1", 1), | ||
opx_output_Q=("con1", 2), | ||
frequency_converter_up=None, | ||
), | ||
resonator=IQChannel( | ||
opx_output_I=("con1", 3), | ||
opx_output_Q=("con1", 4), | ||
frequency_converter_up=None, | ||
), | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def test_quam(mock_qubit, mock_qubit_with_resonator): | ||
"""Test QUAM instance with qubits and qubit pairs""" | ||
machine = TestQUAM( | ||
qubits={"q0": mock_qubit, "q1": mock_qubit_with_resonator}, | ||
) | ||
machine.qubit_pairs["pair_0"] = QubitPair( | ||
qubit_control=mock_qubit.get_reference(), | ||
qubit_target=mock_qubit_with_resonator.get_reference(), | ||
) | ||
return machine |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
from typing import Optional | ||
import pytest | ||
from quam.components import Qubit | ||
from quam.components.channels import IQChannel | ||
from quam.components.pulses import SquarePulse | ||
from quam.core.quam_classes import QuamRoot, quam_dataclass | ||
|
||
|
||
def test_qubit_name_int(): | ||
qubit = Qubit(id=0) | ||
assert qubit.name == "q0" | ||
|
||
|
||
def test_qubit_name_str(): | ||
qubit = Qubit(id="qubit0") | ||
assert qubit.name == "qubit0" | ||
|
||
|
||
def test_qubit_channels(mock_qubit_with_resonator): | ||
assert mock_qubit_with_resonator.channels == { | ||
"xy": mock_qubit_with_resonator.xy, | ||
"resonator": mock_qubit_with_resonator.resonator, | ||
} | ||
|
||
|
||
def test_qubit_channels_referenced(mock_qubit): | ||
# Set resonator as a reference to xy channel | ||
mock_qubit.resonator = "#./xy" | ||
|
||
assert mock_qubit.channels == { | ||
"xy": mock_qubit.xy, | ||
"resonator": mock_qubit.xy, | ||
} | ||
|
||
|
||
def test_qubit_get_pulse_not_found(mock_qubit): | ||
with pytest.raises(ValueError, match="Pulse test_pulse not found"): | ||
mock_qubit.get_pulse("test_pulse") | ||
|
||
|
||
def test_qubit_get_pulse_not_unique(mock_qubit_with_resonator): | ||
mock_qubit_with_resonator.xy.operations["test_pulse"] = SquarePulse( | ||
length=100, amplitude=1.0 | ||
) | ||
mock_qubit_with_resonator.resonator.operations["test_pulse"] = SquarePulse( | ||
length=100, amplitude=1.0 | ||
) | ||
|
||
with pytest.raises(ValueError, match="Pulse test_pulse is not unique"): | ||
mock_qubit_with_resonator.get_pulse("test_pulse") | ||
|
||
|
||
def test_qubit_get_pulse_unique(mock_qubit): | ||
pulse = SquarePulse(length=100, amplitude=1.0) | ||
mock_qubit.xy.operations["test_pulse"] = pulse | ||
|
||
assert mock_qubit.get_pulse("test_pulse") == pulse | ||
|
||
|
||
def test_qubit_align(mock_qubit_with_resonator, mocker): | ||
mocker.patch("quam.components.quantum_components.qubit.align") | ||
mock_qubit_with_resonator.align(mock_qubit_with_resonator) | ||
|
||
from quam.components.quantum_components.qubit import align | ||
|
||
align.assert_called_once_with("q1.xy", "q1.resonator") | ||
|
||
|
||
def test_qubit_get_macros(mock_qubit): | ||
assert mock_qubit.macros == {} | ||
assert mock_qubit.get_macros() == {"align": mock_qubit.align} | ||
|
||
|
||
def test_qubit_apply_align(mock_qubit_with_resonator, mocker): | ||
mocker.patch("quam.components.quantum_components.qubit.align") | ||
mock_qubit_with_resonator.apply("align") | ||
|
||
from quam.components.quantum_components.qubit import align | ||
|
||
align.assert_called_once_with("q1.xy", "q1.resonator") | ||
|
||
|
||
def test_qubit_inferred_id_direct(): | ||
"""Test inferred_id when id is a direct value""" | ||
qubit = Qubit(id=0) | ||
assert qubit.inferred_id == 0 | ||
|
||
|
||
def test_qubit_inferred_id_with_parent(test_quam): | ||
"""Test inferred_id when id is a reference and qubit has parent""" | ||
test_quam.qubits["q2"] = Qubit() | ||
assert test_quam.qubits["q2"].inferred_id == "q2" | ||
|
||
|
||
def test_qubit_inferred_id_no_parent(): | ||
"""Test inferred_id when id is a reference but qubit has no parent""" | ||
qubit = Qubit(id="#./inferred_id") | ||
with pytest.raises( | ||
AttributeError, match="Cannot infer id .* not attached to a parent" | ||
): | ||
_ = qubit.inferred_id |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
from typing import Dict, List | ||
import pytest | ||
from quam.components import Qubit, QubitPair | ||
from quam.components.channels import IQChannel | ||
from quam.core.quam_classes import QuamRoot, quam_dataclass | ||
|
||
|
||
@quam_dataclass | ||
class MockQubit(Qubit): | ||
xy: IQChannel = None | ||
|
||
|
||
@quam_dataclass | ||
class MockQubitPair(QubitPair): | ||
qubit_control: MockQubit | ||
qubit_target: MockQubit | ||
|
||
|
||
@quam_dataclass | ||
class QUAM(QuamRoot): | ||
qubits: Dict[str, MockQubit] | ||
qubit_pairs: str[str, MockQubitPair] | ||
|
||
|
||
@pytest.fixture | ||
def test_qubit_control(): | ||
return MockQubit( | ||
id="q1", | ||
xy=IQChannel( | ||
id="xy_control", | ||
opx_output_I=("con1", 1), | ||
opx_output_Q=("con1", 2), | ||
frequency_converter_up=None, | ||
), | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def test_qubit_target(): | ||
return MockQubit( | ||
id="q2", | ||
xy=IQChannel( | ||
id="xy_target", | ||
opx_output_I=("con1", 5), | ||
opx_output_Q=("con1", 6), | ||
frequency_converter_up=None, | ||
), | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def test_qubit_pair(test_qubit_control, test_qubit_target): | ||
return MockQubitPair( | ||
id="pair_1", | ||
qubit_control=test_qubit_control, | ||
qubit_target=test_qubit_target | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def test_quam(test_qubit_control, test_qubit_target, test_qubit_pair): | ||
return QUAM( | ||
qubits={"control": test_qubit_control, "target": test_qubit_target}, | ||
qubit_pairs=[test_qubit_pair], | ||
) | ||
|
||
|
||
def test_qubit_pair_initialization(test_qubit_pair, test_qubit_control, test_qubit_target): | ||
"""Test that QubitPair is initialized correctly""" | ||
assert test_qubit_pair.qubit_control == test_qubit_control | ||
assert test_qubit_pair.qubit_target == test_qubit_target | ||
assert test_qubit_pair.name == "pair_1" | ||
assert isinstance(test_qubit_pair.macros, dict) | ||
assert len(test_qubit_pair.macros) == 0 | ||
|
||
|
||
def test_qubit_pair_align(test_qubit_pair, mocker): | ||
"""Test that align method calls the control qubit's align method with correct args""" | ||
mock_align = mocker.patch.object(test_qubit_pair.qubit_control, 'align') | ||
|
||
test_qubit_pair.align() | ||
|
||
mock_align.assert_called_once_with(test_qubit_pair.qubit_target) | ||
|
||
|
||
def test_qubit_pair_via_matmul(test_quam): | ||
"""Test that qubit pair can be accessed via @ operator""" | ||
control = test_quam.qubits["control"] | ||
target = test_quam.qubits["target"] | ||
|
||
qubit_pair = control @ target | ||
|
||
assert isinstance(qubit_pair, QubitPair) | ||
assert qubit_pair.qubit_control == control | ||
assert qubit_pair.qubit_target == target | ||
|
||
|
||
def test_matmul_with_invalid_qubit(test_quam): | ||
"""Test that @ operator raises error for invalid qubit pairs""" | ||
control = test_quam.qubits["control"] | ||
|
||
with pytest.raises(ValueError, match="Cannot create a qubit pair with same qubit"): | ||
_ = control @ control | ||
|
||
with pytest.raises(ValueError, match="Cannot create a qubit pair .* with a non-qubit object"): | ||
_ = control @ "not_a_qubit" | ||
|
||
|
||
def test_matmul_with_nonexistent_pair(test_quam): | ||
"""Test that @ operator raises error for non-existent qubit pairs""" | ||
target = test_quam.qubits["target"] | ||
control = test_quam.qubits["control"] | ||
|
||
# Try to access pair in reverse order (target @ control) when only (control @ target) exists | ||
with pytest.raises(ValueError, match="Qubit pair not found"): | ||
_ = target @ control |
Oops, something went wrong.