Пример #1
0
def qng_grad_gaussian(unitary, g, i, hamiltonian):
    '''
    qng function for getting the gradients of gaussian gates.
    THIS variant of the function does not seek out underlying gate parameters; it treats each variable 'as is'.
    This treatment is necessary for the QNG but is incorrect elsewhere.
    :param unitary: QCircuit: the QCircuit object containing the gate to be differentiated
    :param g: a parametrized: the gate being differentiated
    :param i: Int: the position in unitary at which g appears
    :param variable: Variable or String: the variable with respect to which gate g is being differentiated
    :param hamiltonian: the hamiltonian with respect to which unitary is to be measured, in the case that unitary
        is contained within an ExpectationValue
    :return: a list of objectives; the gradient of the Exp. with respect to each of its (internal) parameters
    '''

    if not hasattr(g, "shift"):
        raise TequilaException("No shift found for gate {}".format(g))

    # neo_a and neo_b are the shifted versions of gate g needed to evaluate its gradient
    shift_a = g._parameter + numpy.pi / (4 * g.shift)
    shift_b = g._parameter - numpy.pi / (4 * g.shift)
    neo_a = copy.deepcopy(g)
    neo_a._parameter = shift_a
    neo_b = copy.deepcopy(g)
    neo_b._parameter = shift_b

    U1 = unitary.replace_gates(positions=[i], circuits=[neo_a])
    w1 = g.shift

    U2 = unitary.replace_gates(positions=[i], circuits=[neo_b])
    w2 = -g.shift

    Oplus = ExpectationValueImpl(U=U1, H=hamiltonian)
    Ominus = ExpectationValueImpl(U=U2, H=hamiltonian)
    dOinc = w1 * Objective(args=[Oplus]) + w2 * Objective(args=[Ominus])
    return dOinc
Пример #2
0
def __grad_gaussian(unitary, g, i, variable, hamiltonian):
    '''
    function for getting the gradients of gaussian gates. NOTE: you had better compile first.
    :param unitary: QCircuit: the QCircuit object containing the gate to be differentiated
    :param g: a parametrized: the gate being differentiated
    :param i: Int: the position in unitary at which g appears
    :param variable: Variable or String: the variable with respect to which gate g is being differentiated
    :param hamiltonian: the hamiltonian with respect to which unitary is to be measured, in the case that unitary
        is contained within an ExpectationValue
    :return: an Objective, whose calculation yields the gradient of g w.r.t variable
    '''

    if not hasattr(g, "shift"):
        raise TequilaException("No shift found for gate {}".format(g))

    # neo_a and neo_b are the shifted versions of gate g needed to evaluate its gradient
    shift_a = g._parameter + np.pi / (4 * g.shift)
    shift_b = g._parameter - np.pi / (4 * g.shift)
    neo_a = copy.deepcopy(g)
    neo_a._parameter = shift_a
    neo_b = copy.deepcopy(g)
    neo_b._parameter = shift_b

    U1 = unitary.replace_gates(positions=[i], circuits=[neo_a])
    w1 = g.shift * __grad_inner(g.parameter, variable)

    U2 = unitary.replace_gates(positions=[i], circuits=[neo_b])
    w2 = -g.shift * __grad_inner(g.parameter, variable)

    Oplus = ExpectationValueImpl(U=U1, H=hamiltonian)
    Ominus = ExpectationValueImpl(U=U2, H=hamiltonian)
    dOinc = w1 * Objective(args=[Oplus]) + w2 * Objective(args=[Ominus])
    return dOinc
Пример #3
0
def __grad_shift_rule(unitary, g, i, variable, hamiltonian):
    '''
    function for getting the gradients of directly differentiable gates. Expects precompiled circuits.
    :param unitary: QCircuit: the QCircuit object containing the gate to be differentiated
    :param g: a parametrized: the gate being differentiated
    :param i: Int: the position in unitary at which g appears
    :param variable: Variable or String: the variable with respect to which gate g is being differentiated
    :param hamiltonian: the hamiltonian with respect to which unitary is to be measured, in the case that unitary
        is contained within an ExpectationValue
    :return: an Objective, whose calculation yields the gradient of g w.r.t variable
    '''

    # possibility for overwride in custom gate construction
    if hasattr(g, "shifted_gates"):
        inner_grad = __grad_inner(g.parameter, variable)
        shifted = g.shifted_gates()
        dOinc = Objective()
        for x in shifted:
            w, g = x
            Ux = unitary.replace_gates(positions=[i], circuits=[g])
            wx = w * inner_grad
            Ex = Objective.ExpectationValue(U=Ux, H=hamiltonian)
            dOinc += wx * Ex
        return dOinc

    if not hasattr(g, "eigenvalues_magnitude"):
        raise TequilaException(
            "No shift-rule found for gate {}. Neither shifted_gates nor eigenvalues_magnitude not defined"
            .format(g))

    # neo_a and neo_b are the shifted versions of gate g needed to evaluate its gradient
    shift_a = g._parameter + pi / (4 * g.eigenvalues_magnitude)
    shift_b = g._parameter - pi / (4 * g.eigenvalues_magnitude)
    neo_a = copy.deepcopy(g)
    neo_a._parameter = shift_a
    neo_b = copy.deepcopy(g)
    neo_b._parameter = shift_b

    U1 = unitary.replace_gates(positions=[i], circuits=[neo_a])
    w1 = g.eigenvalues_magnitude * __grad_inner(g.parameter, variable)

    U2 = unitary.replace_gates(positions=[i], circuits=[neo_b])
    w2 = -g.eigenvalues_magnitude * __grad_inner(g.parameter, variable)

    Oplus = ExpectationValueImpl(U=U1, H=hamiltonian)
    Ominus = ExpectationValueImpl(U=U2, H=hamiltonian)
    dOinc = w1 * Objective(args=[Oplus]) + w2 * Objective(args=[Ominus])
    return dOinc
