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 zero-qubit gate #70

Merged
merged 6 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 6 additions & 1 deletion python/binding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,14 @@ NB_MODULE(qulacs_core, m) {

DEF_GATE(Gate);

DEF_GATE(IGate);
DEF_GATE(GlobalPhaseGate).def("phase", [](const GlobalPhaseGate &gate) {
return gate->phase();
});

#define DEF_ONE_QUBIT_GATE(GATE_TYPE) \
DEF_GATE(GATE_TYPE).def("target", [](const GATE_TYPE &gate) { return gate->target(); })

DEF_ONE_QUBIT_GATE(IGate);
DEF_ONE_QUBIT_GATE(XGate);
DEF_ONE_QUBIT_GATE(YGate);
DEF_ONE_QUBIT_GATE(ZGate);
Expand Down Expand Up @@ -206,6 +210,7 @@ NB_MODULE(qulacs_core, m) {
#define DEF_GATE_FACTORY(GATE_NAME) m.def(#GATE_NAME, &GATE_NAME)

DEF_GATE_FACTORY(I);
DEF_GATE_FACTORY(GlobalPhase);
DEF_GATE_FACTORY(X);
DEF_GATE_FACTORY(Y);
DEF_GATE_FACTORY(Z);
Expand Down
20 changes: 18 additions & 2 deletions python/qulacs2023/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,23 @@ class Gate:
self, arg: qulacs2023.qulacs_core.StateVector, /
) -> None: ...

def GlobalPhase(arg: float, /) -> qulacs2023.qulacs_core.Gate: ...

class GlobalPhaseGate:
"""
None
"""

def __init__(self, arg: qulacs2023.qulacs_core.Gate, /) -> None: ...
def copy(self) -> qulacs2023.qulacs_core.Gate: ...
def get_control_qubit_list(self) -> list[int]: ...
def get_inverse(self) -> qulacs2023.qulacs_core.Gate: ...
def get_target_qubit_list(self) -> list[int]: ...
def phase(self) -> float: ...
def update_quantum_state(
self, arg: qulacs2023.qulacs_core.StateVector, /
) -> None: ...

def H(arg: int, /) -> qulacs2023.qulacs_core.Gate: ...

class HGate:
Expand All @@ -109,7 +126,7 @@ class HGate:
self, arg: qulacs2023.qulacs_core.StateVector, /
) -> None: ...

def I(arg: int, /) -> qulacs2023.qulacs_core.Gate: ...
def I() -> qulacs2023.qulacs_core.Gate: ...

