Skip to content

Commit

Permalink
Merge pull request #169 from qulacs/166-stub-check
Browse files Browse the repository at this point in the history
Stubを分割
  • Loading branch information
KowerKoint authored Sep 10, 2024
2 parents b8baf55 + ddcf43b commit e7f133a
Show file tree
Hide file tree
Showing 22 changed files with 1,071 additions and 821 deletions.
2 changes: 2 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ AccessModifierOffset: -4
BinPackArguments: false
BinPackParameters: false
ColumnLimit: 100
DerivePointerAlignment: false
PointerAlignment: Left
5 changes: 5 additions & 0 deletions .github/workflows/ci_ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ jobs:
- name: Test in Ubuntu
run: |
OMP_PROC_BIND=false ninja test -C build -j $(nproc)
- name: Test if stub exists
run: |
echo -e "from scaluq import StateVector\nfrom scaluq.gate import I" > /tmp/stub_sample.py
mypy /tmp/stub_sample.py
nvcc-build:
name: NVCC build
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@ homepage = "http://www.scaluq.org"

[project.optional-dependencies]
dev = [
"mypy == 1.11.2",
"scikit-build == 0.17.6",
"typing_extensions == 4.12.0",
"numpy == 1.26.0",
"nanobind == 2.0.0"
]

ci = [
"mypy == 1.11.2",
"scikit-build == 0.17.6",
"typing_extensions == 4.12.0",
"numpy == 1.26.0",
Expand Down
842 changes: 24 additions & 818 deletions python/binding.cpp

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions scaluq/circuit/circuit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,58 @@ class Circuit {
void check_gate_is_valid(const Gate& gate) const;
void check_gate_is_valid(const ParamGate& gate) const;
};

#ifdef SCALUQ_USE_NANOBIND
namespace internal {
void bind_circuit_circuit_hpp(nb::module_& m) {
nb::class_<Circuit>(m, "Circuit", "Quantum circuit represented as gate array")
.def(nb::init<std::uint64_t>(), "Initialize empty circuit of specified qubits.")
.def("n_qubits", &Circuit::n_qubits, "Get property of `n_qubits`.")
.def("gate_list",
&Circuit::gate_list,
"Get property of `gate_list`.",
nb::rv_policy::reference)
.def("n_gates", &Circuit::n_gates, "Get property of `n_gates`.")
.def("key_set", &Circuit::key_set, "Get set of keys of parameters.")
.def("get_gate_at", &Circuit::get_gate_at, "Get reference of i-th gate.")
.def("get_param_key_at",
&Circuit::get_param_key_at,
"Get parameter key of i-th gate. If it is not parametric, return None.")
.def("calculate_depth", &Circuit::calculate_depth, "Get depth of circuit.")
.def("add_gate",
nb::overload_cast<const Gate&>(&Circuit::add_gate),
"Add gate. Given gate is copied.")
.def("add_param_gate",
nb::overload_cast<const ParamGate&, std::string_view>(&Circuit::add_param_gate),
"Add parametric gate with specifing key. Given param_gate is copied.")
.def("add_circuit",
nb::overload_cast<const Circuit&>(&Circuit::add_circuit),
"Add all gates in specified circuit. Given gates are copied.")
.def("update_quantum_state",
&Circuit::update_quantum_state,
"Apply gate to the StateVector. StateVector in args is directly updated. If the "
"circuit contains parametric gate, you have to give real value of parameter as "
"dict[str, float] in 2nd arg.")
.def(
"update_quantum_state",
[&](const Circuit& circuit, StateVector& state, nb::kwargs kwargs) {
std::map<std::string, double> parameters;
for (auto&& [key, param] : kwargs) {
parameters[nb::cast<std::string>(key)] = nb::cast<double>(param);
}
circuit.update_quantum_state(state, parameters);
},
"Apply gate to the StateVector. StateVector in args is directly updated. If the "
"circuit contains parametric gate, you have to give real value of parameter as "
"\"name=value\" format in kwargs.")
.def(
"update_quantum_state",
[](const Circuit& circuit, StateVector& state) { circuit.update_quantum_state(state); })
.def("copy", &Circuit::copy, "Copy circuit. All the gates inside is copied.")
.def("get_inverse",
&Circuit::get_inverse,
"Get inverse of circuit. All the gates are newly created.");
}
} // namespace internal
#endif
} // namespace scaluq
93 changes: 93 additions & 0 deletions scaluq/gate/gate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,97 @@ class GatePtr {
};
} // namespace internal

