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

Merge QubitTable changes into main branch of default simulator #20

Open
rmshaffer opened this issue May 22, 2024 · 0 comments
Open

Merge QubitTable changes into main branch of default simulator #20

rmshaffer opened this issue May 22, 2024 · 0 comments
Labels
enhancement New feature or request

Comments

@rmshaffer
Copy link
Contributor

Describe the feature you'd like
The QubitTable class in autoqasm.simulator.program_context is almost an exact duplicate of the one in the default simulator repo.

The AutoQASM version of this class is here:

class QubitTable(Table):
def __init__(self):
super().__init__("Qubits")
def _validate_qubit_in_range(self, qubit: int, register_name: str) -> None:
if qubit >= len(self[register_name]):
raise IndexError(
f"qubit register index `{qubit}` out of range for qubit register "
f"of length {len(self[register_name])} `{register_name}`."
)
@singledispatchmethod
def get_by_identifier(self, identifier: Union[Identifier, IndexedIdentifier]) -> tuple[int]:
"""Convenience method to get an element with a possibly indexed identifier.
Args:
identifier (Union[Identifier, IndexedIdentifier]): The identifier to retrieve.
Returns:
tuple[int]: The qubit indices associated with the given identifier.
"""
if identifier.name.startswith("$"):
return (int(identifier.name[1:]),)
return self[identifier.name]
@get_by_identifier.register
def _(self, identifier: IndexedIdentifier) -> tuple[int]: # noqa: C901
"""When identifier is an IndexedIdentifier, function returns a tuple
corresponding to the elements referenced by the indexed identifier.
Args:
identifier (IndexedIdentifier): The indexed identifier to retrieve.
Raises:
IndexError: Qubit register index out of range for specified register.
Returns:
tuple[int]: The qubit indices associated with the given identifier.
"""
name = identifier.name.name
indices = self.get_qubit_indices(identifier)
primary_index = indices[0]
if isinstance(primary_index, (IntegerLiteral, SymbolLiteral)):
if isinstance(primary_index, IntegerLiteral):
self._validate_qubit_in_range(primary_index.value, name)
target = (self[name][0] + primary_index.value,)
elif isinstance(primary_index, RangeDefinition):
target = tuple(np.array(self[name])[convert_range_def_to_slice(primary_index)])
# Discrete set
else:
index_list = convert_discrete_set_to_list(primary_index)
for index in index_list:
if isinstance(index, int):
self._validate_qubit_in_range(index, name)
target = tuple([self[name][0] + index for index in index_list])
if len(indices) == 2:
# used for gate calls on registers, index will be IntegerLiteral
secondary_index = indices[1].value
target = (target[secondary_index],)
# validate indices manually, since we use addition instead of indexing to
# accommodate symbolic indices
for q in target:
if isinstance(q, (int, Integer)) and (relative_index := q - self[name][0]) >= len(
self[name]
):
raise IndexError(
f"qubit register index `{relative_index}` out of range for qubit register "
f"of length {len(self[name])} `{name}`."
)
return target
@staticmethod
def get_qubit_indices(
identifier: IndexedIdentifier,
) -> list[IntegerLiteral | RangeDefinition | DiscreteSet]:
"""Gets the qubit indices from a given indexed identifier.
Args:
identifier (IndexedIdentifier): The identifier representing the
qubit indices.
Raises:
IndexError: Index consists of multiple dimensions.
Returns:
list[IntegerLiteral | RangeDefinition | DiscreteSet]: The qubit indices
corresponding to the given indexed identifier.
"""
primary_index = identifier.indices[0]
if isinstance(primary_index, list):
if len(primary_index) != 1:
raise IndexError("Cannot index multiple dimensions for qubits.")
primary_index = primary_index[0]
if len(identifier.indices) == 1:
return [primary_index]
elif len(identifier.indices) == 2:
# used for gate calls on registers, index will be IntegerLiteral
secondary_index = identifier.indices[1][0]
return [primary_index, secondary_index]
else:
raise IndexError("Cannot index multiple dimensions for qubits.")
def _get_indices_length(
self,
indices: Sequence[IntegerLiteral | SymbolLiteral | RangeDefinition | DiscreteSet],
) -> int:
last_index = indices[-1]
if isinstance(last_index, (IntegerLiteral, SymbolLiteral)):
return 1
elif isinstance(last_index, RangeDefinition):
buffer = np.sign(last_index.step.value) if last_index.step is not None else 1
start = last_index.start.value if last_index.start is not None else 0
stop = last_index.end.value + buffer
step = last_index.step.value if last_index.step is not None else 1
return (stop - start) // step
elif isinstance(last_index, DiscreteSet):
return len(last_index.values)
else:
raise TypeError(f"tuple indices must be integers or slices, not {type(last_index)}")
def get_qubit_size(self, identifier: Union[Identifier, IndexedIdentifier]) -> int:
"""Gets the number of qubit indices for the given identifier.
Args:
identifier (Union[Identifier, IndexedIdentifier]): The identifier representing
the qubit indices.
Returns:
int: The number of qubit indices contained in the given identifier.
"""
if isinstance(identifier, IndexedIdentifier):
indices = self.get_qubit_indices(identifier)
return self._get_indices_length(indices)
return len(self.get_by_identifier(identifier))

The default simulator implementation is here:
https://github.com/amazon-braket/amazon-braket-default-simulator-python/blob/a4d7f98cb123ae6a1092972e728d2dbb93cb27b5/src/braket/default_simulator/openqasm/program_context.py#L96-L150

We should merge the changes into the default simulator repo and delete the QubitTable class from this repo.

How would this feature be used? Please describe.
This will reduce code duplication and improve maintainability.

Describe alternatives you've considered
n/a

Additional context
n/a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Development

No branches or pull requests

1 participant