Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small improvements for sequence building #364

Merged
merged 7 commits into from
Apr 13, 2022
Merged
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
33 changes: 33 additions & 0 deletions pulser-core/pulser/register/base_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,39 @@ def qubit_ids(self) -> tuple[QubitId, ...]:
"""The qubit IDs of this register."""
return self._ids

def find_indices(self, id_list: abcSequence[QubitId]) -> list[int]:
"""Computes indices of qubits.

This can especially be useful when building a Pulser Sequence
with a parameter denoting qubits.

Example:
Let ``reg`` be a register with qubit Ids "a", "b" and "c":

>>> reg.find_indices(["a", "b", "c", "a"])

It returns ``[0, 1, 2, 0]``, following the qubit order of the
register.

Then, it is possible to use these indices when building a
sequence, typically to instantiate a ``VariableArray``,
that can be provided as an argument to ``target_index``
and ``phase_shift_index``.

Args:
id_list (typing::Sequence[QubitId]): IDs of the qubits to denote

Returns:
list[int]: Indices of the qubits to denote, only valid for the
given mapping.
Comment on lines +92 to +115
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very detailed, nice!

"""
if not set(id_list) <= set(self.qubit_ids):
raise ValueError(
"The IDs list must be selected among"
"the IDs of the register's qubits."
)
return [self.qubit_ids.index(id_) for id_ in id_list]

@classmethod
def from_coordinates(
cls: Type[T],
Expand Down
30 changes: 19 additions & 11 deletions pulser-core/pulser/register/mappable_reg.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@

from collections.abc import Mapping
from typing import TYPE_CHECKING, Any
from typing import Sequence as abcSequence

from pulser.json.utils import obj_to_dict

if TYPE_CHECKING: # pragma: no cover
from pulser.register.base_register import BaseRegister, QubitId
from pulser.register.register_layout import RegisterLayout
from typing import Sequence as abcSequence


class MappableRegister:
Expand Down Expand Up @@ -85,16 +85,24 @@ def find_indices(
with a parameter denoting qubits.

Example:
``
mapp_reg = TriangularLatticeLayout(50, 5).make_mappable_register(5)
seq = Sequence(mapp_reg, Chadoq2)
qubit_map = {"q0": 1, "q2": 4, "q4": 2, "q1": 3}
indices = mapp_reg.find_indices(
qubit_map.keys(),
["q4", "q2", "q1", "q2"])
print(indices) # [3, 2, 1, 2]
seq.build(qubits=qubit_map, qubit_indices=indices)
``
Let ``reg`` be a mappable register with qubit Ids "a", "b", "c"
and "d".

>>> qubit_map = dict(b=1, a=2, d=0)
>>> reg.find_indices(
>>> qubit_map.keys(),
>>> ["a", "b", "d", "a"])

It returns ``[0, 1, 2, 0]``, following the qubits order of the
mappable register, but keeping only the chosen ones.

Then, it is possible to use these indices when building a
sequence, typically to instanciate a ``VariableArray``,
that can be provided as an argument to ``target_index``
and ``phase_shift_index``.

``qubit_map`` should be provided when building the sequence,
to tell how to instantiate the register from the mappable register.

Args:
chosen_ids (set[QubitId]): IDs of the qubits that are chosen to
Expand Down
18 changes: 9 additions & 9 deletions pulser-core/pulser/sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -1075,15 +1075,6 @@ def build(
"a concrete register."
)

if not self.is_parametrized():
if not self.is_register_mappable():
warnings.warn(
"Building a non-parametrized sequence simply returns"
" a copy of itself.",
stacklevel=2,
)
return seq

all_keys, given_keys = self._variables.keys(), vars.keys()
if given_keys != all_keys:
invalid_vars = given_keys - all_keys
Expand All @@ -1101,6 +1092,15 @@ def build(
+ ", ".join(missing_vars)
)

if not self.is_parametrized():
if not self.is_register_mappable():
warnings.warn(
"Building a non-parametrized sequence simply returns"
" a copy of itself.",
stacklevel=2,
)
return seq

for name, value in vars.items():
self._variables[name]._assign(value)

Expand Down
12 changes: 12 additions & 0 deletions tests/test_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,18 @@ def test_to_2D():
reg.to_2D()


def test_find_indices():
reg = Register(dict(a=(0, 0), c=(5, 0), b=(0, 5)))
assert reg.find_indices(["c", "b", "a"]) == [1, 2, 0]

with pytest.raises(
ValueError,
match="IDs list must be selected among"
"the IDs of the register's qubits",
):
reg.find_indices(["c", "e", "d"])


def assert_eq(left, right):
assert left == right
assert right == left
Expand Down
7 changes: 6 additions & 1 deletion tests/test_register_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,12 @@ def test_mappable_register_creation():
):
mapp_reg.build_register({"q0": 0, "q5": 2})

reg = mapp_reg.build_register({"q0": 10, "q1": 49})
qubit_map = {"q0": 10, "q1": 49}
reg = mapp_reg.build_register(qubit_map)
assert reg == Register(
{"q0": tri.traps_dict[10], "q1": tri.traps_dict[49]}
)
names = ["q1", "q0", "q0"]
assert mapp_reg.find_indices(qubit_map.keys(), names) == reg.find_indices(
names
)
3 changes: 3 additions & 0 deletions tests/test_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,9 @@ def test_mappable_register():
):
seq.build(qubits={"q0": 1, "q1": 10})

with pytest.warns(UserWarning, match="No declared variables named: a"):
seq.build(qubits={"q2": 20, "q0": 10}, a=5)

seq_ = seq.build(qubits={"q2": 20, "q0": 10})
assert seq_._last("ryd").targets == {"q2", "q0"}
assert not seq_.is_register_mappable()
Expand Down