From 5ca0689c6fa4548d39a896e59605c48f696dedf3 Mon Sep 17 00:00:00 2001 From: Phillip Weinberg Date: Mon, 6 Oct 2025 09:18:04 -0400 Subject: [PATCH 1/8] adding new logical moves --- .../shuttle/stdlib/layouts/gemini/logical.py | 234 ++++++++++++++---- 1 file changed, 182 insertions(+), 52 deletions(-) diff --git a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py index 756fa8b3..6e69d7c4 100644 --- a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py +++ b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py @@ -1,4 +1,4 @@ -from typing import TypeVar +from typing import Any, TypeVar from bloqade.geometry.dialects import grid from kirin.dialects import ilist @@ -11,6 +11,12 @@ def get_spec(): + """Get the architecture specification for the Gemini logical qubit layout. + + Returns: + ArchSpec: The architecture specification with Gemini logical qubit layout. + + """ arch_spec = get_base_spec() gate_zone = arch_spec.layout.static_traps["gate_zone"] @@ -39,11 +45,14 @@ def get_spec(): ML1_block = M1_block[::2, :] MR1_block = M1_block[1::2, :] - GL0_block = left_traps[2 : 2 + 7 :, :] - GR0_block = right_traps[2 : 2 + 7 :, :] + GL_blocks = left_traps[2 : 2 + 2 * 7, :] + GR_blocks = right_traps[2 : 2 + 2 * 7, :] + + GL0_block = GL_blocks[:7, :] + GR0_block = GR_blocks[:7, :] - GL1_block = left_traps[2 + 7 : 2 + 2 * 7 :, :] - GR1_block = right_traps[2 + 7 : 2 + 2 * 7 :, :] + GL1_block = GL_blocks[7 : 2 * 7, :] + GR1_block = GR_blocks[7 : 2 * 7, :] AOM0_block = aom_sites[2 : 2 + 7, :] AOM1_block = aom_sites[2 + 7 : 2 + 7 + 7, :] @@ -53,6 +62,8 @@ def get_spec(): "right_gate_zone_sites": right_traps, "top_reservoir_sites": top_reservoir, "bottom_reservoir_sites": bottom_reservoir, + "GL_blocks": GL_blocks, + "GR_blocks": GR_blocks, "GL0_block": GL0_block, "GL1_block": GL1_block, "GR0_block": GR0_block, @@ -98,62 +109,181 @@ def get_spec(): @tweezer -def ltor_block_aom_move( - left_subblocks: ilist.IList[int, N], - right_subblocks: ilist.IList[int, N], +def get_block( + block_id: str, + col_indices: ilist.IList[int, Any], + row_indices: ilist.IList[int, Any], +): + """Returns the zone corresponding to the specified block and column. + + Args: + block_id (str): The block identifier, either "GL" or "GR". + col_id (int): The column identifier, either 0 or 1. + + Returns: + Grid: The grid corresponding to the specified block and column. + + """ + assert block_id in ("GL", "GR"), "block_id must be either 'GL' or 'GR'" + + block = None + if block_id == "GL": + block = spec.get_static_trap(zone_id="GL_blocks") + elif block_id == "GR": + block = spec.get_static_trap(zone_id="GR_blocks") + + code_size = spec.get_int_constant(constant_id="code_size") + + def _get_physical_columns(logical_col: int): + return ilist.range(logical_col * code_size, (logical_col + 1) * code_size) + + def join( + lhs: ilist.IList[int, Any], rhs: ilist.IList[int, Any] + ) -> ilist.IList[int, Any]: + return lhs + rhs + + physical_columns_lists = ilist.map(_get_physical_columns, col_indices) + physical_col_indices = ilist.foldl( + join, physical_columns_lists[1:], physical_columns_lists[0] + ) + + return block[physical_col_indices, row_indices] + + +@tweezer +def get_other_block(block_id: str) -> str: + assert block_id in ("GL", "GR"), "block_id must be either 'GL' or 'GR'" + other_block = "GL" + if block_id == "GL": + other_block = "GR" + return other_block + + +@tweezer +def swap_block_impl( + src_block: str, + selected_cols: ilist.IList[int, Any], + selected_rows: ilist.IList[int, Any], ): - assert_sorted(left_subblocks) - assert_sorted(right_subblocks) - - assert len(left_subblocks) == len( - right_subblocks - ), "Left and right subblocks must have the same length." - - left_blocks = spec.get_static_trap(zone_id="GL0_block") - right_blocks = spec.get_special_grid(grid_id="AOM1_block") - - left_block = left_blocks[:, left_subblocks] - right_block = right_blocks[:, right_subblocks] - row_separation = spec.get_float_constant(constant_id="row_separation") - col_separation = spec.get_float_constant(constant_id="col_separation") - gate_spacing = spec.get_float_constant(constant_id="gate_spacing") - - # AOM sites are already shifted by the gate spacing, so to shift to the center between the - # two blocks, we need to shift the AOM sites by half the col separation minus the gate - # spacing. - shift_from_aom = col_separation / 2.0 - gate_spacing - third_pos = grid.shift(right_block, -shift_from_aom, 0.0) - first_pos = grid.shift(left_block, 0.0, row_separation / 2.0) - second_pos = grid.from_positions(grid.get_xpos(third_pos), grid.get_ypos(first_pos)) - - action.set_loc(left_block) + + assert_sorted(selected_cols) + assert_sorted(selected_rows) + + dst_block = get_other_block(src_block) + + start = get_block(src_block, selected_cols, selected_rows) + end = get_block(dst_block, selected_cols, selected_rows) + + action.set_loc(start) action.turn_on(action.ALL, action.ALL) - action.move(first_pos) - action.move(second_pos) - action.move(third_pos) - action.move(right_block) + action.move(end) + action.turn_off(action.ALL, action.ALL) -@move -def get_device_fn( - left_subblocks: ilist.IList[int, N], - right_subblocks: ilist.IList[int, N], +@tweezer +def vertical_move_impl( + block_id: str, + col_indices: ilist.IList[int, Any], + src_rows: ilist.IList[int, N], + dst_rows: ilist.IList[int, N], +): + assert_sorted(col_indices) + assert_sorted(src_rows) + assert_sorted(dst_rows) + + assert block_id in ("GL", "GR"), "block_id must be either 'GL' or 'GR'" + src = get_block(block_id, col_indices, src_rows) + dst = get_block(block_id, col_indices, dst_rows) + x_shift = spec.get_float_constant(constant_id="col_separation") / 2.0 + if block_id == "GL": + x_shift = -x_shift + + if src != dst: + action.set_loc(src) + action.turn_on(action.ALL, action.ALL) + action.move(grid.shift(src, x_shift, 0.0)) + action.move(grid.shift(dst, x_shift, 0.0)) + action.move(dst) + action.turn_off(action.ALL, action.ALL) + + +@tweezer +def horizontal_move_impl( + block_id: str, + row_indices: ilist.IList[int, Any], + src_cols: ilist.IList[int, N], + dst_cols: ilist.IList[int, N], ): - x_tones = ilist.range(spec.get_int_constant(constant_id="code_size")) - y_tones = ilist.range(len(left_subblocks)) - return schedule.device_fn(ltor_block_aom_move, x_tones, y_tones) + assert_sorted(row_indices) + assert_sorted(src_cols) + assert_sorted(dst_cols) + + assert block_id in ("GL", "GR"), "block_id must be either 'GL' or 'GR'" + src = get_block(block_id, src_cols, row_indices) + dst = get_block(block_id, dst_cols, row_indices) + y_shift = spec.get_float_constant(constant_id="row_separation") / 2.0 + + if src != dst: + action.set_loc(src) + action.turn_on(action.ALL, action.ALL) + action.move(grid.shift(src, 0.0, y_shift)) + action.move(grid.shift(dst, 0.0, y_shift)) + action.move(dst) + action.turn_off(action.ALL, action.ALL) + + +Nx = TypeVar("Nx", bound=int) +Ny = TypeVar("Ny", bound=int) @move def entangle( - left_subblocks: ilist.IList[int, N], - right_subblocks: ilist.IList[int, N], + src_block: str, + src_cols: ilist.IList[int, Nx], + src_rows: ilist.IList[int, Ny], + dst_block: str, + dst_cols: ilist.IList[int, Nx], + dst_rows: ilist.IList[int, Ny], ): + assert_sorted(src_cols) + assert_sorted(src_rows) + assert_sorted(dst_cols) + assert_sorted(dst_rows) + + assert len(src_cols) == len( + dst_cols + ), "src_cols and dst_cols must have the same length" + assert len(src_rows) == len( + dst_rows + ), "src_rows and dst_rows must have the same length" + + assert src_block in ("GL", "GR"), "src_block must be either 'GL' or 'GR'" + assert dst_block in ("GL", "GR"), "dst_block must be either 'GL' or 'GR'" + + x_tones = ilist.range( + 0, len(src_cols) * spec.get_int_constant(constant_id="code_size") + ) + y_tones = ilist.range(0, len(src_rows)) + + shift = schedule.device_fn(swap_block_impl, x_tones, y_tones) + horizontal_move = schedule.device_fn(horizontal_move_impl, x_tones, y_tones) + vertical_move = schedule.device_fn(vertical_move_impl, x_tones, y_tones) + inv_horizontal_move = schedule.reverse(horizontal_move) + inv_vertical_move = schedule.reverse(vertical_move) + + if src_block == dst_block: + tmp_block = get_other_block(src_block) + shift(src_block, src_cols, src_rows) + else: + tmp_block = src_block + + horizontal_move(tmp_block, src_rows, src_cols, dst_cols) + vertical_move(tmp_block, dst_cols, src_rows, dst_rows) + + gate.top_hat_cz(spec.get_static_trap(zone_id="gate_zone")) - device_func = get_device_fn(left_subblocks, right_subblocks) - rev_func = schedule.reverse(device_func) + inv_vertical_move(tmp_block, dst_cols, src_rows, dst_rows) + inv_horizontal_move(tmp_block, src_rows, src_cols, dst_cols) - if len(left_subblocks) > 0: - device_func(left_subblocks, right_subblocks) - gate.top_hat_cz(spec.get_static_trap(zone_id="gate_zone")) - rev_func(left_subblocks, right_subblocks) + if src_block == dst_block: + shift(tmp_block, src_cols, src_rows) From 7733aadcbf76f5421af4e6f65740cbd32f30f442 Mon Sep 17 00:00:00 2001 From: Phillip Weinberg Date: Mon, 6 Oct 2025 09:47:46 -0400 Subject: [PATCH 2/8] adding new logical moves --- .../shuttle/stdlib/layouts/gemini/logical.py | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py index 6e69d7c4..66da2699 100644 --- a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py +++ b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py @@ -194,17 +194,17 @@ def vertical_move_impl( assert block_id in ("GL", "GR"), "block_id must be either 'GL' or 'GR'" src = get_block(block_id, col_indices, src_rows) dst = get_block(block_id, col_indices, dst_rows) + x_shift = spec.get_float_constant(constant_id="col_separation") / 2.0 if block_id == "GL": x_shift = -x_shift - if src != dst: - action.set_loc(src) - action.turn_on(action.ALL, action.ALL) - action.move(grid.shift(src, x_shift, 0.0)) - action.move(grid.shift(dst, x_shift, 0.0)) - action.move(dst) - action.turn_off(action.ALL, action.ALL) + action.set_loc(src) + action.turn_on(action.ALL, action.ALL) + action.move(grid.shift(src, x_shift, 0.0)) + action.move(grid.shift(dst, x_shift, 0.0)) + action.move(dst) + action.turn_off(action.ALL, action.ALL) @tweezer @@ -223,13 +223,12 @@ def horizontal_move_impl( dst = get_block(block_id, dst_cols, row_indices) y_shift = spec.get_float_constant(constant_id="row_separation") / 2.0 - if src != dst: - action.set_loc(src) - action.turn_on(action.ALL, action.ALL) - action.move(grid.shift(src, 0.0, y_shift)) - action.move(grid.shift(dst, 0.0, y_shift)) - action.move(dst) - action.turn_off(action.ALL, action.ALL) + action.set_loc(src) + action.turn_on(action.ALL, action.ALL) + action.move(grid.shift(src, 0.0, y_shift)) + action.move(grid.shift(dst, 0.0, y_shift)) + action.move(dst) + action.turn_off(action.ALL, action.ALL) Nx = TypeVar("Nx", bound=int) @@ -277,13 +276,19 @@ def entangle( else: tmp_block = src_block - horizontal_move(tmp_block, src_rows, src_cols, dst_cols) - vertical_move(tmp_block, dst_cols, src_rows, dst_rows) + if src_cols != dst_cols: + horizontal_move(tmp_block, src_rows, src_cols, dst_cols) + + if src_rows != dst_rows: + vertical_move(tmp_block, dst_cols, src_rows, dst_rows) gate.top_hat_cz(spec.get_static_trap(zone_id="gate_zone")) - inv_vertical_move(tmp_block, dst_cols, src_rows, dst_rows) - inv_horizontal_move(tmp_block, src_rows, src_cols, dst_cols) + if src_rows != dst_rows: + inv_vertical_move(tmp_block, dst_cols, src_rows, dst_rows) + + if src_cols != dst_cols: + inv_horizontal_move(tmp_block, src_rows, src_cols, dst_cols) if src_block == dst_block: shift(tmp_block, src_cols, src_rows) From 2eaa9f4062b23ee28e2e2e28c5733f8bca5847aa Mon Sep 17 00:00:00 2001 From: Phillip Weinberg Date: Tue, 7 Oct 2025 11:44:27 -0400 Subject: [PATCH 3/8] adding tests of individual logical moves --- .../shuttle/stdlib/layouts/gemini/logical.py | 10 +- test/stdlib/gemini/test_logical.py | 214 +++++++++++++----- 2 files changed, 169 insertions(+), 55 deletions(-) diff --git a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py index 66da2699..83d2f9e1 100644 --- a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py +++ b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py @@ -191,10 +191,14 @@ def vertical_move_impl( assert_sorted(src_rows) assert_sorted(dst_rows) + assert len(src_rows) == len( + dst_rows + ), "src_rows and dst_rows must have the same length" + assert block_id in ("GL", "GR"), "block_id must be either 'GL' or 'GR'" src = get_block(block_id, col_indices, src_rows) dst = get_block(block_id, col_indices, dst_rows) - + x_shift = spec.get_float_constant(constant_id="col_separation") / 2.0 if block_id == "GL": x_shift = -x_shift @@ -218,6 +222,10 @@ def horizontal_move_impl( assert_sorted(src_cols) assert_sorted(dst_cols) + assert len(src_cols) == len( + dst_cols + ), "src_cols and dst_cols must have the same length" + assert block_id in ("GL", "GR"), "block_id must be either 'GL' or 'GR'" src = get_block(block_id, src_cols, row_indices) dst = get_block(block_id, dst_cols, row_indices) diff --git a/test/stdlib/gemini/test_logical.py b/test/stdlib/gemini/test_logical.py index a626f3d7..99d1f164 100644 --- a/test/stdlib/gemini/test_logical.py +++ b/test/stdlib/gemini/test_logical.py @@ -6,12 +6,15 @@ from bloqade.geometry.dialects import grid from kirin.dialects import ilist -from bloqade.shuttle import arch, move -from bloqade.shuttle.arch import ArchSpecInterpreter +from bloqade.shuttle import arch from bloqade.shuttle.codegen import TraceInterpreter, taskgen from bloqade.shuttle.stdlib.layouts.gemini import logical +def is_sorted(lst): + return all(ele1 < ele2 for ele1, ele2 in zip(lst, lst[1:])) + + def get_logical_spec_tyler() -> arch.ArchSpec: ROW_SEPARATION = 10.0 COL_SEPARATION = 8.0 @@ -191,83 +194,186 @@ def test_against_tyler(): N = typing.TypeVar("N") +swap_block_test_cases = [ + (ilist.IList([0]), ilist.IList([0, 2, 4])), + (ilist.IList([1]), ilist.IList([1, 3])), + (ilist.IList([0, 1]), ilist.IList([0, 1, 2, 3, 4])), + (ilist.IList([0, 2]), ilist.IList([0, 2, 4])), + (ilist.IList([1, 0]), ilist.IList([0, 2, 4])), +] + -def run_trace( - left_subblocks: ilist.IList[int, N], - right_subblocks: ilist.IList[int, N], +@pytest.mark.parametrize("x_indices, y_indices", swap_block_test_cases) +def test_swap_block_impl( + x_indices: ilist.IList[int, typing.Any], y_indices: ilist.IList[int, typing.Any] ): + spec = logical.get_spec() + ti = TraceInterpreter(spec) - device_fn = ArchSpecInterpreter( - dialects=move, arch_spec=(arch_spec := logical.get_spec()) - ).run(logical.get_device_fn, (left_subblocks, right_subblocks)) - trace_results = TraceInterpreter(arch_spec=arch_spec).run_trace( - device_fn.move_fn, (left_subblocks, right_subblocks), kwargs={} - ) + y_indices = ilist.IList([0, 2, 4]) + x_indices = ilist.IList([0]) + + args = ("GL", ilist.IList([0]), ilist.IList([0, 2, 4])) - return trace_results, arch_spec + has_error = not is_sorted(x_indices) or not is_sorted(y_indices) + if has_error: + with pytest.raises(AssertionError): + ti.run_trace(logical.swap_block_impl, args=args, kwargs={}) + return -def is_sorted(lst: ilist.IList[int, N]) -> bool: - return all(x <= y for x, y in zip(lst, lst[1:])) + actions = ti.run_trace(logical.swap_block_impl, args=args, kwargs={}) + code_size = spec.int_constants["code_size"] + physical_indices = (range(i * code_size, (i + 1) * code_size) for i in x_indices) + x_physical_indices = ilist.IList(sum(map(tuple, physical_indices), ())) -test_indices = [ - ilist.IList([0]), - ilist.IList([1]), - ilist.IList([1, 3]), - ilist.IList([0, 2, 4]), - ilist.IList([0, 1, 2, 3, 4]), - ilist.IList([3, 2, 1]), + start_grid = spec.layout.static_traps["GL_blocks"][x_physical_indices, y_indices] + end_grid = spec.layout.static_traps["GR_blocks"][x_physical_indices, y_indices] + + expected_actions = [ + taskgen.WayPointsAction([start_grid]), + taskgen.TurnOnXYSliceAction(slice(None), slice(None)), + taskgen.WayPointsAction([start_grid, end_grid]), + taskgen.TurnOffXYSliceAction(slice(None), slice(None)), + taskgen.WayPointsAction([end_grid]), + ] + + for a, e in itertools.zip_longest(actions, expected_actions): + assert a == e, f"Action {a} does not match expected {e}" + + +vertical_move_test_cases = [ + ("GL", ilist.IList([0]), ilist.IList([0, 2]), ilist.IList([1, 4])), + ("GR", ilist.IList([1]), ilist.IList([1, 3]), ilist.IList([0, 2])), + ("GL", ilist.IList([0, 1]), ilist.IList([0, 1, 2]), ilist.IList([2, 3, 4])), + ("GR", ilist.IList([1, 0]), ilist.IList([0, 2]), ilist.IList([1, 4])), + ("GR", ilist.IList([1, 0]), ilist.IList([0, 2]), ilist.IList([1])), ] @pytest.mark.parametrize( - "left_subblocks,right_subblocks", itertools.product(test_indices, repeat=2) + "block_id, col_indices, src_rows, dst_rows", vertical_move_test_cases ) -def test_aom_move( - left_subblocks: ilist.IList[int, N], right_subblocks: ilist.IList[int, N] +def test_vertical_move_impl( + block_id: str, + col_indices: ilist.IList[int, typing.Any], + src_rows: ilist.IList[int, N], + dst_rows: ilist.IList[int, N], ): + spec = logical.get_spec() + ti = TraceInterpreter(spec) + + args = (block_id, col_indices, src_rows, dst_rows) + + has_error = ( + len(src_rows) != len(dst_rows) + or not is_sorted(src_rows) + or not is_sorted(dst_rows) + or not is_sorted(col_indices) + ) - if not (is_sorted(left_subblocks) and is_sorted(right_subblocks)) or len( - left_subblocks - ) != len(right_subblocks): + if has_error: with pytest.raises(AssertionError): - run_trace(left_subblocks, right_subblocks) + ti.run_trace(logical.vertical_move_impl, args=args, kwargs={}) return - else: - actions, arch_spec = run_trace(left_subblocks, right_subblocks) - GL0_block = arch_spec.layout.static_traps["GL0_block"] - AOM1_block = arch_spec.layout.special_grid["AOM1_block"] + trace_results = ti.run_trace(logical.vertical_move_impl, args=args, kwargs={}) + code_size = spec.int_constants["code_size"] - set_waypoint, turn_on, movement = actions + physical_indices = (range(i * code_size, (i + 1) * code_size) for i in col_indices) + x_physical_indices = ilist.IList(sum(map(tuple, physical_indices), ())) - start_pos = GL0_block[:, left_subblocks] - end_pos = AOM1_block[:, right_subblocks] + start_grid = spec.layout.static_traps[f"{block_id}_blocks"][ + x_physical_indices, src_rows + ] + end_grid = spec.layout.static_traps[f"{block_id}_blocks"][ + x_physical_indices, dst_rows + ] - x_shift = ( - arch_spec.float_constants["col_separation"] / 2.0 - - arch_spec.float_constants["gate_spacing"] - ) - y_shift = arch_spec.float_constants["row_separation"] / 2.0 + col_separation = spec.float_constants["col_separation"] + x_shift = col_separation / 2 if block_id == "GR" else -(col_separation / 2) - first_pos = start_pos.shift(0, y_shift) - third_pos = end_pos.shift(-x_shift, 0.0) - mid_pos = grid.Grid.from_positions(third_pos.x_positions, first_pos.y_positions) + mid_1 = start_grid.shift(x_shift, 0.0) + mid_2 = end_grid.shift(x_shift, 0.0) + + expected_actions = [ + taskgen.WayPointsAction([start_grid]), + taskgen.TurnOnXYSliceAction(slice(None), slice(None)), + taskgen.WayPointsAction([start_grid, mid_1, mid_2, end_grid]), + taskgen.TurnOffXYSliceAction(slice(None), slice(None)), + taskgen.WayPointsAction([end_grid]), + ] + + for a, e in itertools.zip_longest(trace_results, expected_actions): + assert a == e, f"Action {a} does not match expected {e}" - expected_movement = taskgen.WayPointsAction( - [start_pos, first_pos, mid_pos, third_pos, end_pos] - ) - assert set_waypoint == taskgen.WayPointsAction([start_pos]) - assert ( - isinstance(turn_on, taskgen.TurnOnXYSliceAction) - and turn_on.x_tone_indices == slice(None) - and turn_on.y_tone_indices == slice(None) +horizontal_move_test_cases = [ + ("GL", ilist.IList([0, 2, 3]), ilist.IList([0]), ilist.IList([1])), + ("GR", ilist.IList([1, 3, 4]), ilist.IList([1]), ilist.IList([0])), + ("GL", ilist.IList([0, 1, 2, 3, 4]), ilist.IList([0]), ilist.IList([1])), + ("GR", ilist.IList([1, 0]), ilist.IList([0]), ilist.IList([1])), + ("GR", ilist.IList([0, 1]), ilist.IList([0]), ilist.IList([0, 1])), +] + + +@pytest.mark.parametrize( + "block_id, row_indices, src_cols, dst_cols", horizontal_move_test_cases +) +def test_horizontal_move_impl( + block_id: str, + row_indices: ilist.IList[int, typing.Any], + src_cols: ilist.IList[int, N], + dst_cols: ilist.IList[int, N], +): + spec = logical.get_spec() + ti = TraceInterpreter(spec) + + args = (block_id, row_indices, src_cols, dst_cols) + + has_error = ( + len(src_cols) != len(dst_cols) + or not is_sorted(row_indices) + or not is_sorted(dst_cols) + or not is_sorted(src_cols) ) - assert movement == expected_movement + if has_error: + with pytest.raises(AssertionError): + ti.run_trace(logical.horizontal_move_impl, args=args, kwargs={}) + + return -# if __name__ == "__main__": -# test_aom_move() + trace_results = ti.run_trace(logical.horizontal_move_impl, args=args, kwargs={}) + code_size = spec.int_constants["code_size"] + + src_physical_indices = (range(i * code_size, (i + 1) * code_size) for i in src_cols) + dst_physical_indices = (range(i * code_size, (i + 1) * code_size) for i in dst_cols) + src_x_physical_indices = ilist.IList(sum(map(tuple, src_physical_indices), ())) + dst_x_physical_indices = ilist.IList(sum(map(tuple, dst_physical_indices), ())) + + start_grid = spec.layout.static_traps[f"{block_id}_blocks"][ + src_x_physical_indices, row_indices + ] + end_grid = spec.layout.static_traps[f"{block_id}_blocks"][ + dst_x_physical_indices, row_indices + ] + + row_separation = spec.float_constants["row_separation"] + y_shift = row_separation / 2 + + mid_1 = start_grid.shift(0.0, y_shift) + mid_2 = end_grid.shift(0.0, y_shift) + + expected_actions = [ + taskgen.WayPointsAction([start_grid]), + taskgen.TurnOnXYSliceAction(slice(None), slice(None)), + taskgen.WayPointsAction([start_grid, mid_1, mid_2, end_grid]), + taskgen.TurnOffXYSliceAction(slice(None), slice(None)), + taskgen.WayPointsAction([end_grid]), + ] + + for a, e in itertools.zip_longest(trace_results, expected_actions): + assert a == e, f"Action {a} does not match expected {e}" From 15f0c212ba1fe779eb1f32e17c96689808b1bdfc Mon Sep 17 00:00:00 2001 From: Phillip Weinberg Date: Tue, 7 Oct 2025 13:31:03 -0400 Subject: [PATCH 4/8] adding docs + fixing tests --- .../shuttle/stdlib/layouts/gemini/logical.py | 71 +++++++++++++++---- test/stdlib/gemini/test_logical.py | 14 ++-- 2 files changed, 67 insertions(+), 18 deletions(-) diff --git a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py index 83d2f9e1..5b62fa54 100644 --- a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py +++ b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py @@ -118,7 +118,8 @@ def get_block( Args: block_id (str): The block identifier, either "GL" or "GR". - col_id (int): The column identifier, either 0 or 1. + col_indices (IList[int, Any]): The list of logical column indices. + row_indices (IList[int, Any]): The list of logical row indices. Returns: Grid: The grid corresponding to the specified block and column. @@ -152,6 +153,15 @@ def join( @tweezer def get_other_block(block_id: str) -> str: + """Returns the identifier of the other block. + + Args: + block_id (str): The current block identifier, either "GL" or "GR". + + Returns: + str: The identifier of the other block. + + """ assert block_id in ("GL", "GR"), "block_id must be either 'GL' or 'GR'" other_block = "GL" if block_id == "GL": @@ -165,6 +175,13 @@ def swap_block_impl( selected_cols: ilist.IList[int, Any], selected_rows: ilist.IList[int, Any], ): + """Swaps the specified rows and columns between the source and destination blocks. + + Args: + src_block (str): the current block identifier, either "GL" or "GR". + selected_cols (ilist.IList[int, Any]): the list of selected column indices to swap. + selected_rows (ilist.IList[int, Any]): the list of selected row indices to swap. + """ assert_sorted(selected_cols) assert_sorted(selected_rows) @@ -187,6 +204,15 @@ def vertical_move_impl( src_rows: ilist.IList[int, N], dst_rows: ilist.IList[int, N], ): + """Moves the specified rows within the given block. + + Args: + block_id (str): The block identifier, either "GL" or "GR". + col_indices (ilist.IList[int, Any]): The list of logical column indices. + src_rows (ilist.IList[int, N]): The list of source row indices. + dst_rows (ilist.IList[int, N]): The list of destination row indices. + + """ assert_sorted(col_indices) assert_sorted(src_rows) assert_sorted(dst_rows) @@ -218,6 +244,14 @@ def horizontal_move_impl( src_cols: ilist.IList[int, N], dst_cols: ilist.IList[int, N], ): + """Moves the specified columns within the given block. + + Args: + block_id (str): The block identifier, either "GL" or "GR". + row_indices (ilist.IList[int, Any]): The list of row indices. + src_cols (ilist.IList[int, N]): The list of source column indices. + dst_cols (ilist.IList[int, N]): The list of destination column indices. + """ assert_sorted(row_indices) assert_sorted(src_cols) assert_sorted(dst_cols) @@ -244,14 +278,29 @@ def horizontal_move_impl( @move -def entangle( - src_block: str, +def gl_entangle( src_cols: ilist.IList[int, Nx], src_rows: ilist.IList[int, Ny], - dst_block: str, dst_cols: ilist.IList[int, Nx], dst_rows: ilist.IList[int, Ny], ): + """Entangles the qubits located in the "GL" blocks between src and dst positions. + + The function performs the following steps: + 1. Validates the input parameters to ensure they are sorted and of equal length. + 3. Moves the qubits horizontally if the source and destination columns differ. + 4. Moves the qubits vertically if the source and destination rows differ. + 5. Applies a CZ gate to the qubits in the gate zone. + 6. Reverses the vertical and horizontal moves to return the qubits to their original positions. + + Args: + src_cols (ilist.IList[int, Nx]): The list of source column indices. + src_rows (ilist.IList[int, Ny]): The list of source row indices. + dst_cols (ilist.IList[int, Nx]): The list of destination column indices. + dst_rows (ilist.IList[int, Ny]): The list of destination row indices. + + """ + assert_sorted(src_cols) assert_sorted(src_rows) assert_sorted(dst_cols) @@ -264,8 +313,8 @@ def entangle( dst_rows ), "src_rows and dst_rows must have the same length" - assert src_block in ("GL", "GR"), "src_block must be either 'GL' or 'GR'" - assert dst_block in ("GL", "GR"), "dst_block must be either 'GL' or 'GR'" + storage_block = "GL" + tmp_block = "GR" x_tones = ilist.range( 0, len(src_cols) * spec.get_int_constant(constant_id="code_size") @@ -278,11 +327,8 @@ def entangle( inv_horizontal_move = schedule.reverse(horizontal_move) inv_vertical_move = schedule.reverse(vertical_move) - if src_block == dst_block: - tmp_block = get_other_block(src_block) - shift(src_block, src_cols, src_rows) - else: - tmp_block = src_block + # Need to swap blocks assuming all atoms are placed in the storage block + shift(storage_block, src_cols, src_rows) if src_cols != dst_cols: horizontal_move(tmp_block, src_rows, src_cols, dst_cols) @@ -298,5 +344,4 @@ def entangle( if src_cols != dst_cols: inv_horizontal_move(tmp_block, src_rows, src_cols, dst_cols) - if src_block == dst_block: - shift(tmp_block, src_cols, src_rows) + shift(tmp_block, src_cols, src_rows) diff --git a/test/stdlib/gemini/test_logical.py b/test/stdlib/gemini/test_logical.py index 99d1f164..54e7af63 100644 --- a/test/stdlib/gemini/test_logical.py +++ b/test/stdlib/gemini/test_logical.py @@ -198,7 +198,7 @@ def test_against_tyler(): (ilist.IList([0]), ilist.IList([0, 2, 4])), (ilist.IList([1]), ilist.IList([1, 3])), (ilist.IList([0, 1]), ilist.IList([0, 1, 2, 3, 4])), - (ilist.IList([0, 2]), ilist.IList([0, 2, 4])), + (ilist.IList([0, 1]), ilist.IList([0, 2, 4])), (ilist.IList([1, 0]), ilist.IList([0, 2, 4])), ] @@ -210,10 +210,7 @@ def test_swap_block_impl( spec = logical.get_spec() ti = TraceInterpreter(spec) - y_indices = ilist.IList([0, 2, 4]) - x_indices = ilist.IList([0]) - - args = ("GL", ilist.IList([0]), ilist.IList([0, 2, 4])) + args = ("GL", x_indices, y_indices) has_error = not is_sorted(x_indices) or not is_sorted(y_indices) @@ -231,6 +228,13 @@ def test_swap_block_impl( start_grid = spec.layout.static_traps["GL_blocks"][x_physical_indices, y_indices] end_grid = spec.layout.static_traps["GR_blocks"][x_physical_indices, y_indices] + has_error = not is_sorted(x_indices) or not is_sorted(y_indices) + + if has_error: + with pytest.raises(AssertionError): + ti.run_trace(logical.swap_block_impl, args=args, kwargs={}) + return + expected_actions = [ taskgen.WayPointsAction([start_grid]), taskgen.TurnOnXYSliceAction(slice(None), slice(None)), From bd77911d6378aa76677e07713d6846509109d9d6 Mon Sep 17 00:00:00 2001 From: Phillip Weinberg Date: Tue, 7 Oct 2025 13:34:39 -0400 Subject: [PATCH 5/8] Renaming variable --- src/bloqade/shuttle/stdlib/layouts/gemini/logical.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py index 5b62fa54..f4719620 100644 --- a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py +++ b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py @@ -314,7 +314,7 @@ def gl_entangle( ), "src_rows and dst_rows must have the same length" storage_block = "GL" - tmp_block = "GR" + move_block = "GR" x_tones = ilist.range( 0, len(src_cols) * spec.get_int_constant(constant_id="code_size") @@ -331,17 +331,17 @@ def gl_entangle( shift(storage_block, src_cols, src_rows) if src_cols != dst_cols: - horizontal_move(tmp_block, src_rows, src_cols, dst_cols) + horizontal_move(move_block, src_rows, src_cols, dst_cols) if src_rows != dst_rows: - vertical_move(tmp_block, dst_cols, src_rows, dst_rows) + vertical_move(move_block, dst_cols, src_rows, dst_rows) gate.top_hat_cz(spec.get_static_trap(zone_id="gate_zone")) if src_rows != dst_rows: - inv_vertical_move(tmp_block, dst_cols, src_rows, dst_rows) + inv_vertical_move(move_block, dst_cols, src_rows, dst_rows) if src_cols != dst_cols: - inv_horizontal_move(tmp_block, src_rows, src_cols, dst_cols) + inv_horizontal_move(move_block, src_rows, src_cols, dst_cols) - shift(tmp_block, src_cols, src_rows) + shift(move_block, src_cols, src_rows) From 5bcdc830357645158929d1216b2975f09f36fd3f Mon Sep 17 00:00:00 2001 From: Phillip Weinberg Date: Wed, 8 Oct 2025 08:54:07 -0400 Subject: [PATCH 6/8] putting more move logic into tweezer kernel --- .../shuttle/stdlib/layouts/gemini/logical.py | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py index f4719620..d43cfa2c 100644 --- a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py +++ b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py @@ -277,6 +277,27 @@ def horizontal_move_impl( Ny = TypeVar("Ny", bound=int) +@tweezer +def entangle_move_impl( + storage_block: str, + src_cols: ilist.IList[int, Nx], + src_rows: ilist.IList[int, Ny], + dst_cols: ilist.IList[int, Nx], + dst_rows: ilist.IList[int, Ny], +): + assert storage_block in ("GL", "GR"), "storage_block must be either 'GL' or 'GR'" + move_block = get_other_block(storage_block) + + # Need to swap blocks assuming all atoms are placed in the storage block + swap_block_impl(storage_block, src_cols, src_rows) + + if src_cols != dst_cols: + horizontal_move_impl(move_block, src_rows, src_cols, dst_cols) + + if src_rows != dst_rows: + vertical_move_impl(move_block, dst_cols, src_rows, dst_rows) + + @move def gl_entangle( src_cols: ilist.IList[int, Nx], @@ -313,35 +334,14 @@ def gl_entangle( dst_rows ), "src_rows and dst_rows must have the same length" - storage_block = "GL" - move_block = "GR" - x_tones = ilist.range( 0, len(src_cols) * spec.get_int_constant(constant_id="code_size") ) y_tones = ilist.range(0, len(src_rows)) - shift = schedule.device_fn(swap_block_impl, x_tones, y_tones) - horizontal_move = schedule.device_fn(horizontal_move_impl, x_tones, y_tones) - vertical_move = schedule.device_fn(vertical_move_impl, x_tones, y_tones) - inv_horizontal_move = schedule.reverse(horizontal_move) - inv_vertical_move = schedule.reverse(vertical_move) - - # Need to swap blocks assuming all atoms are placed in the storage block - shift(storage_block, src_cols, src_rows) - - if src_cols != dst_cols: - horizontal_move(move_block, src_rows, src_cols, dst_cols) - - if src_rows != dst_rows: - vertical_move(move_block, dst_cols, src_rows, dst_rows) + device_fn = schedule.device_fn(entangle_move_impl, x_tones, y_tones) + inf_device_fn = schedule.reverse(device_fn) + device_fn("GL", src_cols, src_rows, dst_cols, dst_rows) gate.top_hat_cz(spec.get_static_trap(zone_id="gate_zone")) - - if src_rows != dst_rows: - inv_vertical_move(move_block, dst_cols, src_rows, dst_rows) - - if src_cols != dst_cols: - inv_horizontal_move(move_block, src_rows, src_cols, dst_cols) - - shift(move_block, src_cols, src_rows) + inf_device_fn("GL", dst_cols, dst_rows, src_cols, src_rows) From 2d198e77d6bfdcd2e69c1796c7433bfaebffa0b7 Mon Sep 17 00:00:00 2001 From: Phillip Weinberg Date: Wed, 8 Oct 2025 16:56:21 -0400 Subject: [PATCH 7/8] refactor tweezer implementations --- .../shuttle/stdlib/layouts/gemini/logical.py | 290 +++++++----------- 1 file changed, 103 insertions(+), 187 deletions(-) diff --git a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py index d43cfa2c..0cee865c 100644 --- a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py +++ b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py @@ -1,10 +1,9 @@ -from typing import Any, TypeVar +from typing import Any from bloqade.geometry.dialects import grid from kirin.dialects import ilist -from bloqade.shuttle import action, gate, schedule, spec, tweezer -from bloqade.shuttle.prelude import move +from bloqade.shuttle import action, spec, tweezer from ..asserts import assert_sorted from .base_spec import get_base_spec @@ -105,20 +104,17 @@ def get_spec(): return arch_spec -N = TypeVar("N") - - @tweezer def get_block( block_id: str, - col_indices: ilist.IList[int, Any], + col_index: int, row_indices: ilist.IList[int, Any], ): """Returns the zone corresponding to the specified block and column. Args: block_id (str): The block identifier, either "GL" or "GR". - col_indices (IList[int, Any]): The list of logical column indices. + col_index (int): The logical column index. row_indices (IList[int, Any]): The list of logical row indices. Returns: @@ -134,214 +130,134 @@ def get_block( block = spec.get_static_trap(zone_id="GR_blocks") code_size = spec.get_int_constant(constant_id="code_size") - - def _get_physical_columns(logical_col: int): - return ilist.range(logical_col * code_size, (logical_col + 1) * code_size) - - def join( - lhs: ilist.IList[int, Any], rhs: ilist.IList[int, Any] - ) -> ilist.IList[int, Any]: - return lhs + rhs - - physical_columns_lists = ilist.map(_get_physical_columns, col_indices) - physical_col_indices = ilist.foldl( - join, physical_columns_lists[1:], physical_columns_lists[0] - ) - - return block[physical_col_indices, row_indices] + return block[col_index * code_size : (col_index + 1) * code_size, row_indices] @tweezer -def get_other_block(block_id: str) -> str: - """Returns the identifier of the other block. - - Args: - block_id (str): The current block identifier, either "GL" or "GR". - - Returns: - str: The identifier of the other block. - - """ - assert block_id in ("GL", "GR"), "block_id must be either 'GL' or 'GR'" - other_block = "GL" - if block_id == "GL": - other_block = "GR" - return other_block - - -@tweezer -def swap_block_impl( - src_block: str, - selected_cols: ilist.IList[int, Any], - selected_rows: ilist.IList[int, Any], +def move_by_shift( + start_pos: grid.Grid[Any, Any], + shifts: ilist.IList[tuple[float, float], Any], + active_x: ilist.IList[int, Any] | slice, + active_y: ilist.IList[int, Any] | slice, ): - """Swaps the specified rows and columns between the source and destination blocks. + """Moves the specified atoms by applying a series of shifts. Args: - src_block (str): the current block identifier, either "GL" or "GR". - selected_cols (ilist.IList[int, Any]): the list of selected column indices to swap. - selected_rows (ilist.IList[int, Any]): the list of selected row indices to swap. + start_pos (grid.Grid[Any, Any]): The starting position of the atoms. + shifts (ilist.IList[tuple[float, float], Any]): The list of shifts to apply. + active_x (ilist.IList[int, Any] | slice): The list or slice of active x indices. + active_y (ilist.IList[int, Any] | slice): The list or slice of active y indices. """ + action.set_loc(start_pos) + action.turn_on(active_x, active_y) - assert_sorted(selected_cols) - assert_sorted(selected_rows) + current_pos = start_pos + for shift in shifts: + current_pos = grid.shift(current_pos, shift[0], shift[1]) + action.move(current_pos) - dst_block = get_other_block(src_block) - - start = get_block(src_block, selected_cols, selected_rows) - end = get_block(dst_block, selected_cols, selected_rows) - - action.set_loc(start) - action.turn_on(action.ALL, action.ALL) - action.move(end) - action.turn_off(action.ALL, action.ALL) + action.turn_off(active_x, active_y) @tweezer -def vertical_move_impl( - block_id: str, - col_indices: ilist.IList[int, Any], - src_rows: ilist.IList[int, N], - dst_rows: ilist.IList[int, N], +def vertial_shift_impl( + offset: int, + src_col: int, + src_rows: ilist.IList[int, Any], ): """Moves the specified rows within the given block. Args: block_id (str): The block identifier, either "GL" or "GR". - col_indices (ilist.IList[int, Any]): The list of logical column indices. - src_rows (ilist.IList[int, N]): The list of source row indices. - dst_rows (ilist.IList[int, N]): The list of destination row indices. - + offset (int): The offset to apply to the row indices, must be non-negative. + src_col (int): The source column index. + src_rows (ilist.IList[int, Any]): The list of source row indices. """ - assert_sorted(col_indices) + assert offset >= 0, "offset must be non-negative" + max_row = spec.get_int_constant(constant_id="logical_rows") - offset + + def check_row(row: int): + assert row + offset < spec.get_int_constant( + constant_id="logical_rows" + ), "row index + offset must be less than `logical_rows`" + + ilist.for_each(check_row, src_rows) + assert ( + len(src_rows) < max_row + ), "Number of source rows must be less than `logical_rows - offset`" assert_sorted(src_rows) - assert_sorted(dst_rows) - - assert len(src_rows) == len( - dst_rows - ), "src_rows and dst_rows must have the same length" - - assert block_id in ("GL", "GR"), "block_id must be either 'GL' or 'GR'" - src = get_block(block_id, col_indices, src_rows) - dst = get_block(block_id, col_indices, dst_rows) - - x_shift = spec.get_float_constant(constant_id="col_separation") / 2.0 - if block_id == "GL": - x_shift = -x_shift - action.set_loc(src) - action.turn_on(action.ALL, action.ALL) - action.move(grid.shift(src, x_shift, 0.0)) - action.move(grid.shift(dst, x_shift, 0.0)) - action.move(dst) - action.turn_off(action.ALL, action.ALL) + start_pos = get_block("GL", src_col, ilist.range(max_row)) + row_separation = spec.get_float_constant(constant_id="row_separation") + col_separation = spec.get_float_constant(constant_id="col_separation") + gate_spacing = spec.get_float_constant(constant_id="gate_spacing") + + if offset > 1: + shifts = ilist.IList( + [ + (0.0, row_separation * 0.5), + (gate_spacing + col_separation * 0.5, 0.0), + (0.0, row_separation * (offset - 0.5)), + (-col_separation * 0.5, 0.0), + ] + ) + elif offset == 1: + shifts = ilist.IList( + [ + (0.0, row_separation * 0.5), + (gate_spacing, 0.0), + (0.0, row_separation * 0.5), + ] + ) + else: + shifts = ilist.IList([(gate_spacing, 0.0)]) + + move_by_shift(start_pos, shifts, action.ALL, src_rows) + + # validate the movement + current_pos = start_pos + for shift in shifts: + current_pos = grid.shift(current_pos, shift[0], shift[1]) + + expected_last_pos = get_block("GR", src_col, ilist.range(offset, max_row + offset)) + assert ( + current_pos == expected_last_pos + ), "Final position does not match expected position" @tweezer -def horizontal_move_impl( - block_id: str, - row_indices: ilist.IList[int, Any], - src_cols: ilist.IList[int, N], - dst_cols: ilist.IList[int, N], +def gr_zero_to_one( + src_rows: ilist.IList[int, Any], ): """Moves the specified columns within the given block. Args: - block_id (str): The block identifier, either "GL" or "GR". - row_indices (ilist.IList[int, Any]): The list of row indices. - src_cols (ilist.IList[int, N]): The list of source column indices. - dst_cols (ilist.IList[int, N]): The list of destination column indices. + src_rows (ilist.IList[int, Any]): The rows to apply the transformation to. """ - assert_sorted(row_indices) - assert_sorted(src_cols) - assert_sorted(dst_cols) - - assert len(src_cols) == len( - dst_cols - ), "src_cols and dst_cols must have the same length" - - assert block_id in ("GL", "GR"), "block_id must be either 'GL' or 'GR'" - src = get_block(block_id, src_cols, row_indices) - dst = get_block(block_id, dst_cols, row_indices) - y_shift = spec.get_float_constant(constant_id="row_separation") / 2.0 - - action.set_loc(src) - action.turn_on(action.ALL, action.ALL) - action.move(grid.shift(src, 0.0, y_shift)) - action.move(grid.shift(dst, 0.0, y_shift)) - action.move(dst) - action.turn_off(action.ALL, action.ALL) - - -Nx = TypeVar("Nx", bound=int) -Ny = TypeVar("Ny", bound=int) - - -@tweezer -def entangle_move_impl( - storage_block: str, - src_cols: ilist.IList[int, Nx], - src_rows: ilist.IList[int, Ny], - dst_cols: ilist.IList[int, Nx], - dst_rows: ilist.IList[int, Ny], -): - assert storage_block in ("GL", "GR"), "storage_block must be either 'GL' or 'GR'" - move_block = get_other_block(storage_block) - - # Need to swap blocks assuming all atoms are placed in the storage block - swap_block_impl(storage_block, src_cols, src_rows) - - if src_cols != dst_cols: - horizontal_move_impl(move_block, src_rows, src_cols, dst_cols) - - if src_rows != dst_rows: - vertical_move_impl(move_block, dst_cols, src_rows, dst_rows) - - -@move -def gl_entangle( - src_cols: ilist.IList[int, Nx], - src_rows: ilist.IList[int, Ny], - dst_cols: ilist.IList[int, Nx], - dst_rows: ilist.IList[int, Ny], -): - """Entangles the qubits located in the "GL" blocks between src and dst positions. - - The function performs the following steps: - 1. Validates the input parameters to ensure they are sorted and of equal length. - 3. Moves the qubits horizontally if the source and destination columns differ. - 4. Moves the qubits vertically if the source and destination rows differ. - 5. Applies a CZ gate to the qubits in the gate zone. - 6. Reverses the vertical and horizontal moves to return the qubits to their original positions. - - Args: - src_cols (ilist.IList[int, Nx]): The list of source column indices. - src_rows (ilist.IList[int, Ny]): The list of source row indices. - dst_cols (ilist.IList[int, Nx]): The list of destination column indices. - dst_rows (ilist.IList[int, Ny]): The list of destination row indices. + logical_rows = spec.get_int_constant(constant_id="logical_rows") + row_separation = spec.get_float_constant(constant_id="row_separation") + col_separation = spec.get_float_constant(constant_id="col_separation") + shift = col_separation * spec.get_float_constant(constant_id="code_size") + + shifts = ilist.IList( + [ + (0.0, row_separation * 0.5), + (shift, 0.0), + (0.0, -row_separation * 0.5), + ] + ) - """ + all_rows = ilist.range(logical_rows) + start_pos = get_block("GR", 0, all_rows) - assert_sorted(src_cols) - assert_sorted(src_rows) - assert_sorted(dst_cols) - assert_sorted(dst_rows) - - assert len(src_cols) == len( - dst_cols - ), "src_cols and dst_cols must have the same length" - assert len(src_rows) == len( - dst_rows - ), "src_rows and dst_rows must have the same length" - - x_tones = ilist.range( - 0, len(src_cols) * spec.get_int_constant(constant_id="code_size") - ) - y_tones = ilist.range(0, len(src_rows)) + move_by_shift(start_pos, shifts, action.ALL, src_rows) - device_fn = schedule.device_fn(entangle_move_impl, x_tones, y_tones) - inf_device_fn = schedule.reverse(device_fn) + # validate the movement + current_pos = start_pos + for shift in shifts: + current_pos = grid.shift(current_pos, shift[0], shift[1]) - device_fn("GL", src_cols, src_rows, dst_cols, dst_rows) - gate.top_hat_cz(spec.get_static_trap(zone_id="gate_zone")) - inf_device_fn("GL", dst_cols, dst_rows, src_cols, src_rows) + expected_last_pos = get_block("GR", 1, all_rows) + assert ( + current_pos == expected_last_pos + ), "Final position does not match expected position" From 23750cbdd7e0ea7dc41264d262bf56d095ffb096 Mon Sep 17 00:00:00 2001 From: Phillip Weinberg Date: Fri, 10 Oct 2025 13:25:44 -0400 Subject: [PATCH 8/8] Fixing name --- src/bloqade/shuttle/stdlib/layouts/gemini/logical.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py index 0cee865c..c218922f 100644 --- a/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py +++ b/src/bloqade/shuttle/stdlib/layouts/gemini/logical.py @@ -160,7 +160,7 @@ def move_by_shift( @tweezer -def vertial_shift_impl( +def vertical_shift_impl( offset: int, src_col: int, src_rows: ilist.IList[int, Any],