def dot_product(self, alpha: Sequence[float] | np.ndarray) -> np.ndarray: """ Computes the standard dot product of `alpha` with the paulis. Args: alpha (Sequence[float] | np.ndarray): The pauli coefficients. Returns: (np.ndarray): Sum of element-wise multiplication of `alpha` and `self.paulis`. Raises: ValueError: If `alpha` and `self.paulis` are incompatible. """ if not is_sequence(alpha) or not all(is_numeric(a) for a in alpha): raise TypeError( 'Expected a sequence of numbers, got %s.' % type(alpha), ) if len(alpha) != len(self): raise ValueError( 'Incorrect number of alpha values, expected %d, got %d.' % (len(self), len(alpha)), ) return np.array(np.sum([a * s for a, s in zip(alpha, self.paulis)], 0))
def __init__( self, loop_body: BasePass | Sequence[BasePass], replace_filter: Callable[[Circuit, Operation], bool] | None = None, ) -> None: """ Construct a ForEachBlockPass. Args: loop_body (BasePass | Sequence[BasePass]): The pass or passes to execute on every block. replace_filter (Callable[[Circuit, Operation], bool] | None): A predicate that determines if the resulting circuit, after calling `loop_body` on a block, should replace the original operation. Called with the circuit output from `loop_body` and the original operation. If this returns true, the operation will be replaced with the new circuit. Defaults to always replace. Raises: ValueError: If a Sequence[BasePass] is given, but it is empty. """ if not is_sequence(loop_body) and not isinstance(loop_body, BasePass): raise TypeError( 'Expected Pass or sequence of Passes, got %s.' % type(loop_body), ) if is_sequence(loop_body): truth_list = [isinstance(elem, BasePass) for elem in loop_body] if not all(truth_list): raise TypeError( 'Expected Pass or sequence of Passes, got %s.' % type(loop_body[truth_list.index(False)]), ) if len(loop_body) == 0: raise ValueError('Expected at least one pass.') self.loop_body = loop_body if is_sequence(loop_body) else [loop_body] self.replace_filter = replace_filter or default_replace_filter if not callable(self.replace_filter): raise TypeError( 'Expected callable method that maps Circuit and Operations to' ' booleans for replace_filter' ', got %s.' % type(self.replace_filter), )
def run(self, circuit: Circuit, data: dict[str, Any]) -> None: """Perform the pass's operation, see BasePass for more info.""" if self.condition(circuit, data): _logger.debug('True branch taken.') if is_sequence(self.on_true): for true_pass in self.on_true: true_pass.run(circuit, data) else: self.on_true.run(circuit, data) elif self.on_false is not None: _logger.debug('False branch taken.') if is_sequence(self.on_false): for false_pass in self.on_false: false_pass.run(circuit, data) else: self.on_false.run(circuit, data)
def run(self, circuit: Circuit, data: dict[str, Any]) -> None: """Perform the pass's operation, see BasePass for more info.""" while self.condition(circuit, data): _logger.debug('Loop body executing...') if is_sequence(self.loop_body): for loop_pass in self.loop_body: loop_pass.run(circuit, data) else: self.loop_body.run(circuit, data)
def __call__(self, params: Sequence[float] | np.ndarray) -> float: """Return the cost value given the input parameters.""" if not is_sequence(params): raise TypeError( 'Expected sequence for params, got %s.' % type(params), ) if not all(is_real_number(param) for param in params): raise TypeError('Expected sequence of floats for params.', ) return self.get_cost(params)
def __init__( self, condition: PassPredicate, loop_body: BasePass | Sequence[BasePass], ) -> None: """ Construct a DoWhileLoopPass. Args: condition (PassPredicate): The condition checked. loop_body (BasePass | Sequence[BasePass]): The pass or passes to execute while `condition` is true. Raises: ValueError: If a Sequence[BasePass] is given, but it is empty. """ if not isinstance(condition, PassPredicate): raise TypeError('Expected PassPredicate, got %s.' % type(condition)) if not is_sequence(loop_body) and not isinstance(loop_body, BasePass): raise TypeError( 'Expected Pass or sequence of Passes, got %s.' % type(loop_body), ) if is_sequence(loop_body): truth_list = [isinstance(elem, BasePass) for elem in loop_body] if not all(truth_list): raise TypeError( 'Expected Pass or sequence of Passes, got %s.' % type(loop_body[truth_list.index(False)]), ) if len(loop_body) == 0: raise ValueError('Expected at least one pass.') self.condition = condition self.loop_body = loop_body if is_sequence(loop_body) else [loop_body]
def __getitem__( self, index: int | slice | Sequence[int], ) -> int | tuple[int, ...]: """Retrieve one or multiple qudit indices from the location.""" if is_integer(index): return self._location[index] # type: ignore # TODO: TypeGuards if isinstance(index, slice): return self._location[index] if not is_sequence(index): raise TypeError(f'Invalid index type, got {type(index)}.') # TODO: TypeGuards return tuple(self._location[idx] for idx in index) # type: ignore
def __call__( # type: ignore self, params: Sequence[float] | np.ndarray, ) -> np.ndarray: """Return the vector of residuals given the input parameters.""" if not is_sequence(params): raise TypeError( 'Expected sequence for params, got %s.' % type(params), ) if not all(is_real_number(param) for param in params): raise TypeError( 'Expected sequence of floats for params.', ) return self.get_residuals(params)
def check_parameters(self, params: Sequence[float] | np.ndarray) -> None: """Checks to ensure parameters are valid and match the unitary.""" if not is_sequence(params): raise TypeError( 'Expected a sequence type for params, got %s.' % type(params), ) if not all(is_numeric(p) for p in params): typechecks = [is_numeric(p) for p in params] fail_idx = typechecks.index(False) raise TypeError( 'Expected params to be floats, got %s.' % type(params[fail_idx]), ) if len(params) != self.get_num_params(): raise ValueError( 'Expected %d params, got %d.' % (self.get_num_params(), len(params)), )
def invalid_utry_gen(dims: int | Sequence[int]) -> np.ndarray: """ Generate a random invalid unitary. dims (int | Sequence[int]): The dimension of the matrix. If multiple are given then the dimension is randomly chosen from the ones given. Returns: (np.ndarray): The randomly generated invalid unitary matrix. """ if isinstance(dims, int): return unitary_group.rvs(dims) + np.identity(dims) elif is_sequence(dims): if not all(isinstance(dim, int) for dim in dims): raise TypeError('Expected integer dimension.') dim = np.random.choice(dims, 1)[0] return unitary_group.rvs(dim) + np.identity(dim) else: raise TypeError( 'Expected integer or sequence of integers' ' for dimension, got: %s' % type(dims), )
def test_a_seq_complex(self, a_seq_complex: Any) -> None: assert is_sequence(a_seq_complex) assert len(a_seq_complex) >= 0 assert all(is_complex(c) for c in a_seq_complex)
def __init__( self, condition: PassPredicate, on_true: BasePass | Sequence[BasePass], on_false: BasePass | Sequence[BasePass] | None = None, ) -> None: """ Construct a IfThenElsePass. Args: condition (PassPredicate): The condition checked. on_true (BasePass | Sequence[BasePass]): The pass or passes to execute if `condition` is true. on_false (BasePass | Sequence[BasePass] | None): If specified, the pass or passes to execute if `condition` is false. Raises: ValueError: If a Sequence[BasePass] is given, but it is empty. """ if not isinstance(condition, PassPredicate): raise TypeError('Expected PassPredicate, got %s.' % type(condition)) if not is_sequence(on_true) and not isinstance(on_true, BasePass): raise TypeError( 'Expected Pass or sequence of Passes, got %s.' % type(on_true), ) if is_sequence(on_true): truth_list = [isinstance(elem, BasePass) for elem in on_true] if not all(truth_list): raise TypeError( 'Expected Pass or sequence of Passes, got %s.' % type(on_true[truth_list.index(False)]), ) if len(on_true) == 0: raise ValueError('Expected at least one pass for true branch.') if on_false is not None: if not is_sequence(on_false) and not isinstance(on_false, BasePass): raise TypeError( 'Expected Pass or sequence of Passes, got %s.' % type(on_false), ) if is_sequence(on_false): truth_list = [isinstance(elem, BasePass) for elem in on_false] if not all(truth_list): raise TypeError( 'Expected Pass or sequence of Passes, got %s.' % type(on_false[truth_list.index(False)]), ) if len(on_false) == 0: raise ValueError( 'Expected at least one pass for false branch.', ) self.condition = condition self.on_true = on_true if is_sequence(on_true) else [on_true] self.on_false = on_false if is_sequence(on_false) else [on_false]
def __init__( self, circuit: Circuit, start: CircuitPointLike = CircuitPoint(0, 0), end: CircuitPointLike | None = None, qudits_or_region: CircuitRegionLike | Sequence[int] | None = None, exclude: bool = False, reverse: bool = False, and_cycles: bool = False, ) -> None: """ Construct a CircuitIterator. Args: circuit (Circuit): The circuit to iterate through. start (CircuitPointLike): Only iterate through points greater than or equal to `start`. Defaults to start at the beginning of the circuit. (Default: (0, 0)) end (CircuitPointLike | None): Only iterate through points less than or equal to this. If left as None, iterates until the end of the circuit. (Default: None) qudits_or_region (CircuitRegionLike | Sequence[int] | None): Determines the way the circuit is iterated. If a region is given, then iterate through operations in the region. If a sequence of qudit indices is given, then only iterate the operations touching those qudits. If left as None, then iterate through the entire circuit in simulation order. (Default: None) exclude (bool): If iterating through a region or only some qudits and `exclude` is true, then do not yield operations that are only partially in the region or on the desired qudits. This may result in a sequence of operations that does not occur in simulation order in the circuit. (Default: False) reverse (bool): Reverse the ordering. If true, then end acts as start and vice versa. (Default: False) and_cycles (bool): If true, in addition to the operation, return the cycle index where it was found. (Default: False) """ if not CircuitPoint.is_point(start): raise TypeError(f'Expected point for start, got {type(start)}.') if end is not None and not CircuitPoint.is_point(end): raise TypeError(f'Expected point for end, got {type(end)}.') if end is None: end = CircuitPoint( circuit.get_num_cycles() - 1, circuit.get_size() - 1, ) self.circuit = circuit self.start = CircuitPoint(*start) self.end = CircuitPoint(*end) self.exclude = exclude self.reverse = reverse self.and_cycles = and_cycles # Set mode of iteration: if qudits_or_region is None: # iterate through the entire circuit normally self.qudits = list(range(self.circuit.get_size())) self.region = CircuitRegion({ qudit: (0, self.circuit.get_num_cycles()) for qudit in self.qudits }) elif CircuitRegion.is_region(qudits_or_region): # TODO: Typeguard # iterate through the region in the circuit self.qudits = list(qudits_or_region.keys()) # type: ignore self.region = CircuitRegion(qudits_or_region) # type: ignore elif is_sequence(qudits_or_region): # iterate through the circuit but only on the specified qudits if not all(is_integer(qudit) for qudit in qudits_or_region): raise TypeError('Expected region or sequence of indices.') if not all(0 <= qudit < self.circuit.get_size() for qudit in qudits_or_region): raise ValueError('Invalid sequence of qudit indices.') self.qudits = list(qudits_or_region) self.region = CircuitRegion({ qudit: (0, self.circuit.get_num_cycles()) for qudit in self.qudits }) self.max_qudit = max(self.qudits) self.min_qudit = min(self.qudits) self.min_cycle = self.region.min_cycle self.max_cycle = self.region.max_cycle if start < (self.min_cycle, self.min_qudit): start = CircuitPoint(self.min_cycle, self.min_qudit) if end > (self.max_cycle, self.max_qudit): end = CircuitPoint(self.max_cycle, self.max_qudit) assert isinstance(start, CircuitPoint) # TODO: Typeguard assert isinstance(end, CircuitPoint) # TODO: Typeguard # Pointer into the circuit structure self.cycle = start.cycle if not self.reverse else end.cycle self.qudit = start.qudit if not self.reverse else end.qudit # Used to track changes to circuit structure self.num_ops = self.circuit.get_num_operations() self.num_cycles = self.circuit.get_num_cycles() self.num_qudits = self.circuit.get_size() # Ensure operations are only returned once self.qudits_to_skip: set[int] = set()
def test_not_a_complex(self, not_a_complex: Any) -> None: assert is_sequence(not_a_complex) or not is_complex(not_a_complex)
def test_not_a_seq_bool(self, not_a_seq_bool: Any) -> None: assert (not is_sequence(not_a_seq_bool) or isinstance(not_a_seq_bool, str) or any(not isinstance(b, (bool, np.bool_)) for b in not_a_seq_bool))
def test_a_seq_str(self, a_seq_str: Any) -> None: assert is_sequence(a_seq_str) assert len(a_seq_str) >= 0 assert all(isinstance(s, str) for s in a_seq_str)
def test_not_a_seq_complex(self, not_a_seq_complex: Any) -> None: assert (not is_sequence(not_a_seq_complex) or isinstance(not_a_seq_complex, str) or any(not is_complex(c) for c in not_a_seq_complex))
def test_a_seq_bool(self, a_seq_bool: Any) -> None: assert is_sequence(a_seq_bool) assert len(a_seq_bool) >= 0 assert all(isinstance(b, (bool, np.bool_)) for b in a_seq_bool)
def test_not_a_seq_str(self, not_a_seq_str: Any) -> None: assert (not is_sequence(not_a_seq_str) or isinstance(not_a_seq_str, str) or any(not isinstance(s, str) for s in not_a_seq_str))
def test_not_a_seq_float(self, not_a_seq_float: Any) -> None: assert (not is_sequence(not_a_seq_float) or isinstance(not_a_seq_float, str) or any(not is_numeric(f) or is_integer(f) or is_complex(f) for f in not_a_seq_float))
def test_a_seq_float(self, a_seq_float: Any) -> None: assert is_sequence(a_seq_float) assert len(a_seq_float) >= 0 assert all( is_numeric(f) and not is_integer(f) and not is_complex(f) for f in a_seq_float)
def test_not_a_seq_int(self, not_a_seq_int: Any) -> None: assert (not is_sequence(not_a_seq_int) or isinstance(not_a_seq_int, str) or any(not is_integer(i) for i in not_a_seq_int))
def test_a_seq_int(self, a_seq_int: Any) -> None: assert is_sequence(a_seq_int) assert len(a_seq_int) >= 0 assert all(is_integer(i) for i in a_seq_int)