Skip to content

Commit

Permalink
[WIP] Precision mode
Browse files Browse the repository at this point in the history
  • Loading branch information
KowerKoint authored and KowerKoint committed Jan 17, 2025
1 parent ec8a171 commit fc3c30f
Show file tree
Hide file tree
Showing 14 changed files with 609 additions and 1,394 deletions.
85 changes: 41 additions & 44 deletions include/scaluq/circuit/circuit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@

namespace scaluq {

template <FloatingPoint Fp>
template <Precision Prec>
class Circuit {
public:
using GateWithKey = std::variant<Gate<Fp>, std::pair<ParamGate<Fp>, std::string>>;
using GateWithKey = std::variant<Gate<Prec>, std::pair<ParamGate<Prec>, std::string>>;
Circuit() = default;
explicit Circuit(std::uint64_t n_qubits) : _n_qubits(n_qubits) {}

Expand All @@ -38,20 +38,20 @@ class Circuit {

[[nodiscard]] std::uint64_t calculate_depth() const;

void add_gate(const Gate<Fp>& gate) {
void add_gate(const Gate<Prec>& gate) {
check_gate_is_valid(gate);
_gate_list.push_back(gate);
}
void add_param_gate(const ParamGate<Fp>& param_gate, std::string_view parameter_key) {
void add_param_gate(const ParamGate<Prec>& param_gate, std::string_view parameter_key) {
check_gate_is_valid(param_gate);
_gate_list.push_back(std::make_pair(param_gate, std::string(parameter_key)));
}

void add_circuit(const Circuit<Fp>& circuit);
void add_circuit(Circuit<Fp>&& circuit);
void add_circuit(const Circuit<Prec>& circuit);
void add_circuit(Circuit<Prec>&& circuit);

void update_quantum_state(StateVector<Fp>& state,
const std::map<std::string, Fp>& parameters = {}) const;
void update_quantum_state(StateVector<Prec>& state,
const std::map<std::string, double>& parameters = {}) const;

Circuit copy() const;

Expand All @@ -73,10 +73,10 @@ class Circuit {
const Json& tmp_list = j.at("gate_list");
for (const Json& gate_with_key : tmp_list) {
if (gate_with_key.contains("key")) {
circuit.add_param_gate(gate_with_key.at("gate").get<ParamGate<Fp>>(),
circuit.add_param_gate(gate_with_key.at("gate").get<ParamGate<Prec>>(),
gate_with_key.at("key").get<std::string>());
} else {
circuit.add_gate(gate_with_key.at("gate").get<Gate<Fp>>());
circuit.add_gate(gate_with_key.at("gate").get<Gate<Prec>>());
}
}
}
Expand All @@ -86,71 +86,68 @@ class Circuit {

std::vector<GateWithKey> _gate_list;

void check_gate_is_valid(const Gate<Fp>& gate) const;
void check_gate_is_valid(const Gate<Prec>& gate) const;

void check_gate_is_valid(const ParamGate<Fp>& gate) const;
void check_gate_is_valid(const ParamGate<Prec>& gate) const;
};

#ifdef SCALUQ_USE_NANOBIND
namespace internal {
template <FloatingPoint Fp>
template <Precision Prec>
void bind_circuit_circuit_hpp(nb::module_& m) {
nb::class_<Circuit<Fp>>(m, "Circuit", "Quantum circuit represented as gate array")
nb::class_<Circuit<Prec>>(m, "Circuit", "Quantum circuit represented as gate array")
.def(nb::init<std::uint64_t>(), "Initialize empty circuit of specified qubits.")
.def("n_qubits", &Circuit<Fp>::n_qubits, "Get property of `n_qubits`.")
.def("n_qubits", &Circuit<Prec>::n_qubits, "Get property of `n_qubits`.")
.def("gate_list",
&Circuit<Fp>::gate_list,
&Circuit<Prec>::gate_list,
"Get property of `gate_list`.",
nb::rv_policy::reference)
.def("n_gates", &Circuit<Fp>::n_gates, "Get property of `n_gates`.")
.def("key_set", &Circuit<Fp>::key_set, "Get set of keys of parameters.")
.def("get_gate_at", &Circuit<Fp>::get_gate_at, "Get reference of i-th gate.")
.def("n_gates", &Circuit<Prec>::n_gates, "Get property of `n_gates`.")
.def("key_set", &Circuit<Prec>::key_set, "Get set of keys of parameters.")
.def("get_gate_at", &Circuit<Prec>::get_gate_at, "Get reference of i-th gate.")
.def("get_param_key_at",
&Circuit<Fp>::get_param_key_at,
&Circuit<Prec>::get_param_key_at,
"Get parameter key of i-th gate. If it is not parametric, return None.")
.def("calculate_depth", &Circuit<Fp>::calculate_depth, "Get depth of circuit.")
.def("calculate_depth", &Circuit<Prec>::calculate_depth, "Get depth of circuit.")
.def("add_gate",
nb::overload_cast<const Gate<Fp>&>(&Circuit<Fp>::add_gate),
nb::overload_cast<const Gate<Prec>&>(&Circuit<Prec>::add_gate),
"Add gate. Given gate is copied.")
.def(
"add_param_gate",
nb::overload_cast<const ParamGate<Fp>&, std::string_view>(&Circuit<Fp>::add_param_gate),
"Add parametric gate with specifing key. Given param_gate is copied.")
.def("add_param_gate",
nb::overload_cast<const ParamGate<Prec>&, std::string_view>(
&Circuit<Prec>::add_param_gate),
"Add parametric gate with specifing key. Given param_gate is copied.")
.def("add_circuit",
nb::overload_cast<const Circuit<Fp>&>(&Circuit<Fp>::add_circuit),
nb::overload_cast<const Circuit<Prec>&>(&Circuit<Prec>::add_circuit),
"Add all gates in specified circuit. Given gates are copied.")
.def("update_quantum_state",
&Circuit<Fp>::update_quantum_state,
&Circuit<Prec>::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.")
"dict[str, float] in 2nd arg.", )
.def(
"update_quantum_state",
[&](const Circuit<Fp>& circuit, StateVector<Fp>& state, nb::kwargs kwargs) {
std::map<std::string, Fp> parameters;
for (auto&& [key, param] : kwargs) {
parameters[nb::cast<std::string>(key)] = nb::cast<Fp>(param);
}
circuit.update_quantum_state(state, parameters);
},
&Circuit < Prec nb::overload_cast <
[&](const Circuit<Prec>& circuit, StateVector<Prec>& 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<Fp>& circuit, StateVector<Fp>& state) {
circuit.update_quantum_state(state);
})
.def("copy", &Circuit<Fp>::copy, "Copy circuit. All the gates inside is copied.")
.def("copy", &Circuit<Prec>::copy, "Copy circuit. All the gates inside is copied.")
.def("get_inverse",
&Circuit<Fp>::get_inverse,
&Circuit<Prec>::get_inverse,
"Get inverse of circuit. All the gates are newly created.")
.def(
"to_json",
[](const Circuit<Fp>& circuit) { return Json(circuit).dump(); },
[](const Circuit<Prec>& circuit) { return Json(circuit).dump(); },
"Information as json style.")
.def(
"load_json",
[](Circuit<Fp>& circuit, const std::string& str) {
[](Circuit<Prec>& circuit, const std::string& str) {
circuit = nlohmann::json::parse(str);
},
"Read an object from the JSON representation of the circuit.");
Expand Down
124 changes: 60 additions & 64 deletions include/scaluq/constant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,23 @@ KOKKOS_INLINE_FUNCTION
constexpr double SINPI8() { return 0.382683432365090; }

//! identity matrix
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> I_GATE() {
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> I_GATE() {
return {1, 0, 0, 1};
}
//! Pauli matrix X
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> X_GATE() {
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> X_GATE() {
return {0, 1, 1, 0};
}
//! Pauli matrix Y
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> Y_GATE() {
return {0, Complex<Fp>(0, -1), Complex<Fp>(0, 1), 0};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> Y_GATE() {
return {0, Complex<Prec>(0, -1), Complex<Prec>(0, 1), 0};
}
//! Pauli matrix Z
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> Z_GATE() {
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> Z_GATE() {
return {1, 0, 0, -1};
}

Expand All @@ -47,86 +47,82 @@ KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> Z_GATE() {
// Y_GATE, Z_GATE};

//! S-gate
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> S_GATE_MATRIX() {
return {1, 0, 0, Complex<Fp>(0, 1)};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> S_GATE_MATRIX() {
return {1, 0, 0, Complex<Prec>(0, 1)};
}
//! Sdag-gate
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> S_DAG_GATE_MATRIX() {
return {1, 0, 0, Complex<Fp>(0, -1)};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> S_DAG_GATE_MATRIX() {
return {1, 0, 0, Complex<Prec>(0, -1)};
}
//! T-gate
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> T_GATE_MATRIX() {
return {1, 0, 0, Complex<Fp>(INVERSE_SQRT2(), INVERSE_SQRT2())};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> T_GATE_MATRIX() {
return {1, 0, 0, Complex<Prec>(INVERSE_SQRT2(), INVERSE_SQRT2())};
}
//! Tdag-gate
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> T_DAG_GATE_MATRIX() {
return {1, 0, 0, Complex<Fp>(INVERSE_SQRT2(), -INVERSE_SQRT2())};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> T_DAG_GATE_MATRIX() {
return {1, 0, 0, Complex<Prec>(INVERSE_SQRT2(), -INVERSE_SQRT2())};
}
//! Hadamard gate
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> HADAMARD_MATRIX() {
Fp ISQRT2 = static_cast<Fp>(INVERSE_SQRT2());
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> HADAMARD_MATRIX() {
Float<Prec> ISQRT2 = static_cast<Float<Prec>>(INVERSE_SQRT2());
return {ISQRT2, ISQRT2, ISQRT2, -ISQRT2};
}
//! square root of X gate
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> SQRT_X_GATE_MATRIX() {
Fp HALF = static_cast<Fp>(0.5);
return {Complex<Fp>(HALF, HALF),
Complex<Fp>(HALF, -HALF),
Complex<Fp>(HALF, -HALF),
Complex<Fp>(HALF, HALF)};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> SQRT_X_GATE_MATRIX() {
return {Complex<Prec>(.5, .5),
Complex<Prec>(.5, -.5),
Complex<Prec>(.5, -.5),
Complex<Prec>(.5, .5)};
}
//! square root of Y gate
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> SQRT_Y_GATE_MATRIX() {
Fp HALF = static_cast<Fp>(0.5);
return {Complex<Fp>(HALF, HALF),
Complex<Fp>(-HALF, -HALF),
Complex<Fp>(HALF, HALF),
Complex<Fp>(HALF, HALF)};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> SQRT_Y_GATE_MATRIX() {
return {Complex<Prec>(.5, .5),
Complex<Prec>(-.5, -.5),
Complex<Prec>(.5, .5),
Complex<Prec>(.5, .5)};
}
//! square root dagger of X gate
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> SQRT_X_DAG_GATE_MATRIX() {
Fp HALF = static_cast<Fp>(0.5);
return {Complex<Fp>(HALF, -HALF),
Complex<Fp>(HALF, HALF),
Complex<Fp>(HALF, HALF),
Complex<Fp>(HALF, -HALF)};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> SQRT_X_DAG_GATE_MATRIX() {
return {Complex<Prec>(.5, -.5),
Complex<Prec>(.5, .5),
Complex<Prec>(.5, .5),
Complex<Prec>(.5, -.5)};
}
//! square root dagger of Y gate
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> SQRT_Y_DAG_GATE_MATRIX() {
Fp HALF = static_cast<Fp>(0.5);
return {Complex<Fp>(HALF, -HALF),
Complex<Fp>(HALF, -HALF),
Complex<Fp>(-HALF, HALF),
Complex<Fp>(HALF, -HALF)};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> SQRT_Y_DAG_GATE_MATRIX() {
return {Complex<Prec>(.5, -.5),
Complex<Prec>(.5, -.5),
Complex<Prec>(-.5, .5),
Complex<Prec>(.5, -.5)};
}
//! Projection to 0
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> PROJ_0_MATRIX() {
return {Fp{1}, Fp{0}, Fp{0}, Fp{0}};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> PROJ_0_MATRIX() {
return {1, 0, 0, 0};
}
//! Projection to 1
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Matrix2x2<Fp> PROJ_1_MATRIX() {
return {Fp{0}, Fp{0}, Fp{0}, Fp{1}};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Matrix2x2<Prec> PROJ_1_MATRIX() {
return {0, 0, 0, 1};
}
//! complex values for exp(j * i*pi/4 )
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Kokkos::Array<Complex<Fp>, 4> PHASE_90ROT() {
return {Fp{1}, Complex<Fp>(0, 1), Fp{-1}, Complex<Fp>(0, -1)};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Kokkos::Array<Complex<Prec>, 4> PHASE_90ROT() {
return {1, Complex<Prec>(0, 1), -1, Complex<Prec>(0, -1)};
}
//! complex values for exp(-j * i*pi/4 )
template <FloatingPoint Fp>
KOKKOS_INLINE_FUNCTION Kokkos::Array<Complex<Fp>, 4> PHASE_M90ROT() {
return {Fp{1}, Complex<Fp>(0, -1), Fp{-1}, Complex<Fp>(0, 1)};
template <Precision Prec>
KOKKOS_INLINE_FUNCTION Kokkos::Array<Complex<Prec>, 4> PHASE_M90ROT() {
return {1, Complex<Prec>(0, -1), -1, Complex<Prec>(0, 1)};
}
} // namespace internal
} // namespace scaluq
Loading

0 comments on commit fc3c30f

Please sign in to comment.