Nota
Esta página fue generada a partir de tutorials/operators/02_gradients_framework.ipynb.
Framework de Gradiente Qiskit¶
El framework de gradiente permite la evaluación de gradientes cuánticos, así como sus funciones. Además de los gradientes estándar de primer orden de los valores esperados de la forma
El framework de gradiente también admite la evaluación de gradientes de segundo orden (Hessianas) y la Información Cuántica de Fisher (Quantum Fisher Information, QFI) de estados cuánticos \(|\psi\left(\theta\right)\rangle\).
Importaciones¶
[1]:
#General imports
import numpy as np
#Operator Imports
from qiskit.opflow import Z, X, I, StateFn, CircuitStateFn, SummedOp
from qiskit.opflow.gradients import Gradient, NaturalGradient, QFI, Hessian
#Circuit imports
from qiskit.circuit import QuantumCircuit, QuantumRegister, Parameter, ParameterVector, ParameterExpression
from qiskit.circuit.library import EfficientSU2
Gradientes de Primer Orden¶
Dado un estado cuántico parametrizado \(|\psi\left(\theta\right)\rangle = V\left(\theta\right)|\psi\rangle\) con estado de entrada \(|\psi\rangle\), Ansatz parametrizado \(V\left(\theta\right)\), y observable \(\hat{O}\left(\omega\right)=\sum_{i}\omega_i\hat{O}_i\), queremos calcular…
Gradientes con respecto a Parámetros del Operador de Medición¶
Gradiente de un valor esperado con respecto a un coeficiente del operador de medición respectivamente observable \(\hat{O}\left(\omega\right)\), es decir,
En primer lugar, definimos un estado cuántico \(|\psi\left(\theta\right)\rangle\) y un Hamiltoniano \(H\) actuando como observable. Luego, el estado y el Hamiltoniano se envuelven en un objeto que define el valor esperado
[2]:
# Instantiate the quantum state
a = Parameter('a')
b = Parameter('b')
q = QuantumRegister(1)
qc = QuantumCircuit(q)
qc.h(q)
qc.rz(a, q[0])
qc.rx(b, q[0])
# Instantiate the Hamiltonian observable
H = (2 * X) + Z
# Combine the Hamiltonian observable and the state
op = ~StateFn(H) @ CircuitStateFn(primitive=qc, coeff=1.)
# Print the operator corresponding to the expectation value
print(op)
ComposedOp([
OperatorMeasurement(2.0 * X
+ 1.0 * Z),
CircuitStateFn(
┌───┐┌───────┐┌───────┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b) ├
└───┘└───────┘└───────┘
)
])
Construimos una lista de los parámetros para los cuales pretendemos evaluar el gradiente. Ahora, esta lista y el operador de valor esperado se utilizan para generar el operador que representa al gradiente.
[3]:
params = [a, b]
# Define the values to be assigned to the parameters
value_dict = {a: np.pi / 4, b: np.pi}
# Convert the operator and the gradient target params into the respective operator
grad = Gradient().convert(operator = op, params = params)
# Print the operator corresponding to the Gradient
print(grad)
ListOp([
SummedOp([
ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌─────────────────────────┐┌───────┐┌───┐
q0_0: ┤ H ├┤ RZ(a + 1.5707963267949) ├┤ RX(b) ├┤ H ├
└───┘└─────────────────────────┘└───────┘└───┘
)
]),
-1.0 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌─────────────────────────┐┌───────┐┌───┐
q0_0: ┤ H ├┤ RZ(a - 1.5707963267949) ├┤ RX(b) ├┤ H ├
└───┘└─────────────────────────┘└───────┘└───┘
)
]),
0.5 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌─────────────────────────┐┌───────┐
q0_0: ┤ H ├┤ RZ(a + 1.5707963267949) ├┤ RX(b) ├
└───┘└─────────────────────────┘└───────┘
)
]),
-0.5 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌─────────────────────────┐┌───────┐
q0_0: ┤ H ├┤ RZ(a - 1.5707963267949) ├┤ RX(b) ├
└───┘└─────────────────────────┘└───────┘
)
])
]),
SummedOp([
ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌─────────────────────────┐┌───┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b + 1.5707963267949) ├┤ H ├
└───┘└───────┘└─────────────────────────┘└───┘
)
]),
-1.0 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌─────────────────────────┐┌───┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b - 1.5707963267949) ├┤ H ├
└───┘└───────┘└─────────────────────────┘└───┘
)
]),
0.5 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌─────────────────────────┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b + 1.5707963267949) ├
└───┘└───────┘└─────────────────────────┘
)
]),
-0.5 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌─────────────────────────┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b - 1.5707963267949) ├
└───┘└───────┘└─────────────────────────┘
)
])
])
])
Todo lo que queda por hacer es asignar valores a los parámetros y evaluar los operadores del gradiente.
[4]:
# Assign the parameters and evaluate the gradient
grad_result = grad.assign_parameters(value_dict).eval()
print('Gradient', grad_result)
Gradient [(-1.414213562373094+0j), (-0.7071067811865474+0j)]
Gradientes con respecto a Parámetros del Estado¶
Gradiente de un valor esperado con respect a un parámetro de estado \(|\psi\left(\theta\right)\rangle\), es decir,
respectivamente a las probabilidades de muestreo con respecto a un parámetro de estado \(|\psi\left(\theta\right)\rangle\), es decir,
Un gradiente con respecto a un parámetro de estado puede evaluarse con diferentes métodos. Cada método tiene ventajas y desventajas.
[5]:
# Define the Hamiltonian with fixed coefficients
H = 0.5 * X - 1 * Z
# Define the parameters w.r.t. we want to compute the gradients
params = [a, b]
# Define the values to be assigned to the parameters
value_dict = { a: np.pi / 4, b: np.pi}
# Combine the Hamiltonian observable and the state into an expectation value operator
op = ~StateFn(H) @ CircuitStateFn(primitive=qc, coeff=1.)
print(op)
ComposedOp([
OperatorMeasurement(0.5 * X
- 1.0 * Z),
CircuitStateFn(
┌───┐┌───────┐┌───────┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b) ├
└───┘└───────┘└───────┘
)
])
Gradientes de Cambio de Parámetro¶
Dado un operador Hermitiano \(g\) con dos valores propios únicos \(\pm r\) que actúa como generador de una compuerta cuántica parametrizada
Luego, los gradientes cuánticos se pueden calcular mediante el uso de cambios dependientes del valor propio \(r\) en los parámetros. Todas las compuertas Qiskit estándar y parametrizadas se pueden desplazar con \(\pi/2\), es decir,
Los gradientes de probabilidad se calculan de forma equivalente.
[6]:
# Convert the expectation value into an operator corresponding to the gradient w.r.t. the state parameters using
# the parameter shift method.
state_grad = Gradient(grad_method='param_shift').convert(operator=op, params=params)
# Print the operator corresponding to the gradient
print(state_grad)
# Assign the parameters and evaluate the gradient
state_grad_result = state_grad.assign_parameters(value_dict).eval()
print('State gradient computed with parameter shift', state_grad_result)
ListOp([
SummedOp([
0.25 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌─────────────────────────┐┌───────┐┌───┐
q0_0: ┤ H ├┤ RZ(a + 1.5707963267949) ├┤ RX(b) ├┤ H ├
└───┘└─────────────────────────┘└───────┘└───┘
)
]),
-0.25 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌─────────────────────────┐┌───────┐┌───┐
q0_0: ┤ H ├┤ RZ(a - 1.5707963267949) ├┤ RX(b) ├┤ H ├
└───┘└─────────────────────────┘└───────┘└───┘
)
]),
-0.5 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌─────────────────────────┐┌───────┐
q0_0: ┤ H ├┤ RZ(a + 1.5707963267949) ├┤ RX(b) ├
└───┘└─────────────────────────┘└───────┘
)
]),
0.5 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌─────────────────────────┐┌───────┐
q0_0: ┤ H ├┤ RZ(a - 1.5707963267949) ├┤ RX(b) ├
└───┘└─────────────────────────┘└───────┘
)
])
]),
SummedOp([
0.25 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌─────────────────────────┐┌───┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b + 1.5707963267949) ├┤ H ├
└───┘└───────┘└─────────────────────────┘└───┘
)
]),
-0.25 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌─────────────────────────┐┌───┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b - 1.5707963267949) ├┤ H ├
└───┘└───────┘└─────────────────────────┘└───┘
)
]),
-0.5 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌─────────────────────────┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b + 1.5707963267949) ├
└───┘└───────┘└─────────────────────────┘
)
]),
0.5 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌─────────────────────────┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b - 1.5707963267949) ├
└───┘└───────┘└─────────────────────────┘
)
])
])
])
State gradient computed with parameter shift [(-0.35355339059327356+0j), (0.7071067811865472+0j)]
Combinación Lineal de Gradientes Unitarios¶
Los operadores unitarios se pueden escribir como \(U\left(\omega\right) = e^{iM\left(\omega\right)}\), donde \(M\left(\omega\right)\) denota una matriz Hermitiana parametrizada. Además, las matrices Hermitianas se pueden descomponer en sumas ponderadas de términos de Pauli, es decir, \(M\left(\omega\right) = \sum_pm_p\left(\omega\right)h_p\) con \(m_p\left(\omega\right)\in\mathbb{R}\) y \(h_p=\bigotimes\limits_{j=0}^{n-1}\sigma_{j, p}\) para \(\sigma_{j, p}\in\left\{I, X, Y, Z\right\}\) actuando en el qubit \(j^{\text{th}}\). Por lo tanto, los gradientes de \(U_k\left(\omega_k\right)\) están dados por \begin{equation*} \frac{\partial U_k\left(\omega_k\right)}{\partial\omega_k} = \sum\limits_pi \frac{\partial m_{k,p}\left(\omega_k\right)}{\partial\omega_k}U_k\left(\omega_k\right)h_{k_p}. \end{equation*}
La combinación de esta observación con una estructura de circuito presentada en Simulating physical phenomena by quantum networks nos permite calcular el gradiente con la evaluación de un solo circuito cuántico.
[7]:
# Convert the expectation value into an operator corresponding to the gradient w.r.t. the state parameter using
# the linear combination of unitaries method.
state_grad = Gradient(grad_method='lin_comb').convert(operator=op, params=params)
# Print the operator corresponding to the gradient
print(state_grad)
# Assign the parameters and evaluate the gradient
state_grad_result = state_grad.assign_parameters(value_dict).eval()
print('State gradient computed with the linear combination method', state_grad_result)
ListOp([
SummedOp([
0.5 * ComposedOp([
OperatorMeasurement(ZZ) * 2.0,
CircuitStateFn(
┌───┐ ┌───────┐┌───────┐┌───┐
q0_0: ┤ H ├────────■─┤ RZ(a) ├┤ RX(b) ├┤ H ├
├───┤┌─────┐ │ └─┬───┬─┘└───────┘└───┘
q81_0: ┤ H ├┤ SDG ├─■───┤ H ├────────────────
└───┘└─────┘ └───┘
) * 0.7071067811865476
]),
-1.0 * ComposedOp([
OperatorMeasurement(ZZ) * 2.0,
CircuitStateFn(
┌───┐ ┌───────┐┌───────┐
q0_0: ┤ H ├────────■─┤ RZ(a) ├┤ RX(b) ├
├───┤┌─────┐ │ └─┬───┬─┘└───────┘
q82_0: ┤ H ├┤ SDG ├─■───┤ H ├───────────
└───┘└─────┘ └───┘
) * 0.7071067811865476
])
]),
SummedOp([
0.5 * ComposedOp([
OperatorMeasurement(ZZ) * 2.0,
CircuitStateFn(
┌───┐┌───────┐┌───┐┌───────┐┌───┐
q0_0: ┤ H ├┤ RZ(a) ├┤ X ├┤ RX(b) ├┤ H ├
├───┤└┬─────┬┘└─┬─┘└─┬───┬─┘└───┘
q83_0: ┤ H ├─┤ SDG ├───■────┤ H ├───────
└───┘ └─────┘ └───┘
) * 0.7071067811865476
]),
-1.0 * ComposedOp([
OperatorMeasurement(ZZ) * 2.0,
CircuitStateFn(
┌───┐┌───────┐┌───┐┌───────┐
q0_0: ┤ H ├┤ RZ(a) ├┤ X ├┤ RX(b) ├
├───┤└┬─────┬┘└─┬─┘└─┬───┬─┘
q84_0: ┤ H ├─┤ SDG ├───■────┤ H ├──
└───┘ └─────┘ └───┘
) * 0.7071067811865476
])
])
])
State gradient computed with the linear combination method [(-0.3535533905932737+0j), (0.7071067811865472+0j)]
Gradientes de Diferencias Finitas¶
A diferencia de los otros métodos, los gradientes de diferencias finitas son estimaciones numéricas en lugar de valores analíticos. Esta implementación emplea un enfoque de diferencia central con \(\epsilon \ll 1\)
Los gradientes de probabilidad se calculan de forma equivalente.
[8]:
# Convert the expectation value into an operator corresponding to the gradient w.r.t. the state parameter using
# the finite difference method.
state_grad = Gradient(grad_method='fin_diff').convert(operator=op, params=params)
# Print the operator corresponding to the gradient
print(state_grad)
# Assign the parameters and evaluate the gradient
state_grad_result = state_grad.assign_parameters(value_dict).eval()
print('State gradient computed with finite difference', state_grad_result)
ListOp([
SummedOp([
250000.0 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌────────────────┐┌───────┐┌───┐
q0_0: ┤ H ├┤ RZ(a + 1.0e-6) ├┤ RX(b) ├┤ H ├
└───┘└────────────────┘└───────┘└───┘
)
]),
-250000.0 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌────────────────┐┌───────┐┌───┐
q0_0: ┤ H ├┤ RZ(a - 1.0e-6) ├┤ RX(b) ├┤ H ├
└───┘└────────────────┘└───────┘└───┘
)
]),
-500000.0 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌────────────────┐┌───────┐
q0_0: ┤ H ├┤ RZ(a + 1.0e-6) ├┤ RX(b) ├
└───┘└────────────────┘└───────┘
)
]),
500000.0 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌────────────────┐┌───────┐
q0_0: ┤ H ├┤ RZ(a - 1.0e-6) ├┤ RX(b) ├
└───┘└────────────────┘└───────┘
)
])
]),
SummedOp([
250000.0 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌────────────────┐┌───┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b + 1.0e-6) ├┤ H ├
└───┘└───────┘└────────────────┘└───┘
)
]),
-250000.0 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌────────────────┐┌───┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b - 1.0e-6) ├┤ H ├
└───┘└───────┘└────────────────┘└───┘
)
]),
-500000.0 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌────────────────┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b + 1.0e-6) ├
└───┘└───────┘└────────────────┘
)
]),
500000.0 * ComposedOp([
OperatorMeasurement(Z),
CircuitStateFn(
┌───┐┌───────┐┌────────────────┐
q0_0: ┤ H ├┤ RZ(a) ├┤ RX(b - 1.0e-6) ├
└───┘└───────┘└────────────────┘
)
])
])
])
State gradient computed with finite difference [(-0.35355339057345814+0j), (0.707106781149+0j)]
Gradiente Natural¶
Un tipo especial de gradiente de primer orden es el gradiente natural que ha demostrado su utilidad en el machine learning clásico y ya se está estudiando en el contexto cuántico. Esta cantidad representa un gradiente que es “reescalado” con la Matriz de Información Cuántica de Fisher (QFI) inversa
En lugar de invertir la QFI, también se puede usar un solucionador de mínimos cuadrados con o sin regularización para resolver
La implementación admite la regularización de ridge y lasso con búsqueda automática de un buen parámetro utilizando la búsqueda de esquina de una curva en L, así como dos tipos de perturbaciones de los elementos diagonales de la QFI.
El gradiente natural se puede utilizar en lugar del gradiente estándar con cualquier optimizador basado en gradiente y/o solucionador de ODE.
[9]:
# Besides the method to compute the circuit gradients resp. QFI, a regularization method can be chosen:
# `ridge` or `lasso` with automatic parameter search or `perturb_diag_elements` or `perturb_diag`
# which perturb the diagonal elements of the QFI.
nat_grad = NaturalGradient(grad_method='lin_comb', qfi_method='lin_comb_full', regularization='ridge').convert(
operator=op, params=params)
# Assign the parameters and evaluate the gradient
nat_grad_result = nat_grad.assign_parameters(value_dict).eval()
print('Natural gradient computed with linear combination of unitaries', nat_grad_result)
Natural gradient computed with linear combination of unitaries [-2.62895551 1.31447775]
Hessianas (Gradientes de Segundo Orden)¶
El framework de gradiente admite cuatro tipos de gradientes de segundo orden.
Gradiente de un valor esperado con respecto a un coeficiente del operador de medición respectivamente observable \(\hat{O}\left(\omega\right)\), es decir, \(\frac{\partial^2\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\omega^2}\)
Gradiente de un valor esperado con respecto a un parámetro del estado \(|\psi\left(\theta\right)\rangle\), es decir, \(\frac{\partial^2\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\theta^2}\)
Gradiente de probabilidades de muestreo con respecto a un parámetro del estado \(|\psi\left(\theta\right)\rangle\), es decir, \(\frac{\partial^2 p_i}{\partial\theta^2} = \frac{\partial^2\langle\psi\left(\theta\right)|i\rangle\langle i|\psi\left(\theta\right)\rangle}{\partial\theta^2}\)
Gradiente de un valor esperado con respecto a un parámetro del estado \(|\psi\left(\theta\right)\rangle\) y un coeficiente del operador de medición respectivamente observable \(\hat{O}\left(\omega\right)\), es decir, \(\frac{\partial^2\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\theta\partial\omega}\)
En los siguientes ejemplos se dan los dos primeros tipos de Hessianas. Las Hessianas restantes se evalúan de forma análoga.
Hessianas con respecto a Parámetros del Operador de Medición¶
Nuevamente, definimos un estado cuántico \(|\psi\left(\theta\right)\rangle\) y un Hamiltoniano \(H\) actuando como observable. Luego, el estado y el Hamiltoniano se envuelven en un objeto que define el valor esperado
[10]:
# Instantiate the Hamiltonian observable
H = X
# Instantiate the quantum state with two parameters
a = Parameter('a')
b = Parameter('b')
q = QuantumRegister(1)
qc = QuantumCircuit(q)
qc.h(q)
qc.rz(a, q[0])
qc.rx(b, q[0])
# Combine the Hamiltonian observable and the state
op = ~StateFn(H) @ CircuitStateFn(primitive=qc, coeff=1.)
A continuación, podemos elegir los parámetros para los que queremos calcular gradientes de segundo orden. - Dada una tupla, la Hessian
evaluará el gradiente de segundo orden para los dos parámetros. - Dada una lista, la Hessian
evaluará el gradiente de segundo orden para todas las posibles combinaciones de tuplas de estos parámetros.
Después de vincular valores a los parámetros, se puede evaluar la Hessiana.
[11]:
# Convert the operator and the hessian target coefficients into the respective operator
hessian = Hessian().convert(operator = op, params = [a, b])
# Define the values to be assigned to the parameters
value_dict = {a: np.pi / 4, b: np.pi/4}
# Assign the parameters and evaluate the Hessian w.r.t. the Hamiltonian coefficients
hessian_result = hessian.assign_parameters(value_dict).eval()
print('Hessian \n', np.real(np.array(hessian_result)))
Hessian
[[-7.07106781e-01 0.00000000e+00]
[ 0.00000000e+00 -5.55111512e-17]]
Hessianas con respecto a los Parámetros de Estado¶
[12]:
# Define parameters
params = [a, b]
# Get the operator object representing the Hessian
state_hess = Hessian(hess_method='param_shift').convert(operator=op, params=params)
# Assign the parameters and evaluate the Hessian
hessian_result = state_hess.assign_parameters(value_dict).eval()
print('Hessian computed using the parameter shift method\n', (np.array(hessian_result)))
# Get the operator object representing the Hessian
state_hess = Hessian(hess_method='lin_comb').convert(operator=op, params=params)
# Assign the parameters and evaluate the Hessian
hessian_result = state_hess.assign_parameters(value_dict).eval()
print('Hessian computed using the linear combination of unitaries method\n', (np.array(hessian_result)))
# Get the operator object representing the Hessian using finite difference
state_hess = Hessian(hess_method='fin_diff').convert(operator=op, params=params)
# Assign the parameters and evaluate the Hessian
hessian_result = state_hess.assign_parameters(value_dict).eval()
print('Hessian computed with finite difference\n', (np.array(hessian_result)))
Hessian computed using the parameter shift method
[[-7.07106781e-01+0.j 0.00000000e+00+0.j]
[ 0.00000000e+00+0.j -5.55111512e-17+0.j]]
Hessian computed using the linear combination of unitaries method
[[-7.07106781e-01+0.j 0.00000000e+00+0.j]
[ 0.00000000e+00+0.j 5.60000000e-17+0.j]]
Hessian computed with finite difference
[[-7.07122803e-01+0.j 3.05175781e-05+0.j]
[ 3.05175781e-05+0.j -6.10351562e-05+0.j]]
Información Cuántica de Fisher (QFI)¶
La Información Cuántica de Fisher es un tensor métrico que es representativo de la capacidad de representación de un estado cuántico parametrizado \(|\psi\left(\theta\right)\rangle = V\left(\theta\right)|\psi\rangle\) con estado de entrada \(|\psi\rangle\), Ansatz parametrizado \(V\left(\theta\right)\).
Las entradas de la QFI para un estado puro se leen
Circuitos QFI¶
La evaluación de la QFI correspondiente a un estado cuántico generado por un circuito cuántico parametrizado se puede realizar de diferentes formas.
Combinación Lineal QFI Completa¶
Para calcular la QFI completa, utilizamos un qubit de trabajo, así como interceptar compuertas controladas. Ver por ejemplo, Variational ansatz-based quantum simulation of imaginary time evolution.
[13]:
# Wrap the quantum circuit into a CircuitStateFn
state = CircuitStateFn(primitive=qc, coeff=1.)
# Convert the state and the parameters into the operator object that represents the QFI
qfi = QFI(qfi_method='lin_comb_full').convert(operator=state, params=params)
# Define the values for which the QFI is to be computed
values_dict = {a: np.pi / 4, b: 0.1}
# Assign the parameters and evaluate the QFI
qfi_result = qfi.assign_parameters(values_dict).eval()
print('full QFI \n', np.real(np.array(qfi_result)))
full QFI
[[ 1.0000000e+00 -2.0659798e-16]
[-2.0659798e-16 5.0000000e-01]]
Aproximación Diagonal y Diagonal en Bloque¶
Se puede calcular una aproximación diagonal de bloque específicamente diagonal de la QFI sin qubits de trabajo adicionales. Esta implementación requiere la descomposición en rotaciones de Pauli y Compuertas no parametrizadas.
[14]:
# Convert the state and the parameters into the operator object that represents the QFI
# and set the approximation to 'block_diagonal'
qfi = QFI('overlap_block_diag').convert(operator=state, params=params)
# Assign the parameters and evaluate the QFI
qfi_result = qfi.assign_parameters(values_dict).eval()
print('Block-diagonal QFI \n', np.real(np.array(qfi_result)))
# Convert the state and the parameters into the operator object that represents the QFI
# and set the approximation to 'diagonal'
qfi = QFI('overlap_diag').convert(operator=state, params=params)
# Assign the parameters and evaluate the QFI
qfi_result = qfi.assign_parameters(values_dict).eval()
print('Diagonal QFI \n', np.real(np.array(qfi_result)))
Block-diagonal QFI
[[1. 0. ]
[0. 0.5]]
Diagonal QFI
[[1. 0. ]
[0. 0.5]]
Ejemplo de Aplicación: VQE con optimización basada en gradientes¶
Importaciones Adicionales¶
[15]:
# Execution Imports
from qiskit import Aer
from qiskit.utils import QuantumInstance
# Algorithm Imports
from qiskit.algorithms import VQE
from qiskit.algorithms.optimizers import CG
El Framework de Gradiente también se puede utilizar para un VQE
basado en gradientes. Primero, se inicializan el Hamiltoniano y el ansatz de la función de onda.
[16]:
from qiskit.opflow import I, X, Z
from qiskit.circuit import QuantumCircuit, ParameterVector
from scipy.optimize import minimize
# Instantiate the system Hamiltonian
h2_hamiltonian = -1.05 * (I ^ I) + 0.39 * (I ^ Z) - 0.39 * (Z ^ I) - 0.01 * (Z ^ Z) + 0.18 * (X ^ X)
# This is the target energy
h2_energy = -1.85727503
# Define the Ansatz
wavefunction = QuantumCircuit(2)
params = ParameterVector('theta', length=8)
it = iter(params)
wavefunction.ry(next(it), 0)
wavefunction.ry(next(it), 1)
wavefunction.rz(next(it), 0)
wavefunction.rz(next(it), 1)
wavefunction.cx(0, 1)
wavefunction.ry(next(it), 0)
wavefunction.ry(next(it), 1)
wavefunction.rz(next(it), 0)
wavefunction.rz(next(it), 1)
# Define the expectation value corresponding to the energy
op = ~StateFn(h2_hamiltonian) @ StateFn(wavefunction)
Ahora, podemos elegir si el VQE
debe usar un Gradient
o un NaturalGradient
, definir una QuantumInstance
para ejecutar los circuitos cuánticos y ejecutar el algoritmo.
[17]:
grad = Gradient(grad_method='lin_comb')
qi_sv = QuantumInstance(Aer.get_backend('aer_simulator_statevector'),
shots=1,
seed_simulator=2,
seed_transpiler=2)
#Conjugate Gradient algorithm
optimizer = CG(maxiter=50)
# Gradient callable
vqe = VQE(wavefunction, optimizer=optimizer, gradient=grad, quantum_instance=qi_sv)
result = vqe.compute_minimum_eigenvalue(h2_hamiltonian)
print('Result:', result.optimal_value, 'Reference:', h2_energy)
Result: -0.8800000000000001 Reference: -1.85727503
[18]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
Qiskit | None |
Terra | 0.17.4 |
Aer | 0.8.2 |
Ignis | None |
Aqua | None |
IBM Q Provider | None |
System information | |
Python | 3.8.8 (default, Apr 13 2021, 12:59:45) [Clang 10.0.0 ] |
OS | Darwin |
CPUs | 2 |
Memory (Gb) | 12.0 |
Fri May 28 09:42:47 2021 EDT |
This code is a part of Qiskit
© Copyright IBM 2017, 2021.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.
[ ]: