def validate_parameter(self, parameter): """Initialize instruction parameter can be str, int, float, and complex.""" # Initialize instruction parameter can be str if self._from_label: if parameter in ['0', '1', '+', '-', 'l', 'r']: return parameter raise CircuitError( "invalid param label {0} for instruction {1}. Label should be " "0, 1, +, -, l, or r ".format(type(parameter), self.name)) # Initialize instruction parameter can be int, float, and complex. if isinstance(parameter, (int, float, complex)): return complex(parameter) elif isinstance(parameter, np.number): return complex(parameter.item()) else: raise CircuitError("invalid param type {0} for instruction " "{1}".format(type(parameter), self.name))
def c_if(self, classical, val): """Set a classical equality condition on this instruction between the register or cbit ``classical`` and value ``val``. .. note:: This is a setter method, not an additive one. Calling this multiple times will silently override any previously set condition; it does not stack. """ if not isinstance(classical, (ClassicalRegister, Clbit)): raise CircuitError("c_if must be used with a classical register or classical bit") if val < 0: raise CircuitError("condition value should be non-negative") if isinstance(classical, Clbit): # Casting the conditional value as Boolean when # the classical condition is on a classical bit. val = bool(val) self.condition = (classical, val) return self
def _raise_if_passed_non_real_value(self, parameter_values): nonreal_parameter_values = { p: v for p, v in parameter_values.items() if not isinstance(v, numbers.Real) } if nonreal_parameter_values: raise CircuitError( 'Expression cannot bind non-real or non-numeric ' 'values ({}).'.format(nonreal_parameter_values))
def _raise_if_passed_nan(self, parameter_values): nan_parameter_values = { p: v for p, v in parameter_values.items() if not isinstance(v, numbers.Number) } if nan_parameter_values: raise CircuitError( f"Expression cannot bind non-numeric values ({nan_parameter_values})" )
def validate_parameter(self, parameter): """Hamiltonian parameter has to be an ndarray, operator or float.""" if isinstance(parameter, (float, int, numpy.ndarray)): return parameter elif isinstance(parameter, ParameterExpression) and len( parameter.parameters) == 0: return float(parameter) else: raise CircuitError("invalid param type {0} for gate " "{1}".format(type(parameter), self.name))
def __init__(self, register, index): """Create a new generic bit. """ try: index = int(index) except Exception: raise CircuitError("index needs to be castable to an int: type %s was provided" % type(index)) if index < 0: index += register.size if index >= register.size: raise CircuitError("index must be under the size of the register: %s was provided" % index) self._register = register self._index = index self._update_hash()
def __init__( self, num_qubits: int, pattern: Optional[List[int]] = None, seed: Optional[int] = None, ) -> None: """Return an n_qubit permutation circuit implemented using SWAPs. Args: num_qubits: circuit width. pattern: permutation pattern. If None, permute randomly. seed: random seed in case a random permutation is requested. Raises: CircuitError: if permutation pattern is malformed. Reference Circuit: .. jupyter-execute:: :hide-code: from qiskit.circuit.library import Permutation import qiskit.tools.jupyter A = [2,4,3,0,1] circuit = Permutation(5, A) circuit.draw('mpl') Expanded Circuit: .. jupyter-execute:: :hide-code: from qiskit.circuit.library import Permutation import qiskit.tools.jupyter A = [2,4,3,0,1] circuit = Permutation(5, A) %circuit_library_info circuit.decompose() """ inner = QuantumCircuit(num_qubits) if pattern is not None: if sorted(pattern) != list(range(num_qubits)): raise CircuitError("Permutation pattern must be some " "ordering of 0..num_qubits-1 in a list.") pattern = np.array(pattern) else: rng = np.random.RandomState(seed) pattern = np.arange(num_qubits) rng.shuffle(pattern) name = "permutation_" + np.array_str(pattern).replace(' ', ',') super().__init__(num_qubits, name=name) for i in range(num_qubits): if (pattern[i] != -1) and (pattern[i] != i): inner.swap(i, int(pattern[i])) pattern[pattern[i]] = -1 all_qubits = self.qubits self.append(inner, all_qubits, label=name)
def __init__(self, name, num_qubits, num_clbits, params, duration=None, unit='dt'): """Create a new instruction. Args: name (str): instruction name num_qubits (int): instruction's qubit width num_clbits (int): instruction's clbit width params (list[int|float|complex|str|ndarray|list|ParameterExpression]): list of parameters duration (int or float): instruction's duration. it must be integer if ``unit`` is 'dt' unit (str): time unit of duration Raises: CircuitError: when the register is not in the correct format. """ if not isinstance(num_qubits, int) or not isinstance(num_clbits, int): raise CircuitError("num_qubits and num_clbits must be integer.") if num_qubits < 0 or num_clbits < 0: raise CircuitError( "bad instruction dimensions: %d qubits, %d clbits." % num_qubits, num_clbits) self.name = name self.num_qubits = num_qubits self.num_clbits = num_clbits self._params = [] # a list of gate params stored # tuple (ClassicalRegister, int) when the instruction has a conditional ("if") self.condition = None # list of instructions (and their contexts) that this instruction is composed of # empty definition means opaque or fundamental instruction self._definition = None self.params = params self._duration = duration self._unit = unit
def __init__(self, size, name=None): """Create a new generic register. """ # validate (or cast) size try: valid_size = size == int(size) except (ValueError, TypeError): valid_size = False if not valid_size: raise CircuitError( "Register size must be an integer. (%s '%s' was provided)" % (type(size).__name__, size)) size = int(size) # cast to int if size <= 0: raise CircuitError( "Register size must be positive (%s '%s' was provided)" % (type(size).__name__, size)) # validate (or cast) name if name is None: name = '%s%i' % (self.prefix, next(self.instances_counter)) else: try: name = str(name) except Exception: raise CircuitError( "The circuit name should be castable to a string " "(or None for autogenerate a name).") if self.name_format.match(name) is None: raise CircuitError("%s is an invalid OPENQASM register name." % name) self._name = name self._size = size self._hash = hash((type(self), self._name, self._size)) self._repr = "%s(%d, '%s')" % (self.__class__.__qualname__, self.size, self.name) self._bits = [self.bit_type(self, idx) for idx in range(size)]
def __enter__(self): if self._used: raise CircuitError( "A for-loop context manager cannot be re-entered.") self._used = True self._circuit._push_scope() if self._generate_loop_parameter: self._loop_parameter = Parameter( f"_loop_i_{self._generated_loop_parameters}") type(self)._generated_loop_parameters += 1 return self._loop_parameter
def permutation_pattern(self): """This method first checks if a linear function is a permutation and raises a `qiskit.circuit.exceptions.CircuitError` if not. In the case that this linear function is a permutation, returns the permutation pattern. """ if not self.is_permutation(): raise CircuitError("The linear function is not a permutation") linear = self.linear locs = np.where(linear == 1) return locs[1]
def validate_parameter(self, parameter): """Initialize instruction parameter can be str, int, float, and complex.""" # Initialize instruction parameter can be str if self._from_label: if parameter in ["0", "1", "+", "-", "l", "r"]: return parameter raise CircuitError( "invalid param label {} for instruction {}. Label should be " "0, 1, +, -, l, or r ".format(type(parameter), self.name)) # Initialize instruction parameter can be int, float, and complex. if isinstance(parameter, (int, float, complex)): return complex(parameter) elif isinstance(parameter, np.number): return complex(parameter.item()) else: raise CircuitError( f"invalid param type {type(parameter)} for instruction {self.name}" )
def name(self, value): """Set the register name.""" if self.name_format.match(value) is None: raise CircuitError( "%s is an invalid OPENQASM register name. See appendix" " A of https://arxiv.org/pdf/1707.03429v2.pdf." % value) self._name = value self._hash = hash((type(self), self._name, self._size)) self._repr = "%s(%d, '%s')" % (self.__class__.__qualname__, self.size, self.name) self._update_bits_hash()
def __init__(self, diag: Union[List, np.array]) -> None: """Create a new Diagonal circuit. Args: diag: list of the 2^k diagonal entries (for a diagonal gate on k qubits). Raises: CircuitError: if the list of the diagonal entries or the qubit list is in bad format; if the number of diagonal entries is not 2^k, where k denotes the number of qubits """ if not isinstance(diag, (list, np.ndarray)): raise CircuitError( "Diagonal entries must be in a list or numpy array.") num_qubits = np.log2(len(diag)) if num_qubits < 1 or not num_qubits.is_integer(): raise CircuitError( "The number of diagonal entries is not a positive power of 2.") if not np.allclose(np.abs(diag), 1, atol=_EPS): raise CircuitError( "A diagonal element does not have absolute value one.") num_qubits = int(num_qubits) super().__init__(num_qubits, name="diagonal") # Since the diagonal is a unitary, all its entries have absolute value # one and the diagonal is fully specified by the phases of its entries. diag_phases = [cmath.phase(z) for z in diag] n = len(diag) while n >= 2: angles_rz = [] for i in range(0, n, 2): diag_phases[i // 2], rz_angle = _extract_rz( diag_phases[i], diag_phases[i + 1]) angles_rz.append(rz_angle) num_act_qubits = int(np.log2(n)) ctrl_qubits = list( range(num_qubits - num_act_qubits + 1, num_qubits)) target_qubit = num_qubits - num_act_qubits self.ucrz(angles_rz, ctrl_qubits, target_qubit) n //= 2 self.global_phase += diag_phases[0]
def broadcast_arguments(self, qargs, cargs): qarg = qargs[0] carg = cargs[0] if len(carg) == len(qarg): for qarg, carg in zip(qarg, carg): yield [qarg], [carg] elif len(qarg) == 1 and carg: for each_carg in carg: yield qarg, [each_carg] else: raise CircuitError("register size error")
def _unroll_param_dict(self, value_dict): unrolled_value_dict = {} for (param, value) in value_dict.items(): if isinstance(param, ParameterExpression): unrolled_value_dict[param] = value if isinstance(param, ParameterVector): if not len(param) == len(value): raise CircuitError('ParameterVector {} has length {}, which ' 'differs from value list {} of ' 'len {}'.format(param, len(param), value, len(value))) unrolled_value_dict.update(zip(param, value)) return unrolled_value_dict
def _gate_to_circuit(operation): qr = QuantumRegister(operation.num_qubits) qc = QuantumCircuit(qr, name=operation.name) if hasattr(operation, 'definition') and operation.definition: for rule in operation.definition.data: if rule[0].name in {'id', 'barrier', 'measure', 'snapshot'}: raise CircuitError('Cannot make controlled gate with {} instruction'.format( rule[0].name)) qc.append(rule[0], qargs=[qr[bit.index] for bit in rule[1]], cargs=[]) else: qc.append(operation, qargs=qr, cargs=[]) return qc
def _bit_argument_conversion(bit_representation, in_array): ret = None try: if isinstance(bit_representation, Bit): # circuit.h(qr[0]) -> circuit.h([qr[0]]) ret = [bit_representation] elif isinstance(bit_representation, Register): # circuit.h(qr) -> circuit.h([qr[0], qr[1]]) ret = bit_representation[:] elif isinstance(QuantumCircuit.cast(bit_representation, int), int): # circuit.h(0) -> circuit.h([qr[0]]) ret = [in_array[bit_representation]] elif isinstance(bit_representation, slice): # circuit.h(slice(0,2)) -> circuit.h([qr[0], qr[1]]) ret = in_array[bit_representation] elif _is_bit(bit_representation): # circuit.h((qr, 0)) -> circuit.h([qr[0]]) ret = [bit_representation[0][bit_representation[1]]] elif isinstance(bit_representation, list) and \ all(_is_bit(bit) for bit in bit_representation): ret = [bit[0][bit[1]] for bit in bit_representation] elif isinstance(bit_representation, list) and \ all(isinstance(bit, Bit) for bit in bit_representation): # circuit.h([qr[0], qr[1]]) -> circuit.h([qr[0], qr[1]]) ret = bit_representation elif isinstance(QuantumCircuit.cast(bit_representation, list), (range, list)): # circuit.h([0, 1]) -> circuit.h([qr[0], qr[1]]) # circuit.h(range(0,2)) -> circuit.h([qr[0], qr[1]]) # circuit.h([qr[0],1]) -> circuit.h([qr[0], qr[1]]) ret = [index if isinstance(index, Bit) else in_array[ index] for index in bit_representation] else: raise CircuitError('Not able to expand a %s (%s)' % (bit_representation, type(bit_representation))) except IndexError: raise CircuitError('Index out of range.') except TypeError: raise CircuitError('Type error handling %s (%s)' % (bit_representation, type(bit_representation))) return ret
def params(self, parameters): indexset, loop_parameter, body = parameters if not isinstance(loop_parameter, (Parameter, type(None))): raise CircuitError( "ForLoopOp expects a loop_parameter parameter to " "be either of type Parameter or None, but received " f"{type(loop_parameter)}.") if not isinstance(body, QuantumCircuit): raise CircuitError( "ForLoopOp expects a body parameter to be of type " f"QuantumCircuit, but received {type(body)}.") if body.num_qubits != self.num_qubits or body.num_clbits != self.num_clbits: raise CircuitError( "Attempted to assign a body parameter with a num_qubits or " "num_clbits different than that of the ForLoopOp. " f"ForLoopOp num_qubits/clbits: {self.num_qubits}/{self.num_clbits} " f"Supplied body num_qubits/clbits: {body.num_qubits}/{body.num_clbits}." ) if (loop_parameter is not None and loop_parameter not in body.parameters and loop_parameter.name in (p.name for p in body.parameters)): warnings.warn( "The Parameter provided as a loop_parameter was not found " "on the loop body and so no binding of the indexset to loop " "parameter will occur. A different Parameter of the same name " f"({loop_parameter.name}) was found. If you intended to loop " "over that Parameter, please use that Parameter instance as " "the loop_parameter.", stacklevel=2, ) # Consume indexset into a tuple unless it was provided as a range. # Preserve ranges so that they can be exported as OpenQASM3 ranges. indexset = indexset if isinstance(indexset, range) else tuple(indexset) self._params = [indexset, loop_parameter, body]
def validate_parameter(self, parameter): """Gate parameters should be int, float, or ParameterExpression""" if isinstance(parameter, ParameterExpression): if len(parameter.parameters) > 0: return parameter # expression has free parameters, we cannot validate it if not parameter._symbol_expr.is_real: raise CircuitError("Bound parameter expression is complex in gate {}".format( self.name)) return parameter # per default assume parameters must be real when bound if isinstance(parameter, (int, float)): return parameter elif isinstance(parameter, (np.integer, np.floating)): return parameter.item() elif isinstance(parameter, np.ndarray): warn("Gate param type %s is being deprecated as of 0.16.0, and will be removed " "no earlier than 3 months after that release date. " "Considering creating your own Gate subclass with the method validate_parameter " " to allow this param type." % type(parameter), DeprecationWarning, 3) return parameter else: raise CircuitError("Invalid param type {0} for gate {1}.".format(type(parameter), self.name))
def _raise_if_parameter_names_conflict(self, other_parameters): self_names = {p.name: p for p in self.parameters} other_names = {p.name: p for p in other_parameters} shared_names = self_names.keys() & other_names.keys() conflicting_names = { name for name in shared_names if self_names[name] != other_names[name] } if conflicting_names: raise CircuitError( 'Name conflict applying operation for parameters: ' '{}'.format(conflicting_names))
def index(self): """Get bit's index.""" if (self._register, self._index) == (None, None): raise CircuitError('Attmped to query index of a new-style Bit.') warnings.warn( 'Back-references to from Bit instances to their containing ' 'Registers have been deprecated. Instead, inspect Registers ' 'to find their contained Bits.', DeprecationWarning, stacklevel=2) return self._index
def register(self): """Get bit's register.""" if (self._register, self._index) == (None, None): raise CircuitError("Attmped to query register of a new-style Bit.") warnings.warn( "Back-references to from Bit instances to their containing " "Registers have been deprecated. Instead, inspect Registers " "to find their contained Bits.", DeprecationWarning, stacklevel=2, ) return self._register
def params(self): """Get parameters from base_gate. Returns: list: List of gate parameters. Raises: CircuitError: Controlled gate does not define a base gate """ if self.base_gate: # CU has one additional parameter to the U base gate return self.base_gate.params + self._params else: raise CircuitError("Controlled gate does not define base gate " "for extracting params")
def __setitem__(self, key, value): instruction, qargs, cargs = value if not isinstance(instruction, Instruction) and hasattr(instruction, "to_instruction"): instruction = instruction.to_instruction() if not isinstance(instruction, Instruction): raise CircuitError("object is not an Instruction.") expanded_qargs = [self._circuit.qbit_argument_conversion(qarg) for qarg in qargs or []] expanded_cargs = [self._circuit.cbit_argument_conversion(carg) for carg in cargs or []] broadcast_args = list(instruction.broadcast_arguments(expanded_qargs, expanded_cargs)) if len(broadcast_args) > 1: raise CircuitError( "QuantumCircuit.data modification does not support argument broadcasting." ) qargs, cargs = broadcast_args[0] self._circuit._check_dups(qargs) self._circuit._data[key] = (instruction, qargs, cargs) self._circuit._update_parameter_table(instruction)
def num_ctrl_qubits(self, num_ctrl_qubits): """Set the number of control qubits. Args: num_ctrl_qubits (int): The number of control qubits in [1, num_qubits-1]. Raises: CircuitError: num_ctrl_qubits is not an integer in [1, num_qubits - 1]. """ if (num_ctrl_qubits == int(num_ctrl_qubits) and 1 <= num_ctrl_qubits < self.num_qubits): self._num_ctrl_qubits = num_ctrl_qubits else: raise CircuitError('The number of control qubits must be in [1, num_qubits-1]')
def requester(classical): if isinstance(classical, Clbit): if classical not in clbit_set: raise CircuitError( f"Condition bit {classical} is not in the registers known here: {creg_set}" ) return classical if isinstance(classical, ClassicalRegister): if classical not in creg_set: raise CircuitError( f"Condition register {classical} is not one of the registers known here:" f" {creg_set}" ) return classical if isinstance(classical, int): try: return clbit_flat[classical] except IndexError: raise CircuitError(f"Bit index {classical} is out-of-range.") from None raise CircuitError( "Invalid classical condition. Must be an int, Clbit or ClassicalRegister, but received" f" '{classical}'." )
def to_matrix(self) -> np.ndarray: """Return a Numpy.array for the gate unitary matrix. Returns: np.ndarray: if the Gate subclass has a matrix definition. Raises: CircuitError: If a Gate subclass does not implement this method an exception will be raised when this base class method is called. """ if hasattr(self, "__array__"): # pylint: disable=no-member return self.__array__(dtype=complex) raise CircuitError(f"to_matrix not defined for this {type(self)}")
def params(self, parameters): """Set base gate parameters. Args: parameters (list): The list of parameters to set. Raises: CircuitError: If controlled gate does not define a base gate. """ if self.base_gate: self.base_gate.params = parameters else: raise CircuitError('Controlled gate does not define base gate ' 'for extracting params')
def params(self): """Get parameters from base_gate. Returns: list: List of gate parameters. Raises: CircuitError: Controlled gate does not define a base gate """ if self.base_gate: return self.base_gate.params else: raise CircuitError('Controlled gate does not define base gate ' 'for extracting params')