Skip to content
Open
62 changes: 62 additions & 0 deletions notebooks/tfim_2cnot_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from qibo.hamiltonians import SymbolicHamiltonian
from boostvqe.models.dbi.double_bracket_evolution_oracles import *
from functools import reduce
import numpy as np
from qibo import hamiltonians
import matplotlib.pyplot as plt

n_qubits = 3
h_coeff = 1
hamiltonian = SymbolicHamiltonian(nqubits=n_qubits)

oracle = TFIM_EvolutionOracle(h=hamiltonian, evolution_oracle_type="trotter", steps=1, B_a=0, order=2)

circuit = oracle.circuit(t_duration=1.0)

unitary = circuit.unitary()
def multikron(matrix_list):
"""Calculates Kronecker product of a list of matrices.

Args:
matrix_list (list): List of matrices as ``ndarray``.

Returns:
ndarray: Kronecker product of all matrices in ``matrix_list``.
"""
return reduce(np.kron, matrix_list)

from numpy.linalg import norm

def our_TFIM(nqubits, h: float = 0.0, dense: bool = True, backend=None):
def multikron(matrix_list):
"""Calculates Kronecker product of a list of matrices."""
return reduce(np.kron, matrix_list)

from qibo.backends import matrices

matrix = (
- multikron([matrices.X, matrices.X]) - h * multikron([matrices.Z, matrices.I])
)
terms = [hamiltonians.terms.HamiltonianTerm(matrix, i, i + 1) for i in range(nqubits - 1)]
terms.append(hamiltonians.terms.HamiltonianTerm(matrix, nqubits - 1, 0))
ham = SymbolicHamiltonian(backend=backend)
ham.terms = terms
return ham

ham = our_TFIM(nqubits=n_qubits, h=h_coeff, dense=False)
truth = ham.exp(1)
verification_norm = []
for step in range(1, 21):
oracle = TFIM_EvolutionOracle(h=hamiltonian, evolution_oracle_type="trotter", steps=step, B_a=h_coeff, order=2)
circuit = oracle.circuit(t_duration=1.0)
unitary = circuit.unitary()
verification_norm.append(norm(truth-unitary))


x = np.array([i for i in range(1, 21)])
plt.plot(x, verification_norm, 'o')
plt.title("verification of TFIM 2 CNOT implementation")
plt.xlabel("steps")
plt.ylabel("norm of difference")

plt.show()
53 changes: 51 additions & 2 deletions src/boostvqe/models/dbi/double_bracket_evolution_oracles.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
from functools import cached_property, reduce
from typing import Union

import hyperopt
import matplotlib.pyplot as plt

#import hyperopt
#import matplotlib.pyplot as plt
import numpy as np
from qibo import Circuit, gates, symbols
from qibo.config import raise_error
Expand Down Expand Up @@ -307,3 +308,51 @@ def circuit(self, t_duration, steps=None, order=None):
steps=steps,
order=order,
)


@dataclass
class TFIM_EvolutionOracle(EvolutionOracle):
steps: int = None
B_a: float = None
order: int = None

def circuit(self, t_duration):
circuit_v = Circuit(self.h.nqubits) # Initialize the circuit with the number of qubits
t_duration /= self.steps
def routine(tmp_circuit, enum_list, routine_t):
for a in enum_list:
tmp_circuit.add(gates.CNOT(a, (a + 1) % self.h.nqubits))
# Time evolution under the transverse field Ising model Hamiltonian
# exp(-i t (X(a) + B_a * Z(a)))
self._time_evolution_step(tmp_circuit, a, routine_t)

# Add second CNOT(a, a+1)
tmp_circuit.add(gates.CNOT(a, (a + 1) % self.h.nqubits))
if self.order is None:
for _ in range(self.steps):
routine(circuit_v, range(self.h.nqubits), t_duration)
elif self.order == 1:
for _ in range(self.steps):
routine(circuit_v, range(0, self.h.nqubits, 2), t_duration)
routine(circuit_v, range(1, self.h.nqubits, 2), t_duration)

elif self.order == 2:
for _ in range(self.steps):
routine(circuit_v, range(1, self.h.nqubits, 2), t_duration/2)
routine(circuit_v, range(0, self.h.nqubits, 2), t_duration)
routine(circuit_v, range(1, self.h.nqubits, 2), t_duration / 2)
else:
print("order must be either 1 or 2")
return circuit_v

def _time_evolution_step(self, tmp_circuit: Circuit, a: int, dt: float):
"""Apply a single Trotter step of the time evolution operator exp(-i dt (X(a) + B_a Z(a)))."""

# Time evolution for X(a)
tmp_circuit.add(gates.RX(a, theta=-2*dt)) # Apply exp(-i dt X(a))

# Time evolution for Z(a)
tmp_circuit.add(gates.RZ(a, theta=-2*dt * self.B_a)) # Apply exp(-i dt B_a Z(a))

return tmp_circuit