Skip to content

Commit

Permalink
[pre-commit.ci] auto fixes from pre-commit.com hooks
Browse files Browse the repository at this point in the history
for more information, see https://pre-commit.ci
  • Loading branch information
pre-commit-ci[bot] committed Jun 11, 2024
1 parent 1a1a45a commit ac85e3a
Showing 1 changed file with 54 additions and 33 deletions.
87 changes: 54 additions & 33 deletions src/qibo/models/dbi/utils_gradients.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import numpy as np
import math

from copy import deepcopy
from enum import Enum, auto

import numpy as np

from qibo import symbols
from qibo.hamiltonians import SymbolicHamiltonian
from qibo.models.dbi.utils import commutator
from qibo.models.dbi.utils_scheduling import polynomial_step
from qibo.hamiltonians import SymbolicHamiltonian
from qibo import symbols


class d_ansatz_type(Enum):

element_wise = auto()
local_1 = auto()
#local_2 = auto() # for future implementation
#ising = auto() # for future implementation
# local_2 = auto() # for future implementation
# ising = auto() # for future implementation


def d_ansatz(params: np.array, d_type: d_ansatz_type == d_ansatz_type.element_wise):
r"""
Expand All @@ -33,20 +36,22 @@ def d_ansatz(params: np.array, d_type: d_ansatz_type == d_ansatz_type.element_wi
d[i, i] = params[i]

elif d_type is d_ansatz_type.local_1:
op_list = [params[i]*symbols.Z(i) for i in len(params)]

op_list = [params[i] * symbols.Z(i) for i in len(params)]
from functools import reduce
d = SymbolicHamiltonian(reduce(symbols.Z.add, op_list) , nqubits = len(params))

d = SymbolicHamiltonian(reduce(symbols.Z.add, op_list), nqubits=len(params))
d.dense.matrix
else:
raise ValueError(f"Parameterization type {type} not recognized.")

return d


def dGamma_diDiagonal(d, h, n, i, dGamma, gamma_list):
r"""
Gradient of the nth gamma operator with respect to the ith diagonal elements of D.
$Gamma_{n} = [W,[W,...,[W,H]]...]]$,
$Gamma_{n} = [W,[W,...,[W,H]]...]]$,
$\frac{\partial Gamma_{n}}{\partial D_{ii}} = \partial_{D_{ii}} W\Gamma_{n-1}-\partial_{D_{ii}}\Gamma_{n-1} W$.
and thus is can be computed recursively.
Args:
Expand All @@ -65,9 +70,9 @@ def dGamma_diDiagonal(d, h, n, i, dGamma, gamma_list):
w = commutator(d, h)
return dW_di + commutator(w, dGamma[-1])

#def dpolynomial_diDiagonal(dbi_object, d, h, i): #element_wise_ansatz
def derivative_scalar_product_dbr_approx_element_wise_ansatz(dbi_object, d, h, i):

