Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tfim simulation using 2 CNOT rather than 3 CNOT #94

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
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):
shangtai marked this conversation as resolved.
Show resolved Hide resolved
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