#ifdef SCALUQ_USE_NANOBIND
namespace internal {
#define DEF_GATE_BASE(GATE_TYPE, DESCRIPTION) \
nb::class_<GATE_TYPE>(m, #GATE_TYPE, DESCRIPTION) \
.def("gate_type", &GATE_TYPE::gate_type, "Get gate type as `GateType` enum.") \
.def( \
"target_qubit_list", \
[](const GATE_TYPE& gate) { return gate->target_qubit_list(); }, \
"Get target qubits as `list[int]`. **Control qubits is not included.**") \
.def( \
"control_qubit_list", \
[](const GATE_TYPE& gate) { return gate->control_qubit_list(); }, \
"Get control qubits as `list[int]`.") \
.def( \
"operand_qubit_list", \
[](const GATE_TYPE& gate) { return gate->operand_qubit_list(); }, \
"Get target and control qubits as `list[int]`.") \
.def( \
"target_qubit_mask", \
[](const GATE_TYPE& gate) { return gate->target_qubit_mask(); }, \
"Get target qubits as mask. **Control qubits is not included.**") \
.def( \
"control_qubit_mask", \
[](const GATE_TYPE& gate) { return gate->control_qubit_mask(); }, \
"Get control qubits as mask.") \
.def( \
"operand_qubit_mask", \
[](const GATE_TYPE& gate) { return gate->operand_qubit_mask(); }, \
"Get target and control qubits as mask.") \
.def( \
"get_inverse", \
[](const GATE_TYPE& gate) { return gate->get_inverse(); }, \
"Generate inverse gate as `Gate` type. If not exists, return None.") \
.def( \
"update_quantum_state", \
[](const GATE_TYPE& gate, StateVector& state_vector) { \
gate->update_quantum_state(state_vector); \
}, \
"Apply gate to `state_vector`. `state_vector` in args is directly updated.") \
.def( \
"get_matrix", \
[](const GATE_TYPE& gate) { return gate->get_matrix(); }, \
"Get matrix representation of the gate.")

nb::class_<Gate> gate_base_def;

#define DEF_GATE(GATE_TYPE, DESCRIPTION) \
::scaluq::internal::gate_base_def.def(nb::init<GATE_TYPE>(), "Upcast from `" #GATE_TYPE "`."); \
DEF_GATE_BASE( \
GATE_TYPE, \
DESCRIPTION \
"\n\n.. note:: Upcast is required to use gate-general functions (ex: add to Circuit).") \
.def(nb::init<Gate>())

void bind_gate_gate_hpp(nb::module_& m) {
nb::enum_<GateType>(m, "GateType", "Enum of Gate Type.")
.value("I", GateType::I)
.value("GlobalPhase", GateType::GlobalPhase)
.value("X", GateType::X)
.value("Y", GateType::Y)
.value("Z", GateType::Z)
.value("H", GateType::H)
.value("S", GateType::S)
.value("Sdag", GateType::Sdag)
.value("T", GateType::T)
.value("Tdag", GateType::Tdag)
.value("SqrtX", GateType::SqrtX)
.value("SqrtXdag", GateType::SqrtXdag)
.value("SqrtY", GateType::SqrtY)
.value("SqrtYdag", GateType::SqrtYdag)
.value("P0", GateType::P0)
.value("P1", GateType::P1)
.value("RX", GateType::RX)
.value("RY", GateType::RY)
.value("RZ", GateType::RZ)
.value("U1", GateType::U1)
.value("U2", GateType::U2)
.value("U3", GateType::U3)
.value("OneTargetMatrix", GateType::OneTargetMatrix)
.value("Swap", GateType::Swap)
.value("TwoTargetMatrix", GateType::TwoTargetMatrix)
.value("Pauli", GateType::Pauli)
.value("PauliRotation", GateType::PauliRotation);

gate_base_def =
DEF_GATE_BASE(Gate,
"General class of QuantumGate.\n\n.. note:: Downcast to requred to use "
"gate-specific functions.")
.def(nb::init<Gate>(), "Just copy shallowly.");
}
} // namespace internal
#endif

} // namespace scaluq
189 changes: 188 additions & 1 deletion scaluq/gate/gate_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ inline Gate TwoTargetMatrix(std::uint64_t target1,
return internal::GateFactory::create_gate<internal::TwoTargetMatrixGateImpl>(
internal::vector_to_mask({target1, target2}), internal::vector_to_mask(controls), matrix);
}
// まだ
inline Gate Pauli(const PauliOperator& pauli, const std::vector<std::uint64_t>& controls = {}) {
auto tar = pauli.target_qubit_list();
return internal::GateFactory::create_gate<internal::PauliGateImpl>(
Expand Down Expand Up @@ -214,4 +213,192 @@ inline Gate Probablistic(const std::vector<double>& distribution,
gate_list);
}
} // namespace gate

#ifdef SCALUQ_USE_NANOBIND
namespace internal {
void bind_gate_gate_factory_hpp(nb::module_& mgate) {
mgate.def("I", &gate::I, "Generate general Gate class instance of I.");
mgate.def("GlobalPhase",
&gate::GlobalPhase,
"Generate general Gate class instance of GlobalPhase.",
"phase"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("X",
&gate::X,
"Generate general Gate class instance of X.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("Y",
&gate::Y,
"Generate general Gate class instance of Y.",
"taget"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("Z",
&gate::Z,
"Generate general Gate class instance of Z.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("H",
&gate::H,
"Generate general Gate class instance of H.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("S",
&gate::S,
"Generate general Gate class instance of S.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("Sdag",
&gate::Sdag,
"Generate general Gate class instance of Sdag.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("T",
&gate::T,
"Generate general Gate class instance of T.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("Tdag",
&gate::Tdag,
"Generate general Gate class instance of Tdag.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("SqrtX",
&gate::SqrtX,
"Generate general Gate class instance of SqrtX.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("SqrtXdag",
&gate::SqrtXdag,
"Generate general Gate class instance of SqrtXdag.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("SqrtY",
&gate::SqrtY,
"Generate general Gate class instance of SqrtY.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("SqrtYdag",
&gate::SqrtYdag,
"Generate general Gate class instance of SqrtYdag.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("P0",
&gate::P0,
"Generate general Gate class instance of P0.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("P1",
&gate::P1,
"Generate general Gate class instance of P1.",
"target"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("RX",
&gate::RX,
"Generate general Gate class instance of RX.",
"target"_a,
"angle"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("RY",
&gate::RY,
"Generate general Gate class instance of RY.",
"target"_a,
"angle"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("RZ",
&gate::RZ,
"Generate general Gate class instance of RZ.",
"target"_a,
"angle"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("U1",
&gate::U1,
"Generate general Gate class instance of U1.",
"target"_a,
"lambda_"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("U2",
&gate::U2,
"Generate general Gate class instance of U2.",
"target"_a,
"phi"_a,
"lambda_"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("U3",
&gate::U3,
"Generate general Gate class instance of U3.",
"target"_a,
"theta"_a,
"phi"_a,
"lambda_"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("Swap",
&gate::Swap,
"Generate general Gate class instance of Swap.",
"target1"_a,
"target2"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def(
"CX",
&gate::CX,
"Generate general Gate class instance of CX.\n\n.. note:: CX is a specialization of X.");
mgate.def("CNot",
&gate::CX,
"Generate general Gate class instance of CNot.\n\n.. note:: CNot is an alias of CX.");
mgate.def(
"CZ",
&gate::CZ,
"Generate general Gate class instance of CZ.\n\n.. note:: CZ is a specialization of Z.");
mgate.def(
"CCX",
&gate::CCX,
"Generate general Gate class instance of CXX.\n\n.. note:: CX is a specialization of X.");
mgate.def(
"CCNot",
&gate::CCX,
"Generate general Gate class instance of CCNot.\n\n.. note:: CCNot is an alias of CCX.");
mgate.def("Toffoli",
&gate::CCX,
"Generate general Gate class instance of Toffoli.\n\n.. note:: Toffoli is an alias "
"of CCX.");
mgate.def("OneTargetMatrix",
&gate::OneTargetMatrix,
"Generate general Gate class instance of OneTargetMatrix.",
"target"_a,
"matrix"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("TwoTargetMatrix",
&gate::TwoTargetMatrix,
"Generate general Gate class instance of TwoTargetMatrix.",
"target1"_a,
"target2"_a,
"matrix"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("DenseMatrix",
&gate::DenseMatrix,
"Generate general Gate class instance of DenseMatrix. IGate, OneTargetMatrixGate or "
"TwoTargetMatrixGate correspond to len(target) is created. The case len(target) >= 3 "
"is currently not supported.",
"targets"_a,
"matrix"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("Pauli",
&gate::Pauli,
"Generate general Gate class instance of Pauli.",
"pauli"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("PauliRotation",
&gate::PauliRotation,
"Generate general Gate class instance of PauliRotation.",
"pauli"_a,
"angle"_a,
"controls"_a = std::vector<std::uint64_t>{});
mgate.def("Probablistic",
&gate::Probablistic,
"Generate general Gate class instance of Probablistic.",
"distribution"_a,
"gate_list"_a);
}
} // namespace internal
#endif
} // namespace scaluq
Loading

0 comments on commit e7f133a

Please sign in to comment.