Skip to content
Open
40 changes: 40 additions & 0 deletions src/boostvqe/models/dbi/double_bracket_evolution_oracles.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,43 @@ 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

def circuit(self, a, t_duration, B_a, steps=None, order=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def circuit(self, a, t_duration, B_a, steps=None, order=None):
def circuit(self, t_duration, steps=None, order=None):

This class must implement eo.circuit(0.1) without requiring other parameters.

What is a?

Copy link
Contributor Author

@shangtai shangtai Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use the notation in the paper where a is an index and B_a is another parameter.

$$H^{(a)}=X_{a}X_{a+1}+B_{a}Z_{a}$$

if steps is None:
steps = self.steps

circuit = Circuit(self.h.nqubits) # Initialize the circuit with the number of qubits

# Add CNOT(a, a+1)
circuit.add(gates.CNOT(a, a + 1))

# Time evolution under the transverse field Ising model Hamiltonian
# exp(-i t (X(a) + B_a * Z(a)))
dt = t_duration / steps # Divide the time duration for Trotterization if needed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
dt = t_duration / steps # Divide the time duration for Trotterization if needed
dt = t_duration / steps # Divide the time duration for Trotterization if needed
for a in range(nqubits:
circuit.add(gates.CNOT(a, a + 1))
circuit += self._time_evolution_step(a, dt, B_a)
circuit.add(gates.CNOT(a, a + 1))

and then loop this over _ in range(steps)

Copy link
Contributor Author

@shangtai shangtai Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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


from qibo import hamiltonians
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()
    #print(norm(truth-unitary))
    verification_norm.append(norm(truth-unitary))

import matplotlib.pyplot as plt
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()

produces the following graph:

Screenshot 2024-11-20 at 3 19 27 PM


for _ in range(steps):
# Apply time evolution for X(a) + B_a * Z(a)
circuit += self._time_evolution_step(a, dt, B_a)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is commuting so it's equivalent to
circuit += self._time_evolution_step(a, t_duration, B_a)

Once you have for a in range(self.nqubits): (TFIM evolution oracle should be implemented for nqubits) then you need to do the CNOTs before every dt step here


# Add second CNOT(a, a+1)
circuit.add(gates.CNOT(a, a + 1))

return circuit

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

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

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

return step_circuit