Portuguese
Idiomas
English
Bengali
French
German
Japanese
Korean
Portuguese
Spanish
Tamil

Nota

Esta página foi gerada, a partir do tutorials/operators/02_gradients_framework.ipynb.

Framework de Gradientes Qiskit

O framework de gradientes permite a avaliação dos gradientes quânticos bem como das suas funções. Além de gradientes de primeira ordem padrões de valores esperados da forma

\[\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle\]

O framework de gradientes também suporta o cálculo de gradientes de segunda ordem (Hessianas), e a Informação Quântica de Fisher (QFI) de estados quânticos \(|\psi\left(\theta\right)\rangle\).

gradient_framework.png

Importações

[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 da Primeira Ordem

Given a parameterized quantum state \(|\psi\left(\theta\right)\rangle = V\left(\theta\right)|\psi\rangle\) with input state \(|\psi\rangle\), parametrized Ansatz \(V\left(\theta\right)\), and observable \(\hat{O}\left(\omega\right)=\sum_{i}\omega_i\hat{O}_i\), we want to compute…

Gradientes com respeito aos Parâmetros do Operador de Medição

Gradiente do valor esperado com respeito a um coeficiente do operador de medição respectivamente observável \(\hat{O}\left(\omega\right)\), ou seja,

\[\frac{\partial\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\omega_i} = \langle\psi\left(\theta\right)|\hat{O}_i\left(\omega\right)|\psi\left(\theta\right)\rangle.\]

Primeiramente, definimos um estado quântico \(|\psi\left(\theta\right)\rangle\) e um Hamiltoniano \(H\) agindo como observável. Então, o estado e o Hamiltoniano são envolvidos em um objeto definindo o valor esperado

\[\langle\psi\left(\theta\right)|H|\psi\left(\theta\right)\rangle.\]
[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) ├
        └───┘└───────┘└───────┘
  )
])

Construímos uma lista com os parâmetros para os quais visamos avaliar o gradiente. Agora, esta lista e o operador de valor de expectativa são usados para gerar o operador que representa o 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) ├
            └───┘└───────┘└─────────────────────────┘
      )
    ])
  ])
])

Tudo o que resta fazer é atribuir valores aos parâmetros e avaliar os operadores gradientes.

[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 com respeito aos Parâmetros de Estado

Gradiente de um valor esperado com respeito a um parâmetro do estado \(|\psi\left(\theta\right)\rangle\), ou seja,

\[\frac{\partial\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\theta}\]

respectivamente às probabilidades amostradas com respeito a um parâmetro do estado \(|\psi\left(\theta\right)\rangle\), ou seja,

\[\frac{\partial p_i}{\partial\theta} = \frac{\partial\langle\psi\left(\theta\right)|i\rangle\langle i |\psi\left(\theta\right)\rangle}{\partial\theta}.\]

Um gradiente com respeito a um parâmetro de estado pode ser avaliado com métodos diferentes. Cada método tem vantagens e desvantagens.

[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 Deslocamento de Parâmetro

Dado um operador Hermitiano \(g\) com dois autovalores únicos \(\pm r\) que atua como gerador para uma porta quântica parametrizada

\[G(\theta)= e^{-i\theta g}.\]

Então, gradientes quânticos podem ser calculados usando deslocamentos dependentes do autovalor \(r\) para os parâmetros. Todas as portas padrões e parametrizadas do Qiskit podem ser deslocadas com \(\pi/2\), isto é,

\[\frac{\partial\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\theta} = \left(\langle\psi\left(\theta+\pi/2\right)|\hat{O}\left(\omega\right)|\psi\left(\theta+\pi/2\right)\rangle -\langle\psi\left(\theta-\pi/2\right)|\hat{O}\left(\omega\right)|\psi\left(\theta-\pi/2\right)\rangle\right) / 2.\]

Os gradientes da probabilidade são computados equivalentemente.

[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)]

Combinação Linear de Gradientes Unitários

Unitários podem ser escritos como \(U\left(\omega\right) = e^{iM\left(\omega\right)}\), onde \(M\left(\omega\right)\) denota uma matriz Hermitiana parametrizada. Além disso, as matrizes Hermitianas podem ser decompostas em somas ponderadas de termos Pauli, ou seja, \(M\left(\omega\right) = \sum_pm_p\left(\omega\right)h_p\) com \(m_p\left(\omega\right)\in\mathbb{R}\) e \(h_p=\bigotimes\limits_{j=0}^{n-1}\sigma_{j, p}\) para \(\sigma_{j, p}\left\{I, X, Y, Z\right\}\) atuando no valor \(j^{\text{th}}\). Assim, os gradientes de \(U_k\left(\omega_k\right)\) são 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)_{k_p}. \end{equation*}

Combinando esta observação com uma estrutura de circuito apresentada em Simulating physical phenomena by quantum networks nos permite calcular o gradiente com a avaliação de um único circuito quâ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 da Diferença Finita

Ao contrário de outros métodos, gradientes finitos de diferença são estimativas numéricas no lugar de valores analíticos. Esta implementação emprega uma abordagem central de diferença com o \(\epsilon \|| 1\)