Пример #4
0
    def compile_objective_argument(self, arg, variables=None, *args, **kwargs):
        """
        Compile an argument of an objective.

        Parameters
        ----------
        arg:
            the term to compile
        variables:
            Todo: jakob, what is this for?
        args
        kwargs

        Returns
        -------
        the arg, compiled
        """

        if isinstance(arg, ExpectationValueImpl) or (hasattr(arg, "U")
                                                     and hasattr(arg, "H")):
            return ExpectationValueImpl(H=arg.H,
                                        U=self.compile_circuit(
                                            abstract_circuit=arg.U,
                                            variables=variables,
                                            *args,
                                            **kwargs))
        elif isinstance(arg, Variable) or hasattr(arg, "name"):
            return arg
        else:
            raise TequilaCompilerException(
                "Unknown argument type for objectives: {arg} or type {type}".
                format(arg=arg, type=type(arg)))
Пример #5
0
    def compile_objective_argument(self, arg, *args, **kwargs):
        """
        Compile an argument of an objective.

        Parameters
        ----------
        arg:
            the term to compile
        args
        kwargs

        Returns
        -------
        the arg, compiled
        """

        if isinstance(arg, ExpectationValueImpl) or (hasattr(arg, "U")
                                                     and hasattr(arg, "H")):
            return ExpectationValueImpl(H=arg.H,
                                        U=self.compile_circuit(
                                            abstract_circuit=arg.U,
                                            *args,
                                            **kwargs))
        elif hasattr(arg, "abstract_expectationvalue"):
            E = arg.abstract_expectationvalue
            E._U = self.compile_circuit(abstract_circuit=E.U, *args, **kwargs)
            return type(arg)(E, **arg._input_args)
        elif isinstance(arg, Variable) or hasattr(arg, "name"):
            return arg
        else:
            raise TequilaCompilerException(
                "Unknown argument type for objectives: {arg} or type {type}".
                format(arg=arg, type=type(arg)))
Пример #6
0
def qng_grad_gaussian(unitary, g, i, hamiltonian) -> Objective:
    """
    get the gradient of an expectationvalue of a unitary and a hamiltonian with respect to gaussian gate g.
    THIS variant of the function does not seek out underlying gate parameters; it treats each variable 'as is'.
    This treatment is necessary for the QNG but is incorrect elsewhere.

    Parameters
    ----------
    unitary: QCircuit:
        the QCircuit object containing the gate to be differentiated
    g: parametrized gate:
        the gate being differentiated
    i: int:
        the position in unitary at which g appears.
    hamiltonian: QubitHamiltonian:
        the hamiltonian with respect to which unitary is to be measured, in the case that unitary
        is contained within an ExpectationValue
    Returns
    -------
    Objective:
        the analytical gradient of  <U,H> w.r.t g=g(theta_g)
    """

    ### unlike grad_gaussian, this doesn't dig below, into a gate's underlying parametrization.
    ### In other words, if a gate is Rx(y), y=f(x), this gives you back d Rx / dy.

    if not hasattr(g, "shift"):
        raise TequilaException("No shift found for gate {}".format(g))

    # neo_a and neo_b are the shifted versions of gate g needed to evaluate its gradient
    shift_a = g._parameter + numpy.pi / (4 * g.shift)
    shift_b = g._parameter - numpy.pi / (4 * g.shift)
    neo_a = copy.deepcopy(g)
    neo_a._parameter = shift_a
    neo_b = copy.deepcopy(g)
    neo_b._parameter = shift_b

    U1 = unitary.replace_gates(positions=[i], circuits=[neo_a])
    w1 = g.shift

    U2 = unitary.replace_gates(positions=[i], circuits=[neo_b])
    w2 = -g.shift

    Oplus = ExpectationValueImpl(U=U1, H=hamiltonian)
    Ominus = ExpectationValueImpl(U=U2, H=hamiltonian)
    dOinc = w1 * Objective(args=[Oplus]) + w2 * Objective(args=[Ominus])
    return dOinc
Пример #7
0
 def compile_objective_argument(self, arg, variables=None, *args, **kwargs):
     if isinstance(arg, ExpectationValueImpl) or (hasattr(arg, "U")
                                                  and hasattr(arg, "H")):
         return ExpectationValueImpl(H=arg.H,
                                     U=self.compile_circuit(
                                         abstract_circuit=arg.U,
                                         variables=variables,
                                         *args,
                                         **kwargs))
     elif isinstance(arg, Variable) or hasattr(arg, "name"):
         return arg
     else:
         raise TequilaCompilerException(
             "Unknown argument type for objectives: {arg} or type {type}".
             format(arg=arg, type=type(arg)))