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 else: raise TequilaException('No shift found for gate {}\nWas the compiler called?'.format(g))
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