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

26 add ugate #27

Merged
merged 6 commits into from
Dec 5, 2023
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
1 change: 0 additions & 1 deletion .devcontainer/cpu/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ ENV PYTHONPATH="${PROJECT_DIR}/build:${PYTHONPATH}"

RUN apt-get update && \
apt-get install -y software-properties-common && \
add-apt-repository ppa:ubuntu-toolchain-r/test && \
apt-get update && \
apt-get install -y gcc-10 g++-10 && \
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 && \
Expand Down
1 change: 0 additions & 1 deletion .devcontainer/gpu/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ ENV PYTHONPATH="${PROJECT_DIR}/build:${PYTHONPATH}"

RUN apt-get update && \
apt-get install -y software-properties-common && \
add-apt-repository ppa:ubuntu-toolchain-r/test && \
apt-get update && \
apt-get install -y gcc-10 g++-10 && \
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 && \
Expand Down
5 changes: 5 additions & 0 deletions qulacs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ cmake_minimum_required(VERSION 3.11)
add_library(qulacs)

target_sources(qulacs PRIVATE
gate/gate_one_control_one_target.cpp
gate/gate_one_qubit.cpp
gate/gate_quantum_matrix.cpp
gate/update_ops_matrix_dense_single.cpp
gate/update_ops_one_qubit.cpp
gate/update_ops_one_target_one_control.cpp
gate/update_ops_quantum_matrix.cpp
state/state_vector.cpp
util/random.cpp
)
Expand Down
2 changes: 1 addition & 1 deletion qulacs/gate/gate_one_control_one_target.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "gate_one_control_one_target.hpp"

#include "update_ops_one_target_one_control.hpp"
#include "update_ops.hpp"

namespace qulacs {
void CNOT::update_quantum_state(StateVector& state_vector) const {
Expand Down
17 changes: 17 additions & 0 deletions qulacs/gate/gate_quantum_matrix.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "gate_quantum_matrix.hpp"

#include "update_ops.hpp"

namespace qulacs {
void U1::update_quantum_state(StateVector& state_vector) const {
u_gate(this->_target, this->_matrix, state_vector);
}

void U2::update_quantum_state(StateVector& state_vector) const {
u_gate(this->_target, this->_matrix, state_vector);
}

void U3::update_quantum_state(StateVector& state_vector) const {
u_gate(this->_target, this->_matrix, state_vector);
}
} // namespace qulacs
44 changes: 44 additions & 0 deletions qulacs/gate/gate_quantum_matrix.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include <vector>

#include "gate.hpp"
#include "update_ops.hpp"
#include "constant.hpp"

namespace qulacs {
class U1 : public QuantumGate {
UINT _target;
double _lambda;
std::array<Complex, 4> _matrix;

public:
U1(UINT target, UINT lambda) : _target(target), _lambda(lambda) {
_matrix = get_IBMQ_matrix(0, 0, lambda);
};
void update_quantum_state(StateVector& state_vector) const override;
};
class U2 : public QuantumGate {
UINT _target;
double _lambda, _phi;
std::array<Complex, 4> _matrix;

public:
U2(UINT target, UINT lambda, UINT phi) : _target(target), _phi(phi), _lambda(lambda) {
_matrix = get_IBMQ_matrix(PI / 2.0, phi, lambda);
};
void update_quantum_state(StateVector& state_vector) const override;
};

class U3 : public QuantumGate {
UINT _target;
double _theta, _lambda, _phi;
std::array<Complex, 4> _matrix;

public:
U3(UINT target, UINT theta, UINT lambda, UINT phi) : _target(target), _theta(theta), _phi(phi), _lambda(lambda) {
_matrix = get_IBMQ_matrix(theta, phi, lambda);
};
void update_quantum_state(StateVector& state_vector) const override;
};
} // namespace qulacs
6 changes: 6 additions & 0 deletions qulacs/gate/update_ops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,10 @@ void rz_gate(UINT target_qubit_index, double angle, StateVector& state);
void cnot_gate(UINT control_qubit_index, UINT target_qubit_index, StateVector& state);

void cz_gate(UINT control_qubit_index, UINT target_qubit_index, StateVector& state);

std::array<Complex, 4> get_IBMQ_matrix(double _theta, double _phi, double _lambda);

void single_qubit_dense_matrix_gate(UINT target_qubit_index, std::array<Complex, 4> matrix, StateVector& state);

void u_gate(UINT target_qubit_index, std::array<Complex, 4> matrix, StateVector& state);
} // namespace qulacs
27 changes: 27 additions & 0 deletions qulacs/gate/update_ops_matrix_dense_single.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <Kokkos_Core.hpp>
#include <Kokkos_StdAlgorithms.hpp>

#include "../types.hpp"
#include "update_ops.hpp"

namespace qulacs {
void single_qubit_dense_matrix_gate(UINT target_qubit_index,
std::array<Complex, 4> matrix,
StateVector& state) {
const UINT mask = 1ULL << target_qubit_index;
const UINT mask_low = mask - 1;
const UINT mask_high = ~mask_low;
auto amplitudes = state.amplitudes_raw();
Kokkos::parallel_for(
state.dim() - 1, KOKKOS_LAMBDA(const UINT it) {
UINT basis_0 = (it & mask_low) + ((it & mask_high) << 1);
UINT basis_1 = basis_0 + mask;
Complex val0 = amplitudes[basis_0];
Complex val1 = amplitudes[basis_1];
Complex res0 = matrix[0] * val0 + matrix[1] * val1;
Complex res1 = matrix[2] * val0 + matrix[3] * val1;
amplitudes[basis_0] = res0;
amplitudes[basis_1] = res1;
});
}
} // namespace qulacs
26 changes: 26 additions & 0 deletions qulacs/gate/update_ops_quantum_matrix.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <Kokkos_Core.hpp>
#include <Kokkos_StdAlgorithms.hpp>

#include "../types.hpp"
#include "constant.hpp"
#include "update_ops.hpp"

namespace qulacs {
std::array<Complex, 4> get_IBMQ_matrix(double theta, double phi, double lambda) {
std::array<Complex, 4> matrix;
Complex im = Complex(0, 1);
Complex exp_val1 = std::exp(im * phi);
Complex exp_val2 = std::exp(im * lambda);
Complex cos_val = std::cos(theta / 2.);
Complex sin_val = std::sin(theta / 2.);
matrix[0] = cos_val;
matrix[1] = -exp_val2 * sin_val;
matrix[2] = exp_val1 * sin_val;
matrix[3] = exp_val1 * exp_val2 * cos_val;
return matrix;
}

void u_gate(UINT target_qubit_index, std::array<Complex, 4> matrix, StateVector& state) {
single_qubit_dense_matrix_gate(target_qubit_index, matrix, state);
}
} // namespace qulacs
45 changes: 44 additions & 1 deletion tests/gate/gate_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,47 @@ void run_random_gate_apply(UINT n_qubits, std::function<Eigen::MatrixXcd(double)
}
}

