Callbacks#

Callbacks provide a way to calculate quantities on the state vector as it propagates through the circuit. Example of such quantity is the entanglement entropy, which is currently the only callback implemented in qibo.callbacks.EntanglementEntropy. The user can create custom callbacks by inheriting the qibo.callbacks.Callback class. The point each callback is calculated inside the circuit is defined by adding a qibo.gates.CallbackGate. This can be added similarly to a standard gate and does not affect the state vector.

class qibo.callbacks.Callback[source]#

Base callback class.

Results of a callback can be accessed by indexing the corresponding object.

property nqubits#

Total number of qubits in the circuit that the callback was added in.

Entanglement entropy#

class qibo.callbacks.EntanglementEntropy(partition=None, compute_spectrum=False, base=2)[source]#

Von Neumann entanglement entropy callback.

\[S = \mathrm{Tr} \left ( \rho \log _2 \rho \right )\]
Parameters:
  • partition (list) – List with qubit ids that defines the first subsystem for the entropy calculation. If partition is not given then the first subsystem is the first half of the qubits.

  • compute_spectrum (bool) – Compute the entanglement spectrum. Default is False.

  • base (float) –

Example

from qibo import Circuit, gates
from qibo.callbacks import EntanglementEntropy

# create entropy callback where qubit 0 is the first subsystem
entropy = EntanglementEntropy([0], compute_spectrum=True)
# initialize circuit with 2 qubits and add gates
circuit = Circuit(2)
# add callback gates between normal gates
circuit.add(gates.CallbackGate(entropy))
circuit.add(gates.H(0))
circuit.add(gates.CallbackGate(entropy))
circuit.add(gates.CNOT(0, 1))
circuit.add(gates.CallbackGate(entropy))
# execute the circuit
final_state = circuit()
print(entropy[:])
# Should print [0, 0, 1] which is the entanglement entropy
# after every gate in the calculation.
print(entropy.spectrum)
# Print the entanglement spectrum.
property nqubits#

Total number of qubits in the circuit that the callback was added in.

Norm#

class qibo.callbacks.Norm[source]#

State norm callback.

\[\mathrm{Norm} = \left \langle \Psi | \Psi \right \rangle = \mathrm{Tr} (\rho )\]

Overlap#

class qibo.callbacks.Overlap(state)[source]#

State overlap callback.

Calculates the overlap between the circuit state and a given target state:

\[\mathrm{Overlap} = |\left \langle \Phi | \Psi \right \rangle |\]
Parameters:
  • state (np.ndarray) – Target state to calculate overlap with.

  • normalize (bool) – If True the states are normalized for the overlap calculation.

Energy#

class qibo.callbacks.Energy(hamiltonian)[source]#

Energy expectation value callback.

Calculates the expectation value of a given Hamiltonian as:

\[\left \langle H \right \rangle = \left \langle \Psi | H | \Psi \right \rangle = \mathrm{Tr} (\rho H)\]

assuming that the state is normalized.

Parameters:

hamiltonian (qibo.hamiltonians.Hamiltonian) – Hamiltonian object to calculate its expectation value.

Gap#

class qibo.callbacks.Gap(mode='gap', check_degenerate=True)[source]#

Callback for calculating the gap of adiabatic evolution Hamiltonians.

Can also be used to calculate the Hamiltonian eigenvalues at each time step during the evolution. Note that this callback can only be added in qibo.evolution.AdiabaticEvolution models.

Parameters:
  • mode (str/int) – Defines which quantity this callback calculates. If mode == 'gap' then the difference between ground state and first excited state energy (gap) is calculated. If mode is an integer, then the energy of the corresponding eigenstate is calculated.

  • check_degenerate (bool) – If True the excited state number is increased until a non-zero gap is found. This is used to find the proper gap in the case of degenerate Hamiltonians. This flag is relevant only if mode is 'gap'. Default is True.

Example

from qibo import callbacks, hamiltonians
from qibo.models import AdiabaticEvolution
# define easy and hard Hamiltonians for adiabatic evolution
h0 = hamiltonians.X(3)
h1 = hamiltonians.TFIM(3, h=1.0)
# define callbacks for logging the ground state, first excited
# and gap energy
ground = callbacks.Gap(0)
excited = callbacks.Gap(1)
gap = callbacks.Gap()
# define and execute the ``AdiabaticEvolution`` model
evolution = AdiabaticEvolution(h0, h1, lambda t: t, dt=1e-1,
                               callbacks=[gap, ground, excited])
final_state = evolution(final_time=1.0)
# print results
print(ground[:])
print(excited[:])
print(gap[:])