# def dpolynomial_diDiagonal(dbi_object, d, h, i): #element_wise_ansatz
def derivative_scalar_product_dbr_approx_element_wise_ansatz(dbi_object, d, h, i):
r"""
TODO: add formula and explain terms
Gradient wrt the ith diagonal elements of D.
Expand All @@ -89,7 +94,8 @@ def derivative_scalar_product_dbr_approx_element_wise_ansatz(dbi_object, d, h, i
dD_di[i, i] = 1
dGamma = [commutator(dD_di, h)]
derivative += np.real(
np.trace(gamma_list[0] @ dD_di) + np.trace(dGamma[0] @ d + gamma_list[1] @ dD_di) * s
np.trace(gamma_list[0] @ dD_di)
+ np.trace(dGamma[0] @ d + gamma_list[1] @ dD_di) * s
)
for n in range(2, 4):
dGamma.append(dGamma_diDiagonal(d, h, n, i, dGamma, gamma_list))
Expand All @@ -99,11 +105,14 @@ def derivative_scalar_product_dbr_approx_element_wise_ansatz(dbi_object, d, h, i

return derivative

def gradientDiagonalEntries(dbi_object, params, h, analytic = True, d_type = d_ansatz_type.element_wise, delta = 1e-4):

def gradientDiagonalEntries(
dbi_object, params, h, analytic=True, d_type=d_ansatz_type.element_wise, delta=1e-4
):
r"""
Gradient of the DBI with respect to the parametrization of D. If analytic is True, the analytical gradient of the polynomial expansion of the DBI is used.
As the analytical gradient is applied on the polynomial expansion of the cost function, the numerical gradients may be more accurate.
Args:
dbi_object(DoubleBracketIteration): DoubleBracketIteration object.
params(np.array): Parameters for the ansatz (note that the dimension must be 2**nqubits for full ansazt and nqubits for Pauli ansatz).
Expand All @@ -119,17 +128,27 @@ def gradientDiagonalEntries(dbi_object, params, h, analytic = True, d_type = d_a
d = d_ansatz(params, d_type)
if analytic == True:
for i in range(len(params)):
derivative = derivative_scalar_product_dbr_approx_element_wise_ansatz(dbi_object,d,h,i)
grad[i] = d[i,i]-derivative
derivative = derivative_scalar_product_dbr_approx_element_wise_ansatz(
dbi_object, d, h, i
)
grad[i] = d[i, i] - derivative
else:
for i in range(len(params)):
params_new = deepcopy(params)
params_new[i] += delta
d_new = d_ansatz(params_new, d_type)
grad[i] = (dbi_object.cost(d_new)-dbi_object.cost(d))/delta
grad[i] = (dbi_object.cost(d_new) - dbi_object.cost(d)) / delta
return grad

def gradient_descent_dbr_d_ansatz(dbi_object, params, nmb_iterations, lr = 1e-2, analytic = True, d_type = d_ansatz_type.element_wise):

def gradient_descent_dbr_d_ansatz(
dbi_object,
params,
nmb_iterations,
lr=1e-2,
analytic=True,
d_type=d_ansatz_type.element_wise,
):
r"""
Optimizes the D operator using gradient descent evaluated at the at the rotaion angle found using the polynomial expansion.
- Declare variables
Expand All @@ -142,7 +161,7 @@ def gradient_descent_dbr_d_ansatz(dbi_object, params, nmb_iterations, lr = 1e-2,
nmb_iterations(int): Number of gradient descent iterations.
lr(float): Learning rate.
analytic(bool): If True, the gradient is calculated analytically, otherwise numerically.
d_type(d_ansatz_type): Ansatz used for the D operator.
d_type(d_ansatz_type): Ansatz used for the D operator.
Returns:
d(np.array): Optimized D operator.
loss(np.array): Loss function evaluated at each iteration.
Expand All @@ -151,9 +170,9 @@ def gradient_descent_dbr_d_ansatz(dbi_object, params, nmb_iterations, lr = 1e-2,
"""

h = dbi_object.h.matrix
d = d_ansatz(params,d_type)
loss = np.zeros(nmb_iterations+1)
grad = np.zeros((nmb_iterations,len(params)))
d = d_ansatz(params, d_type)
loss = np.zeros(nmb_iterations + 1)
grad = np.zeros((nmb_iterations, len(params)))
dbi_new = deepcopy(dbi_object)
s = polynomial_step(dbi_object, n=3, d=d)
dbi_new(s, d=d)
Expand All @@ -163,13 +182,15 @@ def gradient_descent_dbr_d_ansatz(dbi_object, params, nmb_iterations, lr = 1e-2,

for i in range(nmb_iterations):
dbi_new = deepcopy(dbi_object)
grad[i,:] = gradientDiagonalEntries(dbi_object, params, h, analytic=analytic, ansatz=d_type)
grad[i, :] = gradientDiagonalEntries(
dbi_object, params, h, analytic=analytic, ansatz=d_type
)
for j in range(len(params)):
params[j] = params[j] - lr*grad[i,j]
d = d_ansatz(params, d_type)
s = polynomial_step(dbi_new, n = 5, d=d)
dbi_new(s,d=d)
loss[i+1] = dbi_new.cost(d)
params_hist[:,i+1] = params
return d,loss,grad,params_hist
params[j] = params[j] - lr * grad[i, j]
d = d_ansatz(params, d_type)
s = polynomial_step(dbi_new, n=5, d=d)
dbi_new(s, d=d)
loss[i + 1] = dbi_new.cost(d)
params_hist[:, i + 1] = params

return d, loss, grad, params_hist

0 comments on commit ac85e3a

Please sign in to comment.