template <class QuantumGateConstructor>
void run_random_gate_apply(UINT n_qubits, std::function<Eigen::MatrixXcd(double, double, double)> matrix_factory) {
const int dim = 1ULL << n_qubits;
Random random;

Eigen::VectorXcd test_state = Eigen::VectorXcd::Zero(dim);
for (int repeat = 0; repeat < 10; repeat++) {
auto state = StateVector::Haar_random_state(n_qubits);
for (int i = 0; i < dim; i++) {
test_state[i] = state[i];
}

const double theta = M_PI * random.uniform();
const double phi = M_PI * random.uniform();
const double lambda = M_PI * random.uniform();
const QuantumGateConstructor gate;
if(typeid(QuantumGateConstructor) == typeid(U1)){
theta = 0;
phi = 0;
gate = QuantumGateConstructor(lambda);
} else if(typeid(QuantumGateConstructor) == typeid(U2)){
theta = M_PI / 2;
gate = QuantumGateConstructor(phi, lambda);
} else if(typeid(QuantumGateConstructor) == typeid(U3)){
gate = QuantumGateConstructor(theta, phi, lambda);
} else {
throw std::runtime_error("Invalid gate type");
}

const auto matrix = matrix_factory(theta, phi, lambda);
const UINT target = random.int64() % n_qubits;
gate.update_quantum_state(state);

test_state = get_expanded_eigen_matrix_with_identity(target, matrix, n_qubits) * test_state;

for (int i = 0; i < dim; i++) {
ASSERT_NEAR(std::abs(state[i] - test_state[i]), 0, eps);
}
}
}

TEST(GateTest, ApplyI) { run_random_gate_apply<I>(5, make_I); }
TEST(GateTest, ApplyX) { run_random_gate_apply<X>(5, make_X); }
TEST(GateTest, ApplyY) { run_random_gate_apply<Y>(5, make_Y); }
Expand All @@ -83,5 +124,7 @@ TEST(GateTest, ApplyP1) { run_random_gate_apply<P1>(5, make_P1); }
TEST(GateTest, ApplyRX) { run_random_gate_apply<RX>(5, make_RX); }
TEST(GateTest, ApplyRY) { run_random_gate_apply<RY>(5, make_RY); }
TEST(GateTest, ApplyRZ) { run_random_gate_apply<RZ>(5, make_RZ); }

TEST(GateTest, ApplyU1) { run_random_gate_apply<U1>(5, make_U); }
TEST(GateTest, ApplyU2) { run_random_gate_apply<U2>(5, make_U); }
TEST(GateTest, ApplyU3) { run_random_gate_apply<U3>(5, make_U); }
} // namespace qulacs
9 changes: 9 additions & 0 deletions tests/gate/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,13 @@ static Eigen::MatrixXcd make_RZ(double angle) {
return make_2x2_matrix(std::exp(-1i * (angle / 2)), 0, 0, std::exp(1i * (angle / 2)));
}

static Eigen::MatrixXcd make_U(double theta, double phi, double lambda) {
double expval1 = std::exp(1i * phi);
double expval2 = std::exp(1i * lambda);
double cosval = std::cos(theta / 2.);
double sinval = std::sin(theta / 2.);
return make_2x2_matrix(std::cos(theta / 2.), -std::exp(1i * lambda) * std::sin(theta / 2.),
std::exp(1i * phi) * std::sin(theta / 2.), std::exp(1i * phi) * std::exp(1i * lambda) * std::cos(theta / 2.));
}

} // namespace qulacs