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

Add new gates to Photonics simulator #2289

Merged
merged 9 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/config/spelling_allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ qubit
qubits
qudit
qudits
qumode
qumodes
reStructuredText
reconfigurable
runtime
Expand Down
66 changes: 54 additions & 12 deletions docs/sphinx/api/default_ops.rst
Original file line number Diff line number Diff line change
Expand Up @@ -638,31 +638,67 @@ operations, each operating on 2 qubits.
Photonic Operations on Qudits
=============================

These operations are valid only on the `photonics` target which does not support the quantum operations above.
These operations are valid only on the `photonics` target which does not support
the quantum operations above.

:code:`plus`
:code:`create`
khalatepradnya marked this conversation as resolved.
Show resolved Hide resolved
Omar-ORCA marked this conversation as resolved.
Show resolved Hide resolved
---------------------

This is a place-holder, to be updated later.
This operation increments the number of photons in a qumode up to a maximum value
defined by the qudit level that represents the qumode. If it is applied to a qumode
where the number of photons is already at the maximum value, the operation has no
effect.

:math:`U|0\rangle → |1\rangle, U|1\rangle → |2\rangle, U|2\rangle → |3\rangle, \cdots, U|d\rangle → |d\rangle`
where :math:`d` is the qudit level.

.. tab:: Python

.. code-block:: python

q = qudit(3)
plus(q)
create(q)

.. tab:: C++

.. code-block:: cpp

cudaq::qvector<3> q(1);
plus(q[0]);
create(q[0]);

:code:`annihilate`
khalatepradnya marked this conversation as resolved.
Show resolved Hide resolved
---------------------

This operation reduces the number of photons in a qumode up to a minimum value of
0 representing the vacuum state. If it is applied to a qumode where the number of
photons is already at the minimum value 0, the operation has no effect.

:math:`U|0\rangle → |0\rangle, U|1\rangle → |0\rangle, U|2\rangle → |1\rangle, \cdots, U|d\rangle → |d-1\rangle`
where :math:`d` is the qudit level.

.. tab:: Python

.. code-block:: python

q = qudit(3)
annihilate(q)

.. tab:: C++

.. code-block:: cpp

cudaq::qvector<3> q(1);
annihilate(q[0]);

:code:`phase_shift`
---------------------

This is a place-holder, to be updated later.
A phase shifter adds a phase :math:`\phi` on a qumode. For the annihilation (:math:`a_1`)
and creation operators (:math:`a_1^\dagger`) of a qumode, the phase shift operator
is defined by

.. math::
P(\phi) = \exp\left(i \phi a_1^\dagger a_1 \right)

.. tab:: Python

Expand All @@ -681,7 +717,13 @@ This is a place-holder, to be updated later.
:code:`beam_splitter`
---------------------

This is a place-holder, to be updated later.
Beam splitters act on two qumodes together and it is parameterized by a single angle
:math:`\theta`, relating to reflectivity.
For the annihilation (:math:`a_1` and :math:`a_2`) and creation operators (:math:`a_1^\dagger`
and :math:`a_2^\dagger`) of two qumodes, the beam splitter operator is defined by

.. math::
B(\theta) = \exp\left[i \theta (a_1^\dagger a_2 + a_1 a_2^\dagger) \right]

.. tab:: Python

Expand All @@ -700,19 +742,19 @@ This is a place-holder, to be updated later.
:code:`mz`
---------------------

This operation returns the measurement results of the input qudit(s).
This operation returns the measurement results of the input qumode(s).

.. tab:: Python

.. code-block:: python

qutrits = [qudit(3) for _ in range(2)]
mz(qutrits)
qumodes = [qudit(3) for _ in range(2)]
mz(qumodes)


.. tab:: C++

.. code-block:: cpp

cudaq::qvector<3> qutrits(2);
mz(qutrits);
cudaq::qvector<3> qumodes(2);
mz(qumodes);
29 changes: 9 additions & 20 deletions docs/sphinx/targets/cpp/orca.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,13 @@
// To use the ORCA Computing target you will need to set the ORCA_ACCESS_URL
// environment variable or pass the URL to the `--orca-url` flag.

#include "cudaq/orca.h"
#include "cudaq.h"
#include <chrono>
#include <cudaq.h>
#include <cudaq/orca.h>
#include <fstream>
#include <iostream>
#include <thread>

// define helper function to generate linear spaced vectors
template <typename T>
void linear_spaced_vector(std::vector<T> &xs, T min, T max, std::size_t N) {
T h = (max - min) / static_cast<T>(N - 1);
typename std::vector<T>::iterator x;
T val;
for (x = xs.begin(), val = min; x != xs.end(); ++x, val += h) {
*x = val;
}
}

