From d5afb0756f385c7c14a112472bc0e110e6087d16 Mon Sep 17 00:00:00 2001 From: Dean Poulos Date: Fri, 11 Oct 2024 19:18:01 +1100 Subject: [PATCH] Add quantitative regression tests for exact connectivity allocations. --- tests/wirer/test_add_dummy_line.py | 12 ++++- tests/wirer/test_wirer_channel_reuse.py | 28 ++++++++++- tests/wirer/test_wirer_constraining.py | 20 ++++++++ tests/wirer/test_wirer_digital.py | 14 +++++- tests/wirer/test_wirer_lf_and_mw.py | 66 ++++++++++++++++--------- tests/wirer/test_wirer_lf_and_octave.py | 54 +++++++++++++++----- tests/wirer/test_wirer_lf_charge.py | 22 ++++++--- 7 files changed, 170 insertions(+), 46 deletions(-) diff --git a/tests/wirer/test_add_dummy_line.py b/tests/wirer/test_add_dummy_line.py index db714b30..5120d0aa 100644 --- a/tests/wirer/test_add_dummy_line.py +++ b/tests/wirer/test_add_dummy_line.py @@ -1,3 +1,5 @@ +from dataclasses import asdict + import pytest from qualang_tools.wirer import Connectivity, allocate_wiring, visualize from qualang_tools.wirer.connectivity.element import Element, Reference @@ -22,7 +24,13 @@ def test_add_dummy_line(instruments_2lf_2mw): allocate_wiring(connectivity, instruments_2lf_2mw) - print(connectivity.elements) - if pytest.visualize_flag: visualize(connectivity.elements, instruments_2lf_2mw.available_channels) + + # regression test + test_element = connectivity.elements[Reference('test')] + for i, channel in enumerate(test_element.channels['ch']): + assert asdict(channel) == asdict([ + InstrumentChannelLfFemInput(con=1, port=1, slot=1), + InstrumentChannelLfFemOutput(con=1, port=6, slot=1) + ][i]) \ No newline at end of file diff --git a/tests/wirer/test_wirer_channel_reuse.py b/tests/wirer/test_wirer_channel_reuse.py index 433debf2..c3425651 100644 --- a/tests/wirer/test_wirer_channel_reuse.py +++ b/tests/wirer/test_wirer_channel_reuse.py @@ -1,6 +1,12 @@ +from dataclasses import asdict + import pytest from qualang_tools.wirer import * +from qualang_tools.wirer.connectivity.element import QubitReference +from qualang_tools.wirer.connectivity.wiring_spec import WiringLineType +from qualang_tools.wirer.instruments.instrument_channel import InstrumentChannelMwFemInput, \ + InstrumentChannelMwFemOutput, InstrumentChannelLfFemOutput visualize_flag = pytest.visualize_flag @@ -17,7 +23,25 @@ def test_5q_allocation_with_channel_reuse(instruments_2lf_2mw): allocate_wiring(connectivity, instruments_2lf_2mw, block_used_channels=False) - print(connectivity.elements) - if visualize_flag: visualize(connectivity.elements, instruments_2lf_2mw.available_channels) + + for qubit in [1, 3]: + # resonator lines re-used for qubits 1 & 3 + for i, channel in enumerate(connectivity.elements[QubitReference(index=qubit)].channels[WiringLineType.RESONATOR]): + assert asdict(channel) == asdict([ + InstrumentChannelMwFemInput(con=1, port=1, slot=3), + InstrumentChannelMwFemOutput(con=1, port=1, slot=3) + ][i]) + + # drive lines re-used for qubits 1 & 3 + for i, channel in enumerate(connectivity.elements[QubitReference(index=qubit)].channels[WiringLineType.DRIVE]): + assert asdict(channel) == asdict([ + InstrumentChannelMwFemOutput(con=1, port=2, slot=3) + ][i]) + + # flux lines re-used for qubits 1 & 3 + for i, channel in enumerate(connectivity.elements[QubitReference(index=qubit)].channels[WiringLineType.FLUX]): + assert asdict(channel) == asdict([ + InstrumentChannelLfFemOutput(con=1, port=1, slot=1), + ][i]) diff --git a/tests/wirer/test_wirer_constraining.py b/tests/wirer/test_wirer_constraining.py index dcddccf2..1500a2e3 100644 --- a/tests/wirer/test_wirer_constraining.py +++ b/tests/wirer/test_wirer_constraining.py @@ -1,6 +1,13 @@ +from dataclasses import asdict + import pytest from qualang_tools.wirer import * +from qualang_tools.wirer.connectivity.element import QubitReference +from qualang_tools.wirer.connectivity.wiring_spec import WiringLineType +from qualang_tools.wirer.instruments.instrument_channel import InstrumentChannelOpxPlusInput, \ + InstrumentChannelOpxPlusOutput, InstrumentChannelOpxPlusDigitalOutput, InstrumentChannelOctaveInput, \ + InstrumentChannelOctaveDigitalInput, InstrumentChannelOctaveOutput visualize_flag = pytest.visualize_flag @@ -23,6 +30,19 @@ def test_opx_plus_resonator_constraining(): if visualize_flag: visualize(connectivity.elements, instruments.available_channels) + # resonator lines should be hard-coded to I=9, Q=10, rf_out=1 + for i, channel in enumerate(connectivity.elements[QubitReference(index=1)].channels[WiringLineType.RESONATOR]): + assert asdict(channel) == asdict([ + InstrumentChannelOpxPlusInput(con=1, port=1, slot=None), + InstrumentChannelOpxPlusInput(con=1, port=2, slot=None), + InstrumentChannelOpxPlusOutput(con=1, port=9, slot=None), + InstrumentChannelOpxPlusOutput(con=1, port=10, slot=None), + InstrumentChannelOpxPlusDigitalOutput(con=1, port=1, slot=None), + InstrumentChannelOctaveInput(con=1, port=1, slot=None), + InstrumentChannelOctaveOutput(con=1, port=1, slot=None), + InstrumentChannelOctaveDigitalInput(con=1, port=1, slot=None) + ][i]) + def test_fix_attribute_equality(): """ Make sure that channels aren't considered equal just because their attributes diff --git a/tests/wirer/test_wirer_digital.py b/tests/wirer/test_wirer_digital.py index 967828c2..4a0b9c41 100644 --- a/tests/wirer/test_wirer_digital.py +++ b/tests/wirer/test_wirer_digital.py @@ -1,6 +1,11 @@ +from dataclasses import asdict + import pytest from qualang_tools.wirer import * +from qualang_tools.wirer.connectivity.element import QubitReference +from qualang_tools.wirer.connectivity.wiring_spec import WiringLineType +from qualang_tools.wirer.instruments.instrument_channel import InstrumentChannelMwFemDigitalOutput visualize_flag = pytest.visualize_flag @@ -16,7 +21,12 @@ def test_triggered_wiring_spec_generates_digital_channels(instruments_2lf_2mw): allocate_wiring(connectivity, instruments_2lf_2mw) - print(connectivity.elements) - if visualize_flag: visualize(connectivity.elements, instruments_2lf_2mw.available_channels) + + # assert digital trigger channel is present + for qubit in [1, 2]: + resonator_channels = connectivity.elements[QubitReference(index=qubit)].channels[WiringLineType.RESONATOR] + resonator_channels_as_dicts = [asdict(channel) for channel in resonator_channels] + + assert asdict(InstrumentChannelMwFemDigitalOutput(con=1, port=1, slot=3)) in resonator_channels_as_dicts \ No newline at end of file diff --git a/tests/wirer/test_wirer_lf_and_mw.py b/tests/wirer/test_wirer_lf_and_mw.py index bb28c841..d2fcafbc 100644 --- a/tests/wirer/test_wirer_lf_and_mw.py +++ b/tests/wirer/test_wirer_lf_and_mw.py @@ -1,26 +1,56 @@ +from dataclasses import asdict + import pytest from qualang_tools.wirer import * +from qualang_tools.wirer.connectivity.element import QubitReference, QubitPairReference +from qualang_tools.wirer.connectivity.wiring_spec import WiringLineType +from qualang_tools.wirer.instruments.instrument_channel import InstrumentChannelLfFemOutput, \ + InstrumentChannelMwFemOutput, InstrumentChannelMwFemInput visualize_flag = pytest.visualize_flag -def test_5q_allocation(instruments_2lf_2mw): - qubits = [1, 2, 3, 4, 5] - qubit_pairs = [(1, 2), (2, 3), (3, 4), (4, 5)] +def test_6q_allocation(instruments_2lf_2mw): + qubits = [1, 2, 3, 4, 5, 6] + qubit_pairs = [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)] connectivity = Connectivity() - connectivity.add_resonator_line(qubits=qubits, constraints=mw_fem_spec(slot=7)) - connectivity.add_qubit_drive_lines(qubits=qubits, constraints=mw_fem_spec(slot=7)) + connectivity.add_resonator_line(qubits=qubits) + connectivity.add_qubit_drive_lines(qubits=qubits) connectivity.add_qubit_flux_lines(qubits=qubits) connectivity.add_qubit_pair_flux_lines(qubit_pairs=qubit_pairs, constraints=lf_fem_spec(out_slot=2)) allocate_wiring(connectivity, instruments_2lf_2mw) - print(connectivity.elements) - if visualize_flag: visualize(connectivity.elements, instruments_2lf_2mw.available_channels) + for qubit in qubits: + # flux channels should have some port as qubit index since they're allocated sequentially + flux_channels = connectivity.elements[QubitReference(qubit)].channels[WiringLineType.FLUX] + assert [asdict(ch) for ch in flux_channels] == [ + asdict(InstrumentChannelLfFemOutput(con=1, port=qubit, slot=1)) + ] + + # resonators all on same feedline, so should be first available input + outputs channels on MW-FEM + resonator_channels = connectivity.elements[QubitReference(qubit)].channels[WiringLineType.RESONATOR] + assert [asdict(ch) for ch in resonator_channels] == [ + asdict(InstrumentChannelMwFemInput(con=1, port=1, slot=3)), + asdict(InstrumentChannelMwFemOutput(con=1, port=1, slot=3)) + ] + + # drive channels are on MW-FEM + drive_channels = connectivity.elements[QubitReference(qubit)].channels[WiringLineType.DRIVE] + assert [asdict(ch) for ch in drive_channels] == [ + asdict(InstrumentChannelMwFemOutput(con=1, port=qubit+1, slot=3)) + ] + + for i, pair in enumerate(qubit_pairs): + # coupler channels should have some port as pair index since they're allocated sequentially, but on slot 2 + coupler_channels = connectivity.elements[QubitPairReference(*pair)].channels[WiringLineType.COUPLER] + assert [asdict(ch) for ch in coupler_channels] == [ + asdict(InstrumentChannelLfFemOutput(con=1, port=i+1, slot=2)) + ] def test_4rr_allocation(instruments_2lf_2mw): connectivity = Connectivity() @@ -35,19 +65,11 @@ def test_4rr_allocation(instruments_2lf_2mw): if visualize_flag: visualize(connectivity.elements, instruments_2lf_2mw.available_channels) + # resonators all on different feedlines, so should fill all 4 inputs of 2x MW-FEM + for i, qubit in enumerate([1, 2, 3, 4]): + resonator_channels = connectivity.elements[QubitReference(qubit)].channels[WiringLineType.RESONATOR] + assert [asdict(ch) for ch in resonator_channels] == [ + asdict(InstrumentChannelMwFemInput(con=1, port=[1, 2, 1, 2][i], slot=[3, 3, 7, 7][i])), + asdict(InstrumentChannelMwFemOutput(con=1, port=[1, 2, 1, 2][i], slot=[3, 3, 7, 7][i])) + ] -def test_6rr_6xy_6flux_allocation(): - instruments = Instruments() - instruments.add_lf_fem(controller=1, slots=1) - instruments.add_mw_fem(controller=1, slots=2) - - qubits = [1, 2, 3, 4, 5, 6] - connectivity = Connectivity() - connectivity.add_resonator_line(qubits=qubits) - connectivity.add_qubit_drive_lines(qubits=qubits) - connectivity.add_qubit_flux_lines(qubits=qubits) - - allocate_wiring(connectivity, instruments) - - if visualize_flag: - visualize(connectivity.elements, instruments.available_channels) \ No newline at end of file diff --git a/tests/wirer/test_wirer_lf_and_octave.py b/tests/wirer/test_wirer_lf_and_octave.py index c25d5fe3..85cd087d 100644 --- a/tests/wirer/test_wirer_lf_and_octave.py +++ b/tests/wirer/test_wirer_lf_and_octave.py @@ -1,22 +1,54 @@ +from dataclasses import asdict + import pytest from qualang_tools.wirer import * from pprint import pprint +from qualang_tools.wirer.connectivity.element import QubitReference +from qualang_tools.wirer.connectivity.wiring_spec import WiringLineType +from qualang_tools.wirer.instruments.instrument_channel import InstrumentChannelOpxPlusInput, \ + InstrumentChannelOpxPlusOutput, InstrumentChannelOpxPlusDigitalOutput, InstrumentChannelOctaveInput, \ + InstrumentChannelOctaveDigitalInput, InstrumentChannelOctaveOutput + visualize_flag = pytest.visualize_flag -def test_rf_io_allocation(instruments_1octave): - qubits = [1,2,3,4] +def test_rf_io_allocation(instruments_1OPX1Octave): + qubits = [1, 2, 3, 4] + connectivity = Connectivity() connectivity.add_resonator_line(qubits=qubits) connectivity.add_qubit_drive_lines(qubits=qubits) - allocate_wiring(connectivity, instruments_1octave) + allocate_wiring(connectivity, instruments_1OPX1Octave) - pprint(connectivity.elements) if visualize_flag: - visualize(connectivity.elements, available_channels=instruments_1octave.available_channels) + visualize(connectivity.elements, available_channels=instruments_1OPX1Octave.available_channels) + + for qubit in qubits: + # resonator lines should be the same because only 1 feedline + for i, channel in enumerate(connectivity.elements[QubitReference(index=qubit)].channels[WiringLineType.RESONATOR]): + assert asdict(channel) == asdict([ + InstrumentChannelOpxPlusInput(con=1, port=1, slot=None), + InstrumentChannelOpxPlusInput(con=1, port=2, slot=None), + InstrumentChannelOpxPlusOutput(con=1, port=1, slot=None), + InstrumentChannelOpxPlusOutput(con=1, port=2, slot=None), + # InstrumentChannelOpxPlusDigitalOutput(con=1, port=1, slot=None), + InstrumentChannelOctaveInput(con=1, port=1, slot=None), + InstrumentChannelOctaveOutput(con=1, port=1, slot=None), + # InstrumentChannelOctaveDigitalInput(con=1, port=1, slot=None) + ][i]) + + # drive lines should be allocated sequentially + for i, channel in enumerate(connectivity.elements[QubitReference(index=qubit)].channels[WiringLineType.DRIVE]): + assert asdict(channel) == asdict([ + InstrumentChannelOpxPlusOutput(con=1, port=1+2*qubit, slot=None), + InstrumentChannelOpxPlusOutput(con=1, port=2+2*qubit, slot=None), + InstrumentChannelOctaveOutput(con=1, port=1+qubit, slot=None), + ][i]) + + def test_qw_soprano_allocation(instruments_qw_soprano): qubits = [1, 2, 3, 4, 5] @@ -28,11 +60,11 @@ def test_qw_soprano_allocation(instruments_qw_soprano): allocate_wiring(connectivity, instruments_qw_soprano) - pprint(connectivity.elements) - if visualize_flag: visualize(connectivity.elements, available_channels=instruments_qw_soprano.available_channels) + # should run without error + def test_qw_soprano_2qb_allocation(instruments_1OPX1Octave): active_qubits = [1, 2] @@ -44,11 +76,11 @@ def test_qw_soprano_2qb_allocation(instruments_1OPX1Octave): allocate_wiring(connectivity, instruments_1OPX1Octave) - pprint(connectivity.elements) - if visualize_flag: visualize(connectivity.elements, available_channels=instruments_1OPX1Octave.available_channels) + # should run without error + def test_qw_soprano_2qb_among_5_allocation(instruments_1OPX1Octave): all_qubits = [1, 2, 3, 4] active_qubits = [1, 2] @@ -70,7 +102,7 @@ def test_qw_soprano_2qb_among_5_allocation(instruments_1OPX1Octave): allocate_wiring(connectivity, instruments_1OPX1Octave) - pprint(connectivity.elements) - if visualize_flag: visualize(connectivity.elements, instruments_1OPX1Octave.available_channels) + + # should run without error \ No newline at end of file diff --git a/tests/wirer/test_wirer_lf_charge.py b/tests/wirer/test_wirer_lf_charge.py index a2694bf1..c05e946c 100644 --- a/tests/wirer/test_wirer_lf_charge.py +++ b/tests/wirer/test_wirer_lf_charge.py @@ -1,22 +1,30 @@ +from dataclasses import asdict + import pytest from qualang_tools.wirer import * +from qualang_tools.wirer.connectivity.element import QubitReference +from qualang_tools.wirer.connectivity.wiring_spec import WiringLineType +from qualang_tools.wirer.instruments.instrument_channel import InstrumentChannelLfFemOutput visualize_flag = pytest.visualize_flag -def test_5q_allocation_flux_charge(instruments_2lf_2mw): +def test_1q_allocation_flux_charge(instruments_2lf_2mw): qubits = [1, 2, 3, 4, 5] - qubit_pairs = [(1, 2), (2, 3), (3, 4), (4, 5)] connectivity = Connectivity() - connectivity.add_resonator_line(qubits=qubits, constraints=mw_fem_spec(slot=7)) - connectivity.add_qubit_flux_lines(qubits=qubits) connectivity.add_qubit_charge_lines(qubits=qubits) - connectivity.add_qubit_pair_flux_lines(qubit_pairs=qubit_pairs, constraints=lf_fem_spec(out_slot=2)) allocate_wiring(connectivity, instruments_2lf_2mw) - print(connectivity.elements) - if visualize_flag: visualize(connectivity.elements, instruments_2lf_2mw.available_channels) + + for qubit_index in qubits: + charge_channels = connectivity.elements[QubitReference(qubit_index)].channels[WiringLineType.CHARGE] + assert len(charge_channels) == 1 + + for i, channel in enumerate(charge_channels): + assert asdict(channel) == asdict([ + InstrumentChannelLfFemOutput(con=1, port=qubit_index, slot=1) + ][i]) \ No newline at end of file