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

Adds 2q prep for iswap instead of sqrt_iswap #6314

Merged
merged 6 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
from cirq.transformers.analytical_decompositions.two_qubit_state_preparation import (
prepare_two_qubit_state_using_cz,
prepare_two_qubit_state_using_sqrt_iswap,
prepare_two_qubit_state_using_iswap,
Dripto marked this conversation as resolved.
Show resolved Hide resolved
)

from cirq.transformers.analytical_decompositions.single_to_two_qubit_isometry import (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,37 @@ def prepare_two_qubit_state_using_cz(
return op_list + _1q_matrices_to_ops(
np.dot(u, np.linalg.inv(u_CZ)), np.dot(vh.T, np.linalg.inv(vh_CZ.T)), q0, q1
)


def prepare_two_qubit_state_using_iswap(
q0: 'cirq.Qid', q1: 'cirq.Qid', state: 'cirq.STATE_VECTOR_LIKE'
Dripto marked this conversation as resolved.
Show resolved Hide resolved
) -> List['cirq.Operation']:
"""Prepares the given 2q state from |00> using at-most 1 ISWAP gate + single qubit rotations.

Entangled states are prepared using exactly 1 ISWAP gate while product states are prepared
using only single qubit rotations (0 ISWAP gates)

Args:
q0: The first qubit being operated on.
q1: The other qubit being operated on.
state: 4x1 matrix representing two qubit state vector, ordered as 00, 01, 10, 11.

Returns:
List of operations (at-most 1 ISWAP + single qubit rotations) preparing state from |00>.
"""
state_vector = qis.to_valid_state_vector(state, num_qubits=2)
state_vector = state_vector / np.linalg.norm(state_vector)
u, s, vh = np.linalg.svd(state_vector.reshape(2, 2))
if np.isclose(s[0], 1):
# Product state can be prepare with just single qubit unitaries.
return _1q_matrices_to_ops(u, vh.T, q0, q1, True)
alpha = np.arccos(np.clip(s[0], 0, 1))
op_list = [ops.ry(2 * alpha).on(q0), ops.H.on(q1), ops.ISWAP.on(q0, q1)]
intermediate_state = circuits.Circuit(op_list).final_state_vector(
ignore_terminal_measurements=False, dtype=np.complex64
)
u_CZ, _, vh_CZ = np.linalg.svd(intermediate_state.reshape(2, 2))
return op_list + _1q_matrices_to_ops(
np.dot(u, np.linalg.inv(u_CZ)), np.dot(vh.T, np.linalg.inv(vh_CZ.T)), q0, q1
)

Dripto marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ def test_prepare_two_qubit_state_using_cz(state):
)


@pytest.mark.parametrize("state", STATES_TO_PREPARE)
def test_prepare_two_qubit_state_using_iswap(state):
state = cirq.to_valid_state_vector(state, num_qubits=2)
q = cirq.LineQubit.range(2)
circuit = cirq.Circuit(cirq.prepare_two_qubit_state_using_iswap(*q, state))
ops_cz = [*circuit.findall_operations(lambda op: op.gate == cirq.CZ)]
ops_2q = [*circuit.findall_operations(lambda op: cirq.num_qubits(op) > 1)]
assert ops_cz == ops_2q
assert len(ops_cz) <= 1
assert cirq.allclose_up_to_global_phase(
circuit.final_state_vector(ignore_terminal_measurements=False, dtype=np.complex64), state
)


@pytest.mark.parametrize("state", STATES_TO_PREPARE)
@pytest.mark.parametrize("use_sqrt_iswap_inv", [True, False])
def test_prepare_two_qubit_state_using_sqrt_iswap(state, use_sqrt_iswap_inv):
Expand Down