Skip to content

Commit

Permalink
Merge pull request #27 from Qulacs-Osaka/26-add-ugate
Browse files Browse the repository at this point in the history
26 add ugate
  • Loading branch information
Glacialte authored Dec 5, 2023
2 parents 0097025 + be9e17e commit a862a33
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 4 deletions.
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
45 changes: 45 additions & 0 deletions qulacs/gate/gate_quantum_matrix.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once

#include <vector>

#include "constant.hpp"
#include "gate.hpp"
#include "update_ops.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 phi, UINT lambda) : _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 phi, UINT lambda)
: _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
7 changes: 7 additions & 0 deletions tests/gate/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,11 @@ 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) {
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

0 comments on commit a862a33

Please sign in to comment.