def _represent_ZGate(self, basis, **options): """ Represents the (I)QFT In the Z Basis """ nqubits = options.get('nqubits',0) if nqubits == 0: raise QuantumError('The number of qubits must be given as nqubits.') if nqubits < self.min_qubits: raise QuantumError( 'The number of qubits %r is too small for the gate.' % nqubits ) size = self.size omega = self.omega #Make a matrix that has the basic Fourier Transform Matrix arrayFT = [[omega**(i*j%size)/sqrt(size) for i in range(size)] for j in range(size)] matrixFT = Matrix(arrayFT) #Embed the FT Matrix in a higher space, if necessary if self.label[0] != 0: matrixFT = matrix_tensor_product(eye(2**self.label[0]), matrixFT) if self.min_qubits < nqubits: matrixFT = matrix_tensor_product(matrixFT, eye(2**(nqubits-self.min_qubits))) return matrixFT
def _eval_args(self, args): if len(args) != 2: raise QuantumError('QFT/IQFT only takes two arguments, got: %r' % args) if args[0] >= args[1]: raise QuantumError("Start must be smaller than finish") return Gate._eval_args(args)
def random_oracle(nqubits, min_img=1, max_img=1, q_type='bin'): """Create a random OracleGate under the given parameter Parameters ========== nqubits : int The number of qubits for OracleGate min_pic : int Minimum number of inverse images that are mapped to 1 max_pic : int Maximum number of inverse images that are mapped to 1 q_type : OracleGate Type of the Qubits that the oracle should be applied on. Can be 'bin' for binary (Qubit()) or 'int' for integer (IntQubit()). Returns ======= OracleGate : random OracleGate under the given parameter Examples ======== Generate random OracleGate that outputs 1 for 2-4 inputs:: >>> from sympy.physics.quantum.grover import random_oracle >>> oracle = random_oracle(4, min_img=2, max_img=4, q_type="bin") """ if q_type != 'bin' and q_type != 'int': raise QuantumError("q_type must be 'int' or 'bin'") if min_img < 1 or max_img < 1: raise QuantumError("min_pic, max_pic must be > 0") if min_img > max_img: raise QuantumError("max_pic must be >= min_pic") if min_img >= 2 ** nqubits or max_img > 2 ** nqubits: raise QuantumError("min_pic must be < 2**nqubits and max_pic must be <= 2**nqubits") import random pics = random.randint(min_img, max_img) integers = random.sample(range(2 ** nqubits), pics) if q_type == "int": items = [IntQubit(i) for i in integers] else: items = [Qubit(IntQubit(i)) for i in integers] return OracleGate(nqubits, lambda qubits: qubits in items)
def _apply_operator_Qubit(self, qubits, **options): """Apply this operator to a Qubit subclass. Parameters ========== qubits : Qubit The qubit subclass to apply this operator to. Returns ======= state : Expr The resulting quantum state. """ if qubits.nqubits != self.nqubits: raise QuantumError( 'OracleGate operates on %r qubits, got: %r' % (self.nqubits, qubits.nqubits) ) # If function returns 1 on qubits # return the negative of the qubits (flip the sign) if self.search_function(qubits): return -qubits else: return qubits
def _eval_args(cls, args): if len(args) != 1: raise QuantumError( 'Insufficient/excessive arguments to W gate. Please ' + 'supply the number of qubits to operate on.') args = UnitaryOperator._eval_args(args) if not args[0].is_Integer: raise TypeError('Integer expected, got: %r' % args[0]) return args
def _validate_targets_controls(tandc): tandc = list(tandc) # Check for integers for bit in tandc: if not bit.is_Integer and not bit.is_Symbol: raise TypeError("Integer expected, got: %r" % tandc[bit]) # Detect duplicates if len(list(set(tandc))) != len(tandc): raise QuantumError("Target/control qubits in a gate cannot be duplicated")
def _represent_ZGate(self, basis, **options): format = options.get("format", "sympy") nqubits = options.get("nqubits", 0) if nqubits == 0: raise QuantumError("The number of qubits must be given as nqubits.") # Make sure we have enough qubits for the gate. if nqubits < self.min_qubits: raise QuantumError( "The number of qubits %r is too small for the gate." % nqubits ) target_matrix = self.get_target_matrix(format) targets = self.targets if isinstance(self, CGate): controls = self.controls else: controls = [] m = represent_zbasis(controls, targets, target_matrix, nqubits, format) return m
def _eval_args(cls, args): if len(args) != 2: raise QuantumError( 'Insufficient/excessive arguments to Oracle. Please ' + 'supply the number of qubits and an unknown function.') sub_args = args[0], sub_args = UnitaryOperator._eval_args(sub_args) if not sub_args[0].is_Integer: raise TypeError('Integer expected, got: %r' % sub_args[0]) if not callable(args[1]): raise TypeError('Callable expected, got: %r' % args[1]) sub_args = UnitaryOperator._eval_args(tuple(range(args[0]))) return (sub_args, args[1])
def _eval_args(cls, args): if len(args) != 2: raise QuantumError( 'Insufficient/excessive arguments to Oracle. Please ' + 'supply the number of qubits and an unknown function.') sub_args = (args[0], ) sub_args = UnitaryOperator._eval_args(sub_args) if not sub_args[0].is_Integer: raise TypeError('Integer expected, got: %r' % sub_args[0]) function = args[1] if not isinstance(function, OracleGateFunction): function = OracleGateFunction(function) return (sub_args[0], function)
def _eval_args(cls, args): # TODO: args[1] is not a subclass of Basic if len(args) != 2: raise QuantumError( "Insufficient/excessive arguments to Oracle. Please " + "supply the number of qubits and an unknown function." ) sub_args = (args[0],) sub_args = UnitaryOperator._eval_args(sub_args) if not sub_args[0].is_Integer: raise TypeError("Integer expected, got: %r" % sub_args[0]) if not callable(args[1]): raise TypeError("Callable expected, got: %r" % args[1]) return (sub_args[0], args[1])
def _apply_operator_Qubit(self, qubits, **options): """ qubits: a set of qubits (Qubit) Returns: quantum object (quantum expression - QExpr) """ if qubits.nqubits != self.nqubits: raise QuantumError('WGate operates on %r qubits, got: %r' % (self.nqubits, qubits.nqubits)) # See 'Quantum Computer Science' by David Mermin p.92 -> W|a> result # Return (2/(sqrt(2^n)))|phi> - |a> where |a> is the current basis # state and phi is the superposition of basis states (see function # create_computational_basis above) basis_states = superposition_basis(self.nqubits) change_to_basis = (2 / sqrt(2**self.nqubits)) * basis_states return change_to_basis - qubits
def __new__(cls, *args): if len(args) != 2: raise QuantumError("Rk gates only take two arguments, got: %r" % args) # For small k, Rk gates simplify to other gates, using these # substitutions give us familiar results for the QFT for small numbers # of qubits. target = args[0] k = args[1] if k == 1: return ZGate(target) elif k == 2: return PhaseGate(target) elif k == 3: return TGate(target) args = cls._eval_args(args) inst = Expr.__new__(cls, *args) inst.hilbert_space = cls._eval_hilbert_space(args) return inst
def _apply_operator_Qubit(self, qubits, **options): """Apply this gate to a Qubit.""" # Check number of qubits this gate acts on. if qubits.nqubits < self.min_qubits: raise QuantumError( "Gate needs a minimum of %r qubits to act on, got: %r" % (self.min_qubits, qubits.nqubits) ) # If the controls are not met, just return if isinstance(self, CGate): if not self.eval_controls(qubits): return qubits targets = self.targets target_matrix = self.get_target_matrix(format="sympy") # Find which column of the target matrix this applies to. column_index = 0 n = 1 for target in targets: column_index += n * qubits[target] n = n << 1 column = target_matrix[:, int(column_index)] # Now apply each column element to the qubit. result = 0 for index in range(column.rows): # TODO: This can be optimized to reduce the number of Qubit # creations. We should simply manipulate the raw list of qubit # values and then build the new Qubit object once. # Make a copy of the incoming qubits. new_qubit = qubits.__class__(*qubits.args) # Flip the bits that need to be flipped. for bit in range(len(targets)): if new_qubit[targets[bit]] != (index >> bit) & 1: new_qubit = new_qubit.flip(targets[bit]) # The value in that row and column times the flipped-bit qubit # is the result for that part. result += column[index] * new_qubit return result
def _eval_args(cls, args): if len(args) != 4: raise QuantumError('Insufficient/excessive arguments to Vx.') return args
def tensor_product_simp_Mul(e): """Simplify a Mul with TensorProducts. Current the main use of this is to simplify a ``Mul`` of ``TensorProduct``s to a ``TensorProduct`` of ``Muls``. It currently only works for relatively simple cases where the initial ``Mul`` only has scalars and raw ``TensorProduct``s, not ``Add``, ``Pow``, ``Commutator``s of ``TensorProduct``s. Parameters ========== e : Expr A ``Mul`` of ``TensorProduct``s to be simplified. Returns ======= e : Expr A ``TensorProduct`` of ``Mul``s. Examples ======== This is an example of the type of simplification that this function performs:: >>> from sympy.physics.quantum.tensorproduct import \ tensor_product_simp_Mul, TensorProduct >>> from sympy import Symbol >>> A = Symbol('A',commutative=False) >>> B = Symbol('B',commutative=False) >>> C = Symbol('C',commutative=False) >>> D = Symbol('D',commutative=False) >>> e = TensorProduct(A,B)*TensorProduct(C,D) >>> e AxB*CxD >>> tensor_product_simp_Mul(e) (A*C)x(B*D) """ # TODO: This won't work with Muls that have other composites of # TensorProducts, like an Add, Pow, Commutator, etc. # TODO: This only works for the equivalent of single Qbit gates. if not isinstance(e, Mul): return e c_part, nc_part = e.args_cnc() n_nc = len(nc_part) if n_nc == 0 or n_nc == 1: return e elif e.has(TensorProduct): nc_part = map(tensor_product_simp, nc_part) nc_s = [] while nc_part: curr = nc_part.pop(0) n_terms = len(curr.args) new_args = list(curr.args) while (len(nc_part) and isinstance(curr, TensorProduct) and isinstance(nc_part[0], TensorProduct)): x = nc_part.pop(0) # TODO: check the hilbert spaces of next and current here. if n_terms != len(x.args): raise QuantumError( 'TensorProducts of different lengths: %r and %r' % (curr, x)) for i in range(len(new_args)): new_args[i] = new_args[i] * x.args[i] curr = TensorProduct(*new_args) nc_s.append(curr) return Mul(*c_part) * Mul(*nc_s) else: return e