Exemple #1
0
    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
Exemple #2
0
 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)
Exemple #3
0
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)
Exemple #4
0
    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
Exemple #6
0
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")
Exemple #7
0
    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
Exemple #8
0
 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])
Exemple #9
0
    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)
Exemple #10
0
    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
Exemple #12
0
 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
Exemple #13
0
    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
Exemple #15
0
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