int main() {
using namespace std::this_thread; // sleep_for, sleep_until
using namespace std::chrono_literals; // `ns`, `us`, `ms`, `s`, `h`, etc.
Expand All @@ -39,10 +28,10 @@ int main() {

// half of 8 time bins is filled with a single photon and the other half is
// filled with the vacuum state (empty)
std::vector<std::size_t> input_state{1, 0, 1, 0, 1, 0, 1, 0};
std::vector<std::size_t> input_state = {1, 0, 1, 0, 1, 0, 1, 0};

// The time bin interferometer in this example has two loops, each of length 1
std::vector<std::size_t> loop_lengths{1, 1};
std::vector<std::size_t> loop_lengths = {1, 1};

// helper variables to calculate the number of beam splitters and phase
// shifters needed in the TBI
Expand All @@ -53,18 +42,18 @@ int main() {
const std::size_t n_beam_splitters = n_loops * n_modes - sum_loop_lengths;

// beam splitter angles (created as a linear spaced vector of angles)
std::vector<double> bs_angles(n_beam_splitters);
linear_spaced_vector(bs_angles, M_PI / 8, M_PI / 3, n_beam_splitters);
std::vector<double> bs_angles =
cudaq::linspace(M_PI / 3, M_PI / 6, n_beam_splitters);

// Optionally, we can also specify the phase shifter angles (created as a
// linear spaced vector of angles), if the system includes phase shifters
// ```
// std::vector<double> ps_angles(n_beam_splitters);
// linear_spaced_vector(ps_angles, M_PI / 6, M_PI / 3, n_beam_splitters);
// std::vector<double> ps_angles = cudaq::linspace(M_PI / 3, M_PI / 5,
// n_beam_splitters);
// ```

// we can also set number of requested samples
int n_samples{10000};
int n_samples = 10000;

// Submit to ORCA synchronously (e.g., wait for the job result to be
// returned before proceeding with the rest of the execution).
Expand Down
26 changes: 7 additions & 19 deletions docs/sphinx/targets/cpp/orca_mqpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,28 @@
// ```
// See accompanying example `orca.cpp` for detailed explanation.

#include "cudaq.h"
#include "cudaq/orca.h"

#include <cudaq.h>
#include <cudaq/orca.h>
#include <fstream>
#include <iostream>

// define helper function to generate linear spaced vectors
template <typename T>
void linear_spaced_vector(std::vector<T> &xs, T min, T max, std::size_t N) {
T h = (max - min) / static_cast<T>(N - 1);
typename std::vector<T>::iterator x;
T val;
for (x = xs.begin(), val = min; x != xs.end(); ++x, val += h) {
*x = val;
}
}

int main() {

auto &platform = cudaq::get_platform();
auto num_qpus = platform.num_qpus();
printf("Number of QPUs: %zu\n", num_qpus);

// A time-bin boson sampling experiment
std::vector<std::size_t> input_state{1, 0, 1, 0, 1, 0, 1, 0};
std::vector<std::size_t> loop_lengths{1, 1};
std::vector<std::size_t> input_state = {1, 0, 1, 0, 1, 0, 1, 0};
std::vector<std::size_t> loop_lengths = {1, 1};
std::size_t sum_loop_lengths{std::accumulate(
loop_lengths.begin(), loop_lengths.end(), static_cast<std::size_t>(0))};
const std::size_t n_loops = loop_lengths.size();
const std::size_t n_modes = input_state.size();
const std::size_t n_beam_splitters = n_loops * n_modes - sum_loop_lengths;
std::vector<double> bs_angles(n_beam_splitters);
linear_spaced_vector(bs_angles, M_PI / 8, M_PI / 3, n_beam_splitters);
int n_samples{10000};
std::vector<double> bs_angles =
cudaq::linspace(M_PI / 3, M_PI / 6, n_beam_splitters);
int n_samples = 10000;

std::cout << "Submitting to ORCA Server asynchronously" << std::endl;
std::vector<cudaq::async_sample_result> countFutures;
Expand Down
17 changes: 7 additions & 10 deletions docs/sphinx/targets/cpp/photonics.cpp
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
// Compile and run with:
// ```
// nvq++ --target photonics photonics.cpp
// ./a.out
// nvq++ --target photonics photonics.cpp && ./a.out
// ```

#include "cudaq/photonics.h"
#include "cudaq.h"

struct photonicsKernel {
void operator()() __qpu__ {
cudaq::qvector<3> qutrits(2);
plus(qutrits[0]);
plus(qutrits[1]);
plus(qutrits[1]);
mz(qutrits);
cudaq::qvector<3> qumodes(2);
create(qumodes[0]);
create(qumodes[1]);
create(qumodes[1]);
mz(qumodes);
}
};

int main() {

auto counts = cudaq::sample(photonicsKernel{});
for (auto &[k, v] : counts) {
printf("Result : Count = %s : %lu\n", k.c_str(), v);
}
counts.dump();

auto state = cudaq::get_state(photonicsKernel{});
state.dump();
Expand Down
84 changes: 0 additions & 84 deletions docs/sphinx/targets/cpp/photonics_tbi.cpp

This file was deleted.

Loading
Loading