Skip to content

Commit

Permalink
Givens gate (#135)
Browse files Browse the repository at this point in the history
* added givens gate decomposition

Co-authored-by: ValentinS4t1qbit <41597680+ValentinS4t1qbit@users.noreply.github.com>
  • Loading branch information
JamesB-1qbit and ValentinS4t1qbit authored Mar 21, 2022
1 parent eefae92 commit 61b2a75
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 3 deletions.
23 changes: 23 additions & 0 deletions tangelo/toolboxes/ansatz_generator/ansatz_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,3 +394,26 @@ def derangement_circuit(qubit_list, control=None, n_qubits=None, decomp=None):
control=control)]

return Circuit(gate_list, n_qubits=n_qubits)


def givens_gate(target, theta, is_variational=False):
"""Generates the list of gates corresponding to a givens rotation exp(-theta*(XX+YY))
Explicitly the two-qubit matrix is
[[0, 0, 0, 0],
[0, cos(theta), -sin(theta), 0],
[0, sin(theta), cos(theta), 0],
[0, 0, 0, 0]]
Args:
target (list): list of two integers that indicate which qubits are involved in the givens rotation
theta (float): the rotation angle
is_variational (bool): Whether the rotation angle is a variational parameter.
Returns:
list of Gate: The list of gates corresponding to the givens rotation"""
if len(target) != 2:
raise ValueError("target must be a list or array of two integers")
return [Gate("CNOT", target=target[0], control=target[1]),
Gate("CRY", target=target[1], control=target[0], parameter=-theta, is_variational=is_variational),
Gate("CNOT", target=target[0], control=target[1])]
22 changes: 19 additions & 3 deletions tangelo/toolboxes/ansatz_generator/tests/test_ansatz_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
from tangelo.molecule_library import mol_H4_sto3g
from tangelo.linq.tests.test_simulator import assert_freq_dict_almost_equal
from tangelo.toolboxes.qubit_mappings.statevector_mapping import get_reference_circuit
from tangelo.toolboxes.ansatz_generator.ansatz_utils import trotterize, get_qft_circuit
from tangelo.toolboxes.ansatz_generator.ansatz_utils import controlled_swap_to_XX_gates
from tangelo.toolboxes.ansatz_generator.ansatz_utils import derangement_circuit, controlled_pauliwords
from tangelo.toolboxes.ansatz_generator.ansatz_utils import (givens_gate, trotterize, get_qft_circuit, controlled_swap_to_XX_gates,
derangement_circuit, controlled_pauliwords)

# Initiate simulators, Use cirq as it has the same ordering for statevectors as openfermion does for Hamiltonians
# This is important when converting the openfermion QubitOperator toarray(), propagating exactly and comparing
Expand Down Expand Up @@ -302,6 +301,23 @@ def test_derangement_circuit_by_estimating_pauli_string(self):
measured = sim.get_expectation_value(exp_op, rho3_pa_circuit, initial_statevector=full_start_vec)
self.assertAlmostEqual(measured, exact, places=6)

def test_givens_gate(self):
"""Test of givens gate decomposition into 2 CNOTs and a CRY gate."""
theta = 0.3

# Explicit definition of givens rotation gate
mat_rep = np.eye(4)
mat_rep[1, 1] = np.cos(theta/2)
mat_rep[1, 2] = -np.sin(theta/2)
mat_rep[2, 1] = np.sin(theta/2)
mat_rep[2, 2] = np.cos(theta/2)

# Test that explicit definition and circuit return the same state vector
vec = np.array([np.sqrt(2)/3, 2/3, np.sqrt(2)/3, 1/3])
gvec = mat_rep@vec
_, gvec2 = sim.simulate(Circuit(givens_gate([0, 1], theta)), return_statevector=True, initial_statevector=vec)
np.testing.assert_array_almost_equal(gvec, gvec2)


if __name__ == "__main__":
unittest.main()

0 comments on commit 61b2a75

Please sign in to comment.