class IGate:
"""
Expand All @@ -121,7 +138,6 @@ class IGate:
def get_control_qubit_list(self) -> list[int]: ...
def get_inverse(self) -> qulacs2023.qulacs_core.Gate: ...
def get_target_qubit_list(self) -> list[int]: ...
def target(self) -> int: ...
def update_quantum_state(
self, arg: qulacs2023.qulacs_core.StateVector, /
) -> None: ...
Expand Down
20 changes: 18 additions & 2 deletions python/qulacs2023/qulacs_core.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,23 @@ class Gate:
self, arg: qulacs2023.qulacs_core.StateVector, /
) -> None: ...

def GlobalPhase(arg: float, /) -> qulacs2023.qulacs_core.Gate: ...

class GlobalPhaseGate:
"""
None
"""

def __init__(self, arg: qulacs2023.qulacs_core.Gate, /) -> None: ...
def copy(self) -> qulacs2023.qulacs_core.Gate: ...
def get_control_qubit_list(self) -> list[int]: ...
def get_inverse(self) -> qulacs2023.qulacs_core.Gate: ...
def get_target_qubit_list(self) -> list[int]: ...
def phase(self) -> float: ...
def update_quantum_state(
self, arg: qulacs2023.qulacs_core.StateVector, /
) -> None: ...

def H(arg: int, /) -> qulacs2023.qulacs_core.Gate: ...

class HGate:
Expand All @@ -109,7 +126,7 @@ class HGate:
self, arg: qulacs2023.qulacs_core.StateVector, /
) -> None: ...

def I(arg: int, /) -> qulacs2023.qulacs_core.Gate: ...
def I() -> qulacs2023.qulacs_core.Gate: ...

class IGate:
"""
Expand All @@ -121,7 +138,6 @@ class IGate:
def get_control_qubit_list(self) -> list[int]: ...
def get_inverse(self) -> qulacs2023.qulacs_core.Gate: ...
def get_target_qubit_list(self) -> list[int]: ...
def target(self) -> int: ...
def update_quantum_state(
self, arg: qulacs2023.qulacs_core.StateVector, /
) -> None: ...
Expand Down
2 changes: 2 additions & 0 deletions qulacs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ target_sources(qulacs PRIVATE
gate/gate_pauli.cpp
gate/gate_quantum_matrix.cpp
gate/gate_two_qubit.cpp
gate/gate_zero_qubit.cpp
gate/update_ops_dense_matrix.cpp
gate/update_ops_npair_qubit.cpp
gate/update_ops_one_control_one_target.cpp
gate/update_ops_one_qubit.cpp
gate/update_ops_pauli.cpp
gate/update_ops_quantum_matrix.cpp
gate/update_ops_two_qubit.cpp
gate/update_ops_zero_qubit.cpp
operator/pauli_operator.cpp
operator/operator.cpp
state/state_vector.cpp
Expand Down
6 changes: 4 additions & 2 deletions qulacs/gate/gate_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "gate/gate_pauli.hpp"
#include "gate/gate_quantum_matrix.hpp"
#include "gate/gate_two_qubit.hpp"
#include "gate/gate_zero_qubit.hpp"

namespace qulacs {
namespace internal {
Expand All @@ -18,8 +19,9 @@ class GateFactory {
};
} // namespace internal

inline Gate I(UINT target) {
return internal::GateFactory::create_gate<internal::IGateImpl>(target);
inline Gate I() { return internal::GateFactory::create_gate<internal::IGateImpl>(); }
inline Gate GlobalPhase(double phase) {
return internal::GateFactory::create_gate<internal::GlobalPhaseGateImpl>(phase);
}
inline Gate X(UINT target) {
return internal::GateFactory::create_gate<internal::XGateImpl>(target);
Expand Down
5 changes: 0 additions & 5 deletions qulacs/gate/gate_one_qubit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ Gate TGateImpl::get_inverse() const { return std::make_shared<TdagGateImpl>(_tar
Gate SqrtXGateImpl::get_inverse() const { return std::make_shared<SqrtXdagGateImpl>(_target); }
Gate SqrtYGateImpl::get_inverse() const { return std::make_shared<SqrtYdagGateImpl>(_target); }

void IGateImpl::update_quantum_state(StateVector& state_vector) const {
check_qubit_within_bounds(state_vector, this->_target);
i_gate(this->_target, state_vector);
}

void XGateImpl::update_quantum_state(StateVector& state_vector) const {
check_qubit_within_bounds(state_vector, this->_target);
x_gate(this->_target, state_vector);
Expand Down
11 changes: 0 additions & 11 deletions qulacs/gate/gate_one_qubit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,6 @@ class OneQubitRotationGateBase : public OneQubitGateBase {
double angle() const { return _angle; }
};

class IGateImpl : public OneQubitGateBase {
public:
IGateImpl(UINT target) : OneQubitGateBase(target){};

Gate copy() const override { return std::make_shared<IGateImpl>(*this); }
Gate get_inverse() const override { return std::make_shared<IGateImpl>(*this); }

void update_quantum_state(StateVector& state_vector) const override;
};

class XGateImpl : public OneQubitGateBase {
public:
XGateImpl(UINT target) : OneQubitGateBase(target){};
Expand Down Expand Up @@ -212,7 +202,6 @@ class RZGateImpl : public OneQubitRotationGateBase {
};
} // namespace internal

using IGate = internal::GatePtr<internal::IGateImpl>;
using XGate = internal::GatePtr<internal::XGateImpl>;
using YGate = internal::GatePtr<internal::YGateImpl>;
using ZGate = internal::GatePtr<internal::ZGateImpl>;
Expand Down
13 changes: 13 additions & 0 deletions qulacs/gate/gate_zero_qubit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "gate_zero_qubit.hpp"

#include "update_ops.hpp"

namespace qulacs {
namespace internal {
void IGateImpl::update_quantum_state(StateVector& state_vector) const { i_gate(state_vector); }

void GlobalPhaseGateImpl::update_quantum_state(StateVector& state_vector) const {
global_phase_gate(_phase, state_vector);
}
} // namespace internal
} // namespace qulacs
43 changes: 43 additions & 0 deletions qulacs/gate/gate_zero_qubit.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

#include "gate.hpp"

namespace qulacs {
namespace internal {
class ZeroQubitGateBase : public GateBase {
public:
ZeroQubitGateBase(){};

std::vector<UINT> get_target_qubit_list() const override { return {}; }
std::vector<UINT> get_control_qubit_list() const override { return {}; };
};

class IGateImpl : public ZeroQubitGateBase {
public:
IGateImpl() : ZeroQubitGateBase(){};

Gate copy() const override { return std::make_shared<IGateImpl>(*this); }
Gate get_inverse() const override { return std::make_shared<IGateImpl>(*this); }

void update_quantum_state(StateVector& state_vector) const override;
};

class GlobalPhaseGateImpl : public ZeroQubitGateBase {
protected:
double _phase;

public:
GlobalPhaseGateImpl(double phase) : ZeroQubitGateBase(), _phase(phase){};

[[nodiscard]] double phase() const { return _phase; }

Gate copy() const override { return std::make_shared<GlobalPhaseGateImpl>(*this); }
Gate get_inverse() const override { return std::make_shared<GlobalPhaseGateImpl>(-_phase); }

void update_quantum_state(StateVector& state_vector) const override;
};
} // namespace internal

using IGate = internal::GatePtr<internal::IGateImpl>;
using GlobalPhaseGate = internal::GatePtr<internal::GlobalPhaseGateImpl>;
} // namespace qulacs
4 changes: 3 additions & 1 deletion qulacs/gate/update_ops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ inline void check_qubit_within_bounds(const StateVector& state, UINT op_qubit) {
}
}

void i_gate(UINT target_qubit_index, StateVector& state);
void i_gate(StateVector& state);

void global_phase_gate(double angle, StateVector& state);

void x_gate(UINT target_qubit_index, StateVector& state);

Expand Down
2 changes: 0 additions & 2 deletions qulacs/gate/update_ops_one_qubit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

namespace qulacs {
namespace internal {
void i_gate(UINT, StateVector&) {}

void x_gate(UINT target_qubit_index, StateVector& state) {
Kokkos::parallel_for(
state.dim() >> 1, KOKKOS_LAMBDA(const UINT& it) {
Expand Down
13 changes: 13 additions & 0 deletions qulacs/gate/update_ops_zero_qubit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "update_ops.hpp"

namespace qulacs {
namespace internal {
void i_gate(StateVector&) {}

void global_phase_gate(double phase, StateVector& state) {
Complex coef = Kokkos::polar(1., phase);
Kokkos::parallel_for(
state.dim(), KOKKOS_LAMBDA(const UINT& i) { state._raw[i] *= coef; });
}
} // namespace internal
} // namespace qulacs
53 changes: 52 additions & 1 deletion tests/gate/gate_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,56 @@ using namespace qulacs;
const auto eps = 1e-12;
using CComplex = std::complex<double>;

template <Gate (*QuantumGateConstructor)()>
void run_random_gate_apply(UINT n_qubits) {
const int dim = 1ULL << n_qubits;

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

const Gate gate = QuantumGateConstructor();
gate->update_quantum_state(state);
state_cp = state.amplitudes();

test_state = test_state;

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

template <Gate (*QuantumGateConstructor)(double)>
void run_random_gate_apply(UINT n_qubits) {
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);
auto state_cp = state.amplitudes();
for (int i = 0; i < dim; i++) {
test_state[i] = state_cp[i];
}

const double angle = M_PI * random.uniform();
const Gate gate = QuantumGateConstructor(angle);
gate->update_quantum_state(state);
state_cp = state.amplitudes();

test_state = std::polar(1., angle) * test_state;

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

template <Gate (*QuantumGateConstructor)(UINT)>
void run_random_gate_apply(UINT n_qubits, std::function<Eigen::MatrixXcd()> matrix_factory) {
const auto matrix = matrix_factory();
Expand Down Expand Up @@ -324,7 +374,8 @@ void run_random_gate_apply_pauli(UINT n_qubits) {
}
}

TEST(GateTest, ApplyI) { run_random_gate_apply<I>(5, make_I); }
TEST(GateTest, ApplyI) { run_random_gate_apply<I>(5); }
TEST(GateTest, ApplyGlobalPhase) { run_random_gate_apply<GlobalPhase>(5); }
TEST(GateTest, ApplyX) { run_random_gate_apply<X>(5, make_X); }
TEST(GateTest, ApplyY) { run_random_gate_apply<Y>(5, make_Y); }
TEST(GateTest, ApplyZ) { run_random_gate_apply<Z>(5, make_Z); }
Expand Down
Loading