\[\frac{\partial\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\theta} \approx \frac{1}{2\epsilon} \left(\langle\psi\left(\theta+\epsilon\right)|\hat{O}\left(\omega\right)|\psi\left(\theta+\epsilon\right)\rangle - \partial\langle\psi\left(\theta-\epsilon\right)|\hat{O}\left(\omega\right)|\psi\left(\theta-\epsilon\right)\rangle\right).\]

Os gradientes da probabilidade são computados equivalentemente.

[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

A special type of first order gradient is the natural gradient which has proven itself useful in classical machine learning and is already being studied in the quantum context. This quantity represents a gradient that is “rescaled” with the inverse Quantum Fisher Information matrix (QFI)

\[QFI ^{-1} \frac{\partial\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\theta}.\]

Em vez de inverter a QFI, pode-se também usar um solucionador de mínimos quadrados com ou sem regularização para resolver

\[QFI x = \frac{\partial\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\theta}.\]

A implementação suporta regularização de lasso com busca automática por um bom parâmetro usando L-curve corner search bem como dois tipos de perturbações dos elementos diagonais da QFI.

O gradiente natural pode ser usado no lugar do gradiente padrão com qualquer otimizador baseado em gradientes e/ou solucionador 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 Segunda Ordem)

Quatro tipos de gradientes de segunda ordem são suportados pela estrutura de gradiente.

  1. Gradiente de um valor esperado com relação a um coeficiente do operador de medição, respectivamente, observável \(\hat{O}\left(\omega\right)\), ou seja, \(\frac{\partial^2\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\omega^2}\)

  2. Gradiente de um valor esperado com relação a um coeficiente do operador de medição, respectivamente, observável \(|\psi\left(\theta\right)\rangle\), ou seja, \(\frac{\partial^2\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\theta^2}\)

  3. Gradiente de probabilidades de amostragem com relação a um parâmetro de estado \(|\psi\left(\theta\right)\rangle\), ou seja, \(\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}\)

  4. Gradiente de um valor esperado com relação a um parâmetro de estado \(|\psi\left(\theta\right)\rangle\) e a um coeficiente do operador de medição, respectivamente, observável \(\hat{O}\left(\omega\right)\), ou seja, \(\frac{\partial^2\langle\psi\left(\theta\right)|\hat{O}\left(\omega\right)|\psi\left(\theta\right)\rangle}{\partial\theta\partial\omega}\)

Os exemplos a seguir são dados para os dois primeiros tipos Hessianos. Os Hessianos restantes são avaliadas de forma análoga.

Hessianas com relação aos Parâmetros do Operador de Medição

Novamente, nós definimos um estado quântico \(|\psi\left(\theta\right)\rangle\) e um Hamiltoniano \(H\) agindo como observável. Em seguida, o estado e o Hamiltoniano são envolvidos em um objeto que define o valor esperado

\[\langle\psi\left(\theta\right)|H|\psi\left(\theta\right)\rangle.\]
[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.)

Em seguida, podemos escolher os parâmetros para os quais queremos calcular os gradientes de segunda ordem. - Dada uma tupla, o Hessian irá avaliar o gradiente de segunda ordem para os dois parâmetros. - Dada uma lista, o Hessian irá avaliar o gradiente de segunda ordem para todas as combinações possíveis de tuplas destes parâmetros.

Depois de vincular valores de parâmetro aos parâmetros, a Hessiana pode ser avaliada.

[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 com respeito aos 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]]

Informação Quântica de Fisher (QFI)

A Informação Quântica de Fisher é um tensor métrico que é representativo da capacidade de representação de um estado quântico parametrizado \(|\psi\left(\theta\right)\rangle = V\left(\theta\right)|\psi\rangle\) com estado de entrada \(|\psi\rangle\), Ansatz parametrizado \(V\left(\theta\right)\).

As entradas da QFI para um estado puro mostram

\[QFI_{kl} = 4 * \text{Re}\left[\langle\partial_k\psi|\partial_l\psi\rangle-\langle\partial_k\psi|\psi\rangle\langle\psi|\partial_l\psi\rangle \right].\]

Circuitos QFI

A avaliação da QFI correspondente a um estado quântico gerado por um circuito quântico parametrizado pode ser realizada de diferentes maneiras.

Combinação Linear QFI Completa

To compute the full QFI, we use a working qubit as well as intercepting controlled gates. See e.g. 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]]

Bloco-diagonal e Aproximação Diagonal

Uma aproximação diagonal ou bloco-diagonal da QFI pode ser calculada sem qubits funcionais adicionais. Essa implementação requer a decomposição em rotações de Pauli e Portas não 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]]

Exemplo de Aplicação: VQE com otimização baseada em gradiente

Importações Adicionais

[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

O Framework Gradient também pode ser usado para um VQE baseado no gradiente. Primeiro, o Hamiltoniano e o ansatz da função de onda são inicializados.

[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)

Agora, podemos escolher se o VQE deve usar um Gradient ou um NaturalGradient, defina uma QuantumInstance para executar os circuitos quânticos e executar o 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 SoftwareVersion
QiskitNone
Terra0.17.4
Aer0.8.2
IgnisNone
AquaNone
IBM Q ProviderNone
System information
Python3.8.8 (default, Apr 13 2021, 12:59:45) [Clang 10.0.0 ]
OSDarwin
CPUs2
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.

[ ]: