-
Notifications
You must be signed in to change notification settings - Fork 11
Description
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:
autoqasm/src/autoqasm/simulator/program_context.py
Lines 42 to 181 in 8128271
| 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
Metadata
Metadata
Assignees
Labels
Type
Projects
Status