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

Decompose U3 gate to rotation gates for hardware #1614

Merged
merged 15 commits into from
Jun 12, 2024

Conversation

anthony-santana
Copy link
Collaborator

@anthony-santana anthony-santana commented May 6, 2024

Description

  • Writes a decomposition pattern for the u3 gate in terms of rx and rz gates
  • Adds a decomposition test to Quake tests
  • Connects this decomposition pattern to all of the hardware backend configs
  • Tests on each backend in C++ and Python if the u3 gate and its controlled variant is properly lowered and executed

Copy link

copy-pr-bot bot commented May 6, 2024

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@anthony-santana
Copy link
Collaborator Author

anthony-santana commented May 8, 2024

The following code was used to benchmark the simulated accuracy of various decomposition patterns of the u3 gate.

The procedure is as follows.

For each simulator, at various different theta, phi, and lambda angles:

  1. Run each kernel and get their respective measurement distributions.
  2. Take the distance of each distribution from the desired distribution generated by the u3 gate — use the Wasserstein metric. Call this the “infidelity”
  3. Keep a running sum of the infidelity for each kernel, and at the end, take the kernel that has the lowest total infidelity value

Results show that the qiskit and pennylane decompositions produce nearly identical results -- both of which are slightly off from the u3 gate.

import cudaq
import numpy as np
from scipy.stats import wasserstein_distance


@cudaq.kernel
def kernel(theta: float, phi: float, lam: float):
    q = cudaq.qubit()
    u3(theta, phi, lam, q)


@cudaq.kernel
def kernel_b(theta: float, phi: float, lam: float):
    """Trial decomposition."""
    q = cudaq.qubit()
    rx(theta, q)
    ry(phi, q)
    rz(lam, q)

@cudaq.kernel
def kernel_c(theta: float, phi: float, lam: float):
    """First decomposition pattern."""
    q = cudaq.qubit()
    rz(lam, q)
    rx(np.pi / 2, q)
    rz(theta, q)
    rx(-np.pi / 2, q)
    rz(phi, q)


@cudaq.kernel
def kernel_d(theta: float, phi: float, lam: float):
    """Second decomposition pattern"""
    q = cudaq.qubit()
    r1(phi+lam, q)
    rz (-1.*lam, q)
    ry (theta, q)
    rz (lam, q)


def convert_dict_to_distribution(result):
    distribution = None
    # This only works because we'll only be working with
    # single qubit results -- e.g, length 1 bit values instead
    # of bitstrings.
    for bit_value, count in result.items():
        if distribution is None:
            distribution = np.repeat(bit_value, repeats=count)
        else:
            distribution = np.append(distribution,
                                     np.repeat(bit_value, repeats=count))
    return distribution


iteration_count = 12
thetas = np.arange(0.0, 2 * np.pi, step=np.pi / iteration_count, dtype=float)
phis = np.arange(0.0, 2 * np.pi, step=np.pi / iteration_count, dtype=float)
lams = np.arange(0.0, 2 * np.pi, step=np.pi / iteration_count, dtype=float)

np.random.shuffle(thetas)
np.random.shuffle(phis)
np.random.shuffle(lams)

distribution_infidelity_b = 0.0
distribution_infidelity_c = 0.0
distribution_infidelity_d = 0.0

targets = [
    "tensornet", "tensornet-mps", "nvidia-mqpu-fp64", "density-matrix-cpu",
    "nvidia", "nvidia-fp64", "nvidia-mqpu", "nvidia-mqpu-mps" , "qpp-cpu" 
]
for target in targets:
    cudaq.set_target(target)
    for theta, phi, lam in zip(thetas, phis, lams):

        result = cudaq.sample(kernel, theta, phi, lam, shots_count=2000)
        distribution = convert_dict_to_distribution(result)
        # print("result = ", result)
        result_b = cudaq.sample(kernel_b, theta, phi, lam, shots_count=2000)
        distribution_b = convert_dict_to_distribution(result_b)
        # print("result_b = ", result_b)
        result_c = cudaq.sample(kernel_c, theta, phi, lam, shots_count=2000)
        distribution_c = convert_dict_to_distribution(result_c)
        # print("result_c = ", result_c)
        result_d = cudaq.sample(kernel_d, theta, phi, lam, shots_count=2000)
        distribution_d = convert_dict_to_distribution(result_d)
        # print("result_d = ", result_d)

        # print("distribution vs. itself = ", wasserstein_distance(distribution, distribution))
        # print("distribution b = ", wasserstein_distance(distribution, distribution_b))
        # print("distribution c = ", wasserstein_distance(distribution, distribution_c))
        # print("distribution d = ", wasserstein_distance(distribution, distribution_d))

        distribution_infidelity_b += wasserstein_distance(distribution,
                                                        distribution_b)
        distribution_infidelity_c += wasserstein_distance(distribution,
                                                        distribution_c)
        distribution_infidelity_d += wasserstein_distance(distribution,
                                                        distribution_d)

print("total infidelity, b = ", distribution_fidelity_b)
print("total infidelity, c = ", distribution_fidelity_c)
print("total infidelity, d = ", distribution_fidelity_d)

@anthony-santana anthony-santana force-pushed the u3_decomposition branch 4 times, most recently from 81b5b86 to 2e35175 Compare May 15, 2024 19:15
@anthony-santana
Copy link
Collaborator Author

anthony-santana commented May 15, 2024

/ok to test

Command Bot: Processing...

Copy link

CUDA Quantum Docs Bot: A preview of the documentation can be found here.

github-actions bot pushed a commit that referenced this pull request May 15, 2024
@anthony-santana
Copy link
Collaborator Author

anthony-santana commented May 15, 2024

/ok to test

Command Bot: Processing...

Copy link

CUDA Quantum Docs Bot: A preview of the documentation can be found here.

github-actions bot pushed a commit that referenced this pull request May 15, 2024
@anthony-santana anthony-santana force-pushed the u3_decomposition branch 2 times, most recently from 4e3b9a4 to 4ed510c Compare May 20, 2024 19:00
@anthony-santana anthony-santana changed the title [DRAFT] Decompose U3 gate to rotation gates for hardware Decompose U3 gate to rotation gates for hardware May 20, 2024
@anthony-santana anthony-santana marked this pull request as ready for review May 20, 2024 20:00
@anthony-santana
Copy link
Collaborator Author

anthony-santana commented May 20, 2024

/ok to test

Command Bot: Processing...

Copy link

CUDA Quantum Docs Bot: A preview of the documentation can be found here.

github-actions bot pushed a commit that referenced this pull request May 20, 2024
@khalatepradnya
Copy link
Collaborator

You may want to change this Python test - https://github.com/NVIDIA/cuda-quantum/blob/main/python/tests/backends/test_Quantinuum_LocalEmulation_kernel.py#L120. It should no longer raise error.

@anthony-santana
Copy link
Collaborator Author

anthony-santana commented May 30, 2024

/ok to test

Command Bot: Processing...

Copy link

CUDA Quantum Docs Bot: A preview of the documentation can be found here.

github-actions bot pushed a commit that referenced this pull request Jun 11, 2024
@anthony-santana anthony-santana merged commit a423b73 into NVIDIA:main Jun 12, 2024
125 checks passed
@anthony-santana anthony-santana deleted the u3_decomposition branch June 12, 2024 04:08
@github-actions github-actions bot locked and limited conversation to collaborators Jun 12, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for U gate
3 participants