From f96fd114f1da9750f309f8cc24d196f828cdf9bd Mon Sep 17 00:00:00 2001 From: Glacialte Date: Fri, 10 Jan 2025 11:19:50 +0900 Subject: [PATCH 01/13] add docstring for gate_factory, richer docstring for state_vector_batched --- include/scaluq/gate/gate_factory.hpp | 558 ++++++++++++++---- include/scaluq/state/state_vector_batched.hpp | 279 +++++++-- 2 files changed, 686 insertions(+), 151 deletions(-) diff --git a/include/scaluq/gate/gate_factory.hpp b/include/scaluq/gate/gate_factory.hpp index 5fb7904..aee21d0 100644 --- a/include/scaluq/gate/gate_factory.hpp +++ b/include/scaluq/gate/gate_factory.hpp @@ -238,179 +238,535 @@ inline Gate Probablistic(const std::vector& distribution, namespace internal { template 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{}); - mgate.def("X", - &gate::X, - "Generate general Gate class instance of X.", - "target"_a, - "controls"_a = std::vector{}); - mgate.def("Y", - &gate::Y, - "Generate general Gate class instance of Y.", - "taget"_a, - "controls"_a = std::vector{}); - mgate.def("Z", - &gate::Z, - "Generate general Gate class instance of Z.", - "target"_a, - "controls"_a = std::vector{}); - mgate.def("H", - &gate::H, - "Generate general Gate class instance of H.", - "target"_a, - "controls"_a = std::vector{}); - mgate.def("S", - &gate::S, - "Generate general Gate class instance of S.", - "target"_a, - "controls"_a = std::vector{}); + mgate.def("I", + &gate::I, + DocString() + .desc("Generate identity gate.") + .ret("Gate", "Identity gate instance") + .ex(DocString::Code({">>> gate = I()", ">>> print(gate)", "Identity Gate"})) + .build_as_google_style() + .c_str()); + mgate.def( + "GlobalPhase", + &gate::GlobalPhase, + "phase"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate global phase gate.") + .arg("phase", "float", "Global phase angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "Global phase gate instance") + .ex(DocString::Code( + {">>> gate = GlobalPhase(math.pi/2)", ">>> print(gate)", "Global Phase Gate"})) + .build_as_google_style() + .c_str()); + mgate.def( + "X", + &gate::X, + "target"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate Pauli-X (NOT) gate.") + .desc("Performs bit flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "Pauli-X gate instance") + .ex(DocString::Code({">>> gate = X(0) # X gate on qubit 0", + ">>> gate = X(1, [0]) # Controlled-X with control on qubit 0"})) + .build_as_google_style() + .c_str()); + mgate.def( + "Y", + &gate::Y, + "taget"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate Pauli-Y gate.") + .desc("Performs bit flip and phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "Pauli-Y gate instance") + .ex(DocString::Code({">>> gate = Y(0) # Y gate on qubit 0", + ">>> gate = Y(1, [0]) # Controlled-Y with control on qubit 0"})) + .build_as_google_style() + .c_str()); + mgate.def( + "Z", + &gate::Z, + "target"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate Pauli-Z gate.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "Pauli-Z gate instance") + .ex(DocString::Code({">>> gate = Z(0) # Z gate on qubit 0", + ">>> gate = Z(1, [0]) # Controlled-Z with control on qubit 0"})) + .build_as_google_style() + .c_str()); + mgate.def( + "H", + &gate::H, + "target"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate Hadamard gate.") + .desc("Performs superposition operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "Hadamard gate instance") + .ex(DocString::Code({">>> gate = H(0) # H gate on qubit 0", + ">>> gate = H(1, [0]) # Controlled-H with control on qubit 0"})) + .build_as_google_style() + .c_str()); + mgate.def( + "S", + &gate::S, + "target"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of S.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "S gate instance") + .ex(DocString::Code({">>> gate = S(0) # S gate on qubit 0", + ">>> gate = S(1, [0]) # Controlled-S with control on qubit 0"})) + .build_as_google_style() + .c_str()); mgate.def("Sdag", &gate::Sdag, - "Generate general Gate class instance of Sdag.", - "target"_a, - "controls"_a = std::vector{}); - mgate.def("T", - &gate::T, - "Generate general Gate class instance of T.", "target"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of Sdag.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "Sdag gate instance") + .ex(DocString::Code( + {">>> gate = Sdag(0) # Sdag gate on qubit 0", + ">>> gate = Sdag(1, [0]) # Controlled-Sdag with control on qubit 0"})) + .build_as_google_style() + .c_str()); + mgate.def( + "T", + &gate::T, + "target"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of T.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "T gate instance") + .ex(DocString::Code({">>> gate = T(0) # T gate on qubit 0", + ">>> gate = T(1, [0]) # Controlled-T with control on qubit 0"})) + .build_as_google_style() + .c_str()); mgate.def("Tdag", &gate::Tdag, - "Generate general Gate class instance of Tdag.", "target"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of Tdag.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "Tdag gate instance") + .ex(DocString::Code( + {">>> gate = Tdag(0) # Tdag gate on qubit 0", + ">>> gate = Tdag(1, [0]) # Controlled-Tdag with control on qubit 0"})) + .build_as_google_style() + .c_str()); mgate.def("SqrtX", &gate::SqrtX, - "Generate general Gate class instance of SqrtX.", "target"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of SqrtX.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "SqrtX gate instance") + .ex(DocString::Code({">>> gate = SqrtX(0) # SqrtX gate on qubit 0", + ">>> gate = SqrtX(1, [0]) # Controlled-SqrtX"})) + .build_as_google_style() + .c_str()); mgate.def("SqrtXdag", &gate::SqrtXdag, - "Generate general Gate class instance of SqrtXdag.", "target"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of SqrtXdag.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "SqrtXdag gate instance") + .ex(DocString::Code({">>> gate = SqrtXdag(0) # SqrtXdag gate on qubit 0", + ">>> gate = SqrtXdag(1, [0]) # Controlled-SqrtXdag"})) + .build_as_google_style() + .c_str()); mgate.def("SqrtY", &gate::SqrtY, - "Generate general Gate class instance of SqrtY.", "target"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of SqrtY.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "SqrtY gate instance") + .ex(DocString::Code({">>> gate = SqrtY(0) # SqrtY gate on qubit 0", + ">>> gate = SqrtY(1, [0]) # Controlled-SqrtY"})) + .build_as_google_style() + .c_str()); mgate.def("SqrtYdag", &gate::SqrtYdag, - "Generate general Gate class instance of SqrtYdag.", "target"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of SqrtYdag.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "SqrtYdag gate instance") + .ex(DocString::Code({">>> gate = SqrtYdag(0) # SqrtYdag gate on qubit 0", + ">>> gate = SqrtYdag(1, [0]) # Controlled-SqrtYdag"})) + .build_as_google_style() + .c_str()); mgate.def("P0", &gate::P0, - "Generate general Gate class instance of P0.", "target"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of P0.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "P0 gate instance") + .ex(DocString::Code({">>> gate = P0(0) # P0 gate on qubit 0", + ">>> gate = P0(1, [0]) # Controlled-P0"})) + .build_as_google_style() + .c_str()); mgate.def("P1", &gate::P1, - "Generate general Gate class instance of P1.", "target"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of P1.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "P1 gate instance") + .ex(DocString::Code({">>> gate = P1(0) # P1 gate on qubit 0", + ">>> gate = P1(1, [0]) # Controlled-P1"})) + .build_as_google_style() + .c_str()); mgate.def("RX", &gate::RX, - "Generate general Gate class instance of RX.", "target"_a, "angle"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate rotation gate around X-axis.") + .desc("Rotation angle is specified in radians.") + .arg("target", "int", "Target qubit index") + .arg("angle", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "RX gate instance") + .ex(DocString::Code({">>> gate = RX(0, math.pi/2) # π/2 rotation around X-axis", + ">>> gate = RX(1, math.pi, [0]) # Controlled-RX"})) + .build_as_google_style() + .c_str()); mgate.def("RY", &gate::RY, - "Generate general Gate class instance of RY.", "target"_a, "angle"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate rotation gate around Y-axis.") + .desc("Rotation angle is specified in radians.") + .arg("target", "int", "Target qubit index") + .arg("angle", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "RY gate instance") + .ex(DocString::Code({">>> gate = RY(0, math.pi/2) # π/2 rotation around Y-axis", + ">>> gate = RY(1, math.pi, [0]) # Controlled-RY"})) + .build_as_google_style() + .c_str()); mgate.def("RZ", &gate::RZ, - "Generate general Gate class instance of RZ.", "target"_a, "angle"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate rotation gate around Z-axis.") + .desc("Rotation angle is specified in radians.") + .arg("target", "int", "Target qubit index") + .arg("angle", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "RZ gate instance") + .ex(DocString::Code({">>> gate = RZ(0, math.pi/2) # π/2 rotation around Z-axis", + ">>> gate = RZ(1, math.pi, [0]) # Controlled-RZ"})) + .build_as_google_style() + .c_str()); mgate.def("U1", &gate::U1, - "Generate general Gate class instance of U1.", "target"_a, "lambda_"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of U1.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("lambda_", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "U1 gate instance") + .ex(DocString::Code({">>> gate = U1(0, math.pi/2) # π/2 rotation around Z-axis", + ">>> gate = U1(1, math.pi, [0]) # Controlled-U1"})) + .build_as_google_style() + .c_str()); mgate.def("U2", &gate::U2, - "Generate general Gate class instance of U2.", - "target"_a, - "phi"_a, - "lambda_"_a, - "controls"_a = std::vector{}); - mgate.def("U3", - &gate::U3, - "Generate general Gate class instance of U3.", "target"_a, - "theta"_a, "phi"_a, "lambda_"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of U2.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("phi", "float", "Rotation angle in radians") + .arg("lambda_", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "U2 gate instance") + .ex(DocString::Code( + {">>> gate = U2(0, math.pi/2, math.pi) # π/2 rotation around Z-axis", + ">>> gate = U2(1, math.pi, math.pi/2, [0]) # Controlled-U2"})) + .build_as_google_style() + .c_str()); + mgate.def( + "U3", + &gate::U3, + "target"_a, + "theta"_a, + "phi"_a, + "lambda_"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of U3.") + .desc("Performs phase flip operation.") + .arg("target", "int", "Target qubit index") + .arg("theta", "float", "Rotation angle in radians") + .arg("phi", "float", "Rotation angle in radians") + .arg("lambda_", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "U3 gate instance") + .ex(DocString::Code( + {">>> gate = U3(0, math.pi/2, math.pi, math.pi) # π/2 rotation around Z-axis", + ">>> gate = U3(1, math.pi, math.pi/2, math.pi, [0]) # Controlled-U3"})) + .build_as_google_style() + .c_str()); mgate.def("Swap", &gate::Swap, - "Generate general Gate class instance of Swap.", "target1"_a, "target2"_a, - "controls"_a = std::vector{}); - mgate.def( - "CX", - &gate::CX, - "Generate general Gate class instance of CX.\n\n.. note:: CX is a specialization of X."); - mgate.def("CNot", + "controls"_a = std::vector{}, + DocString() + .desc("Generate SWAP gate.") + .desc("Swaps the states of two qubits.") + .arg("target1", "int", "First target qubit index") + .arg("target2", "int", "Second target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "SWAP gate instance") + .ex(DocString::Code({">>> gate = Swap(0, 1) # Swap qubits 0 and 1", + ">>> gate = Swap(1, 2, [0]) # Controlled-SWAP"})) + .build_as_google_style() + .c_str()); + mgate.def("CX", &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."); + "control"_a, + "target"_a, + DocString() + .desc("Generate general Gate class instance of CX.") + .desc("Performs controlled-X operation.") + .arg("control", "int", "Control qubit index") + .arg("target", "int", "Target qubit index") + .ret("Gate", "CX gate instance") + .ex(DocString::Code({">>> gate = CX(0, 1) # CX gate with control on qubit 0", + ">>> gate = CX(1, 2) # CX gate with control on qubit 1"})) + .build_as_google_style() + .c_str()); mgate.def( - "CCX", - &gate::CCX, - "Generate general Gate class instance of CXX.\n\n.. note:: CX is a specialization of X."); + "CNot", + &gate::CX, + "control"_a, + "target"_a, + DocString() + .desc("Generate general Gate class instance of CNot.") + .desc("Performs controlled-X operation.") + .arg("control", "int", "Control qubit index") + .arg("target", "int", "Target qubit index") + .ret("Gate", "CNot gate instance") + .ex(DocString::Code({">>> gate = CNot(0, 1) # CNot gate with control on qubit 0", + ">>> gate = CNot(1, 2) # CNot gate with control on qubit 1"})) + .build_as_google_style() + .c_str()); + mgate.def("CZ", + &gate::CZ, + "control"_a, + "target"_a, + DocString() + .desc("Generate general Gate class instance of CZ.") + .desc("Performs controlled-Z operation.") + .arg("control", "int", "Control qubit index") + .arg("target", "int", "Target qubit index") + .ret("Gate", "CZ gate instance") + .ex(DocString::Code({">>> gate = CZ(0, 1) # CZ gate with control on qubit 0", + ">>> gate = CZ(1, 2) # CZ gate with control on qubit 1"})) + .build_as_google_style() + .c_str()); + mgate.def("CCX", + &gate::CCX, + "control1"_a, + "control2"_a, + "target"_a, + DocString() + .desc("Generate general Gate class instance of CCX.") + .desc("Performs controlled-controlled-X operation.") + .arg("control1", "int", "First control qubit index") + .arg("control2", "int", "Second control qubit index") + .arg("target", "int", "Target qubit index") + .ret("Gate", "CCX gate instance") + .ex(DocString::Code( + {">>> gate = CCX(0, 1, 2) # CCX gate with controls on qubits 0 and 1", + ">>> gate = CCX(1, 2, 3) # CCX gate with controls on qubits 1 and 2"})) + .build_as_google_style() + .c_str()); + mgate.def("CCNot", + &gate::CCX, + "control1"_a, + "control2"_a, + "target"_a, + DocString() + .desc("Generate general Gate class instance of CCNot.") + .desc("Performs controlled-controlled-X operation.") + .arg("control1", "int", "First control qubit index") + .arg("control2", "int", "Second control qubit index") + .arg("target", "int", "Target qubit index") + .ret("Gate", "CCNot gate instance") + .ex(DocString::Code( + {">>> gate = CCNot(0, 1, 2) # CCNot gate with controls on qubits 0 and 1", + ">>> gate = CCNot(1, 2, 3) # CCNot gate with controls on qubits 1 and 2"})) + .build_as_google_style() + .c_str()); mgate.def( - "CCNot", + "Toffoli", &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."); + "control1"_a, + "control2"_a, + "target"_a, + DocString() + .desc("Toffoli is an alias of CCX.") + .desc("Generate general Gate class instance of Toffoli.") + .desc("Performs controlled-controlled-X operation.") + .arg("control1", "int", "First control qubit index") + .arg("control2", "int", "Second control qubit index") + .arg("target", "int", "Target qubit index") + .ret("Gate", "Toffoli gate instance") + .ex(DocString::Code( + {">>> gate = Toffoli(0, 1, 2) # Toffoli gate with controls on qubits 0 and 1", + ">>> gate = Toffoli(1, 2, 3) # Toffoli gate with controls on qubits 1 and 2"})) + .build_as_google_style() + .c_str()); mgate.def("DenseMatrix", &gate::DenseMatrix, - "Generate general Gate class instance of DenseMatrix.", "targets"_a, "matrix"_a, "controls"_a = std::vector{}, - "is_unitary"_a = false); + "is_unitary"_a = false, + DocString() + .desc("Generate general Gate class instance of DenseMatrix.") + .desc("Performs dense matrix operation.") + .arg("targets", "list[int]", "Target qubit indices") + .arg("matrix", "numpy.ndarray", "Matrix to be applied") + .arg("controls", "list[int]", true, "Control qubit indices") + .arg("is_unitary", "bool", true, "Whether the matrix is unitary") + .ret("Gate", "DenseMatrix gate instance") + .ex(DocString::Code( + {">>> matrix = np.array([[1, 0], [0, 1]])", + ">>> gate = DenseMatrix([0], matrix)", + ">>> gate = DenseMatrix([0], matrix, [1]) # Controlled-DenseMatrix"})) + .build_as_google_style() + .c_str()); mgate.def("SparseMatrix", &gate::SparseMatrix, - "Generate general Gate class instance of SparseMatrix.", "targets"_a, "matrix"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of SparseMatrix.") + .desc("Performs sparse matrix operation.") + .arg("targets", "list[int]", "Target qubit indices") + .arg("matrix", "scipy.sparse.csr_matrix", "Matrix to be applied") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "SparseMatrix gate instance") + .ex(DocString::Code( + {">>> matrix = scipy.sparse.csr_matrix([[1, 0], [0, 1]])", + ">>> gate = SparseMatrix([0], matrix)", + ">>> gate = SparseMatrix([0], matrix, [1]) # Controlled-SparseMatrix"})) + .build_as_google_style() + .c_str()); mgate.def("Pauli", &gate::Pauli, - "Generate general Gate class instance of Pauli.", "pauli"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of Pauli.") + .desc("Performs Pauli operation.") + .arg("pauli", "PauliOperator", "Pauli operator") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "Pauli gate instance") + .ex(DocString::Code({">>> pauli = PauliOperator('X', 0)", + ">>> gate = Pauli(pauli)", + ">>> gate = Pauli(pauli, [1]) # Controlled-Pauli"})) + .build_as_google_style() + .c_str()); mgate.def("PauliRotation", &gate::PauliRotation, - "Generate general Gate class instance of PauliRotation.", "pauli"_a, "angle"_a, - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general Gate class instance of PauliRotation.") + .desc("Performs Pauli rotation operation.") + .arg("pauli", "PauliOperator", "Pauli operator") + .arg("angle", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "PauliRotation gate instance") + .ex(DocString::Code( + {">>> pauli = PauliOperator('X', 0)", + ">>> gate = PauliRotation(pauli, math.pi/2)", + ">>> gate = PauliRotation(pauli, math.pi/2, [1]) # Controlled-Pauli"})) + .build_as_google_style() + .c_str()); mgate.def("Probablistic", &gate::Probablistic, - "Generate general Gate class instance of Probablistic.", "distribution"_a, - "gate_list"_a); + "gate_list"_a, + DocString() + .desc("Generate general Gate class instance of Probablistic.") + .desc("Performs probablistic operation.") + .arg("distribution", "list[float]", "Probablistic distribution") + .arg("gate_list", "list[Gate]", "List of gates") + .ret("Gate", "Probablistic gate instance") + .ex(DocString::Code({">>> distribution = [0.5, 0.5]", + ">>> gate_list = [X(0), Y(0)]", + ">>> gate = Probablistic(distribution, gate_list)"})) + .build_as_google_style() + .c_str()); } } // namespace internal #endif diff --git a/include/scaluq/state/state_vector_batched.hpp b/include/scaluq/state/state_vector_batched.hpp index d5a34b0..4c71b01 100644 --- a/include/scaluq/state/state_vector_batched.hpp +++ b/include/scaluq/state/state_vector_batched.hpp @@ -123,48 +123,132 @@ void bind_state_state_vector_batched_hpp(nb::module_& m) { nb::class_>( m, "StateVectorBatched", - "Batched vector representation of quantum state.\n\n.. note:: Qubit index is start from 0. " - "If the amplitudes of $\\ket{b_{n-1}\\dots b_0}$ is $b_i$, the state is $\\sum_i b_i " - "2^i$.") + DocString() + .desc("Batched vector representation of quantum state.") + .desc("Qubit index starts from 0. If the amplitudes of $\\ket{b_{n-1}\\dots b_0}$ " + "are $b_i$, the state is $\\sum_i b_i 2^i$.") + .build_as_google_style() + .c_str()) + // Constructor: batch size and number of qubits .def(nb::init(), - "Construct batched state vector with specified batch size and qubits.") + "batch_size"_a, + "n_qubits"_a, + DocString() + .desc("Construct batched state vector with specified batch size and qubits.") + .arg("batch_size", "int", "Number of batches.") + .arg("n_qubits", "int", "Number of qubits in each state vector.") + .ex(DocString::Code({">>> states = StateVectorBatched(3, 2)", + ">>> print(states)", + " *** Quantum States ***", + " * Qubit Count : 2", + " * Dimension : 4", + "--------------------", + " * Batch_id : 0", + " * State vector : ", + " 00 : (1,0)\n 01 : (0,0)\n 10 : (0,0)\n 11 : (0,0)", + "--------------------", + " * Batch_id : 1", + " * State vector : ", + " 00 : (1,0)\n 01 : (0,0)\n 10 : (0,0)\n 11 : (0,0)"})) + .build_as_google_style() + .c_str()) + // Constructor: Copy constructor .def(nb::init&>(), - "Constructing batched state vector by copying other batched state.") - .def("n_qubits", &StateVectorBatched::n_qubits, "Get num of qubits.") + "other"_a, + DocString() + .desc("Construct a batched state vector by copying another batched state.") + .arg("other", "StateVectorBatched", "The batched state vector to copy.") + .build_as_google_style() + .c_str()) + // Basic getters + .def("n_qubits", + &StateVectorBatched::n_qubits, + DocString() + .desc("Get the number of qubits in each state vector.") + .ret("int", "The number of qubits.") + .build_as_google_style() + .c_str()) .def("dim", &StateVectorBatched::dim, - "Get dimension of the vector ($=2^\\mathrm{n\\_qubits}$).") - .def("batch_size", &StateVectorBatched::batch_size, "Get batch size.") + DocString() + .desc("Get the dimension of each state vector (=$2^{\\mathrm{n\\_qubits}}$).") + .ret("int", "The dimension of the vector.") + .build_as_google_style() + .c_str()) + .def("batch_size", + &StateVectorBatched::batch_size, + DocString() + .desc("Get the batch size (number of state vectors).") + .ret("int", "The batch size.") + .build_as_google_style() + .c_str()) + // State manipulation methods .def("set_state_vector", - nb::overload_cast&>(&StateVectorBatched::set_state_vector), - "Set the state vector for all batches.") + &StateVectorBatched::set_state_vector, + "state"_a, + DocString() + .desc("Set all state vectors in the batch to the given state.") + .arg("state", "StateVector", "State to set for all batches.") + .build_as_google_style() + .c_str()) .def("set_state_vector_at", - nb::overload_cast&>( - &StateVectorBatched::set_state_vector_at), - "Set the state vector for a specific batch.") + &StateVectorBatched::set_state_vector_at, + "batch_id"_a, + "state"_a, + DocString() + .desc("Set the state vector at a specific batch index.") + .arg("batch_id", "int", "Index in batch to set.") + .arg("state", "StateVector", "State to set at the specified index.") + .build_as_google_style() + .c_str()) .def("get_state_vector_at", &StateVectorBatched::get_state_vector_at, - "Get the state vector for a specific batch.") + "batch_id"_a, + DocString() + .desc("Get the state vector at a specific batch index.") + .arg("batch_id", "int", "Index in batch to get.") + .ret("StateVector", "The state vector at the specified batch index.") + .build_as_google_style() + .c_str()) + // State initialization methods .def("set_zero_state", &StateVectorBatched::set_zero_state, - "Initialize all batches with computational basis $\\ket{00\\dots0}$.") - .def("set_zero_norm_state", - &StateVectorBatched::set_zero_norm_state, - "Initialize with 0 (null vector).") + DocString().desc("Initialize all states to |0...0⟩.").build_as_google_style().c_str()) .def("set_computational_basis", &StateVectorBatched::set_computational_basis, - "Initialize with computational basis \\ket{\\mathrm{basis}}.") + "basis"_a, + DocString() + .desc("Set all states to the specified computational basis state.") + .arg("basis", "int", "Index of the computational basis state.") + .build_as_google_style() + .c_str()) + .def("set_zero_norm_state", + &StateVectorBatched::set_zero_norm_state, + DocString().desc("Set all amplitudes to zero.").build_as_google_style().c_str()) + // Haar random state methods .def( - "sampling", - [](const StateVectorBatched& states, - std::uint64_t sampling_count, + "set_Haar_random_state", + [](StateVectorBatched& states, + std::uint64_t batch_size, + std::uint64_t n_qubits, + bool set_same_state, std::optional seed) { - return states.sampling(sampling_count, seed.value_or(std::random_device{}())); + states.set_Haar_random_state( + batch_size, n_qubits, set_same_state, seed.value_or(std::random_device()())); }, - "sampling_count"_a, + "batch_size"_a, + "n_qubits"_a, + "set_same_state"_a, "seed"_a = std::nullopt, - "Sampling specified times. Result is `list[list[int]]` with the `sampling_count` " - "length.") + DocString() + .desc("Initialize with Haar random states.") + .arg("batch_size", "int", "Number of states in batch.") + .arg("n_qubits", "int", "Number of qubits per state.") + .arg( + "set_same_state", "bool", "Whether to set all states to the same random state.") + .arg("seed", "int, optional", "Random seed (default: random).") + .build_as_google_style() + .c_str()) .def_static( "Haar_random_state", [](std::uint64_t batch_size, @@ -172,57 +256,152 @@ void bind_state_state_vector_batched_hpp(nb::module_& m) { bool set_same_state, std::optional seed) { return StateVectorBatched::Haar_random_state( - batch_size, n_qubits, set_same_state, seed.value_or(std::random_device{}())); + batch_size, n_qubits, set_same_state, seed.value_or(std::random_device()())); }, "batch_size"_a, "n_qubits"_a, "set_same_state"_a, "seed"_a = std::nullopt, - "Construct batched state vectors with Haar random states. If seed is not " - "specified, the value from random device is used.") - .def("get_amplitudes", - &StateVectorBatched::get_amplitudes, - "Get all amplitudes with as `list[list[complex]]`.") + DocString() + .desc("Construct :class:`StateVectorBatched` with Haar random state.") + .arg("batch_size", "int", "Number of states in batch.") + .arg("n_qubits", "int", "Number of qubits per state.") + .arg( + "set_same_state", "bool", "Whether to set all states to the same random state.") + .arg("seed", "int, optional", "Random seed (default: random).") + .ret("StateVectorBatched", "New batched state vector with random states.") + .build_as_google_style() + .c_str()) + // Measurement and probability methods .def("get_squared_norm", &StateVectorBatched::get_squared_norm, - "Get squared norm of each state in the batch. $\\braket{\\psi|\\psi}$.") + DocString() + .desc("Get squared norm for each state in the batch.") + .ret("list[float]", "List of squared norms.") + .build_as_google_style() + .c_str()) .def("normalize", &StateVectorBatched::normalize, - "Normalize each state in the batch (let $\\braket{\\psi|\\psi} = 1$ by " - "multiplying coef).") + DocString().desc("Normalize all states in the batch.").build_as_google_style().c_str()) .def("get_zero_probability", &StateVectorBatched::get_zero_probability, - "Get the probability to observe $\\ket{0}$ at specified index for each state in " - "the batch.") + "target_qubit_index"_a, + DocString() + .desc("Get probability of measuring |0⟩ on specified qubit for each state.") + .arg("target_qubit_index", "int", "Index of qubit to measure.") + .ret("list[float]", "Probabilities for each state in batch.") + .build_as_google_style() + .c_str()) .def("get_marginal_probability", &StateVectorBatched::get_marginal_probability, - "Get the marginal probability to observe as specified for each state in the batch. " - "Specify the result as n-length list. `0` and `1` represent the qubit is observed " - "and get the value. `2` represents the qubit is not observed.") + "measured_values"_a, + DocString() + .desc("Get marginal probabilities for specified measurement outcomes.") + .arg("measured_values", "list[int]", "Measurement configuration.") + .ret("list[float]", "Probabilities for each state in batch.") + .build_as_google_style() + .c_str()) + // Entropy and sampling methods .def("get_entropy", &StateVectorBatched::get_entropy, - "Get the entropy of each state in the batch.") + DocString() + .desc("Calculate von Neumann entropy for each state.") + .ret("list[float]", "Entropy values for each state.") + .build_as_google_style() + .c_str()) + .def( + "sampling", + [](const StateVectorBatched& states, + std::uint64_t sampling_count, + std::optional seed) { + return states.sampling(sampling_count, seed.value_or(std::random_device()())); + }, + "sampling_count"_a, + "seed"_a = std::nullopt, + DocString() + .desc("Sample from the probability distribution of each state.") + .arg("sampling_count", "int", "Number of samples to take.") + .arg("seed", "int, optional", "Random seed (default: random).") + .ret("list[list[int]]", "Samples for each state in batch.") + .build_as_google_style() + .c_str()) + // State manipulation methods .def("add_state_vector_with_coef", &StateVectorBatched::add_state_vector_with_coef, - "Add other batched state vectors with multiplying the coef and make superposition. " - "$\\ket{\\mathrm{this}}\\leftarrow\\ket{\\mathrm{this}}+\\mathrm{coef}" - "\\ket{\\mathrm{states}}$.") + "coef"_a, + "states"_a, + DocString() + .desc("Add another batched state vector multiplied by a coefficient.") + .arg("coef", "complex", "Coefficient to multiply with states.") + .arg("states", "StateVectorBatched", "States to add.") + .build_as_google_style() + .c_str()) + .def("multiply_coef", + &StateVectorBatched::multiply_coef, + "coef"_a, + DocString() + .desc("Multiply all states by a coefficient.") + .arg("coef", "complex", "Coefficient to multiply.") + .build_as_google_style() + .c_str()) + // Data access methods .def("load", &StateVectorBatched::load, - "Load batched amplitudes from `list[list[complex]]`.") - .def("copy", &StateVectorBatched::copy, "Create a copy of the batched state vector.") - .def("to_string", &StateVectorBatched::to_string, "Information as `str`.") - .def("__str__", &StateVectorBatched::to_string, "Information as `str`.") + "states"_a, + DocString() + .desc("Load amplitudes for all states in batch.") + .arg("states", "list[list[complex]]", "Amplitudes for each state.") + .build_as_google_style() + .c_str()) + .def("get_amplitudes", + &StateVectorBatched::get_amplitudes, + DocString() + .desc("Get amplitudes of all states in batch.") + .ret("list[list[complex]]", "Amplitudes for each state.") + .build_as_google_style() + .c_str()) + // Copy and string representation + .def("copy", + &StateVectorBatched::copy, + DocString() + .desc("Create a deep copy of this batched state vector.") + .ret("StateVectorBatched", "New copy of the states.") + .build_as_google_style() + .c_str()) + .def("to_string", + &StateVectorBatched::to_string, + DocString() + .desc("Get string representation of the batched states.") + .ret("str", "String representation of states.") + .build_as_google_style() + .c_str()) + .def("__str__", + &StateVectorBatched::to_string, + DocString() + .desc("Get string representation of the batched states.") + .ret("str", "String representation of states.") + .build_as_google_style() + .c_str()) + // JSON serialization .def( "to_json", [](const StateVectorBatched& states) { return Json(states).dump(); }, - "Get JSON representation of the states.") + DocString() + .desc("Convert states to JSON string.") + .ret("str", "JSON representation of states.") + .build_as_google_style() + .c_str()) .def( "load_json", [](StateVectorBatched& states, const std::string& str) { states = nlohmann::json::parse(str); }, - "Read an object from the JSON representation of the states."); + "json_str"_a, + DocString() + .desc("Load states from JSON string.") + .arg("json_str", "str", "JSON string to load from.") + .build_as_google_style() + .c_str()); } } // namespace internal #endif From 28c1fe37a434b2a979aa06769d064fb9c6148b2c Mon Sep 17 00:00:00 2001 From: Glacialte Date: Tue, 14 Jan 2025 04:15:02 +0000 Subject: [PATCH 02/13] add f32 module --- doc/source/conf.py | 42 +++++++++++++++++-- include/scaluq/gate/gate.hpp | 6 ++- include/scaluq/gate/gate_standard.hpp | 49 +++++++++++----------- include/scaluq/operator/pauli_operator.hpp | 19 +++++---- python/scaluq/__init__.py | 2 +- python/scaluq/f32/__init__.py | 2 +- python/scaluq/f32/gate/__init__.py | 2 +- python/scaluq/f64/__init__.py | 2 +- python/scaluq/f64/gate/__init__.py | 2 +- src/operator/pauli_operator.cpp | 14 +++---- 10 files changed, 92 insertions(+), 48 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index a735919..656254e 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -1,8 +1,25 @@ import sys import subprocess +from pathlib import Path -subprocess.run([sys.executable, '-m', 'nanobind.stubgen', '-m', 'scaluq.scaluq_core', '-o', './stub/scaluq/__init__.py']) -subprocess.run([sys.executable, '-m', 'nanobind.stubgen', '-m', 'scaluq.scaluq_core.gate', '-o', './stub/scaluq/gate.py']) +stub_dir = Path('./stub/scaluq/') +stub_dir.mkdir(parents=True, exist_ok=True) + +subprocess.run([sys.executable, '-m', 'nanobind.stubgen', + '-m', 'scaluq.scaluq_core.f64', + '-o', './stub/scaluq/f64/__init__.py']) + +subprocess.run([sys.executable, '-m', 'nanobind.stubgen', + '-m', 'scaluq.scaluq_core.f64.gate', + '-o', './stub/scaluq/f64/gate.py']) + +subprocess.run([sys.executable, '-m', 'nanobind.stubgen', + '-m', 'scaluq.scaluq_core.f32', + '-o', './stub/scaluq/f32/__init__.py']) + +subprocess.run([sys.executable, '-m', 'nanobind.stubgen', + '-m', 'scaluq.scaluq_core.f32.gate', + '-o', './stub/scaluq/f32/gate.py']) project = 'scaluq' copyright = '2024, Fuji Lab.' @@ -16,14 +33,24 @@ 'autoapi.extension', ] +mathjax3_config = { + 'tex': { + 'inlineMath': [['$', '$'], ['\\(', '\\)']], + 'displayMath': [['$$', '$$'], ['\\[', '\\]']], + 'packages': ['base', 'ams', 'braket', 'noerrors', 'noundefined'], + 'processEscapes': True, + 'processEnvironments': True + } +} + autoapi_type = "python" autoapi_keep_files = True autoapi_file_patterns = ["*.py"] autoapi_dirs = ["./stub/scaluq"] autoapi_add_toctree_entry = True - autoapi_python_class_content = 'class' + autoapi_options = [ "members", "undoc-members", @@ -32,8 +59,17 @@ "imported-members", ] +autodoc_typehints = 'none' + html_theme = "sphinx_rtd_theme" +html_theme_options = { + 'math_number_all': True, +} +# html_js_files = [ +# 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.0/es5/tex-mml-chtml.js' +# ] + # `version` is only used for local build. # On Read the Docs, the latest version is `latest`` and the specific version # is the Git tag name. diff --git a/include/scaluq/gate/gate.hpp b/include/scaluq/gate/gate.hpp index 672bd98..da5cc35 100644 --- a/include/scaluq/gate/gate.hpp +++ b/include/scaluq/gate/gate.hpp @@ -352,7 +352,11 @@ namespace internal { "Get target and control qubits as mask.") \ .def( \ "get_inverse", \ - [](const GATE_TYPE& gate) { return gate->get_inverse(); }, \ + [](const GATE_TYPE& gate) { \ + auto inv = gate->get_inverse(); \ + if (!inv) nb::none(); \ + return Gate(inv); \ + }, \ "Generate inverse gate as `Gate` type. If not exists, return None.") \ .def( \ "update_quantum_state", \ diff --git a/include/scaluq/gate/gate_standard.hpp b/include/scaluq/gate/gate_standard.hpp index 50dc266..817ac46 100644 --- a/include/scaluq/gate/gate_standard.hpp +++ b/include/scaluq/gate/gate_standard.hpp @@ -764,33 +764,32 @@ void bind_gate_gate_standard_hpp(nb::module_& m) { DEF_GATE(HGate, Fp, "Specific class of Hadamard gate."); DEF_GATE(SGate, Fp, - "Specific class of S gate, represented as $\\begin { bmatrix }\n1 & 0\\\\\n0 &" - "i\n\\end{bmatrix}$."); + "Specific class of S gate, represented as $\\begin{bmatrix} 1 & 0 \\\\ 0 & i " + "\\end{bmatrix}$."); DEF_GATE(SdagGate, Fp, "Specific class of inverse of S gate."); DEF_GATE(TGate, Fp, - "Specific class of T gate, represented as $\\begin { bmatrix }\n1 & 0\\\\\n0 &" - "e^{i\\pi/4}\n\\end{bmatrix}$."); + "Specific class of T gate, represented as $\\begin{bmatrix} 1 & 0 \\\\ 0 &" + "e^{i\\pi/4} \\end{bmatrix}$."); DEF_GATE(TdagGate, Fp, "Specific class of inverse of T gate."); - DEF_GATE( - SqrtXGate, - Fp, - "Specific class of sqrt(X) gate, represented as $\\begin{ bmatrix }\n1+i & 1-i\\\\\n1-i " - "& 1+i\n\\end{bmatrix}$."); + DEF_GATE(SqrtXGate, + Fp, + "Specific class of sqrt(X) gate, represented as $\\begin{bmatrix} 1+i & 1-i\\\\ 1-i " + "& 1+i \\end{bmatrix}$."); DEF_GATE(SqrtXdagGate, Fp, "Specific class of inverse of sqrt(X) gate."); DEF_GATE(SqrtYGate, Fp, - "Specific class of sqrt(Y) gate, represented as $\\begin{ bmatrix }\n1+i & -1-i " - "\\\\\n1+i & 1+i\n\\end{bmatrix}$."); + "Specific class of sqrt(Y) gate, represented as $\\begin{bmatrix} 1+i & -1-i " + "\\\\ 1+i & 1+i \\end{bmatrix}$."); DEF_GATE(SqrtYdagGate, Fp, "Specific class of inverse of sqrt(Y) gate."); - DEF_GATE( - P0Gate, - Fp, - "Specific class of projection gate to $\\ket{0}$.\n\n.. note:: This gate is not unitary."); - DEF_GATE( - P1Gate, - Fp, - "Specific class of projection gate to $\\ket{1}$.\n\n.. note:: This gate is not unitary."); + DEF_GATE(P0Gate, + Fp, + "Specific class of projection gate to $\\vert 0 \\rangle$.\n\n.. note:: This gate is " + "not unitary."); + DEF_GATE(P1Gate, + Fp, + "Specific class of projection gate to $\\vert 1 \\rangle$.\n\n.. note:: This gate is " + "not unitary."); #define DEF_ROTATION_GATE(GATE_TYPE, FLOAT, DESCRIPTION) \ DEF_GATE(GATE_TYPE, FLOAT, DESCRIPTION) \ @@ -816,7 +815,7 @@ void bind_gate_gate_standard_hpp(nb::module_& m) { Fp, "Specific class of IBMQ's U1 Gate, which is a rotation abount Z-axis, " "represented as " - "$\\begin{bmatrix}\n1 & 0\\\\\n0 & e^{i\\lambda}\n\\end{bmatrix}$.") + "$\\begin{bmatrix} 1 & 0\\\\ 0 & e^{i\\lambda} \\end{bmatrix}$.") .def( "lambda_", [](const U1Gate& gate) { return gate->lambda(); }, @@ -825,8 +824,8 @@ void bind_gate_gate_standard_hpp(nb::module_& m) { Fp, "Specific class of IBMQ's U2 Gate, which is a rotation about X+Z-axis, " "represented as " - "$\\frac{1}{\\sqrt{2}} \\begin{bmatrix}1 & -e^{-i\\lambda}\\\\\n" - "e^{i\\phi} & e^{i(\\phi+\\lambda)}\n\\end{bmatrix}$.") + "$\\frac{1}{\\sqrt{2}} \\begin{bmatrix}1 & -e^{-i\\lambda}\\\\ " + "e^{i\\phi} & e^{i(\\phi+\\lambda)} \\end{bmatrix}$.") .def( "phi", [](const U2Gate& gate) { return gate->phi(); }, "Get `phi` property.") .def( @@ -837,10 +836,10 @@ void bind_gate_gate_standard_hpp(nb::module_& m) { Fp, "Specific class of IBMQ's U3 Gate, which is a rotation abount 3 axis, " "represented as " - "$\\begin{bmatrix}\n\\cos \\frac{\\theta}{2} & " - "-e^{i\\lambda}\\sin\\frac{\\theta}{2}\\\\\n" + "$\\begin{bmatrix} \\cos \\frac{\\theta}{2} & " + "-e^{i\\lambda}\\sin\\frac{\\theta}{2}\\\\ " "e^{i\\phi}\\sin\\frac{\\theta}{2} & " - "e^{i(\\phi+\\lambda)}\\cos\\frac{\\theta}{2}\n\\end{bmatrix}$.") + "e^{i(\\phi+\\lambda)}\\cos\\frac{\\theta}{2} \\end{bmatrix}$.") .def( "theta", [](const U3Gate& gate) { return gate->theta(); }, "Get `theta` property.") .def( diff --git a/include/scaluq/operator/pauli_operator.hpp b/include/scaluq/operator/pauli_operator.hpp index a4fc245..2edcc5f 100644 --- a/include/scaluq/operator/pauli_operator.hpp +++ b/include/scaluq/operator/pauli_operator.hpp @@ -53,7 +53,7 @@ class PauliOperator { std::shared_ptr _ptr; public: - enum PauliID : std::uint64_t { I, X, Y, Z }; + enum PauliID : std::uint64_t { PAULI_I, PAULI_X, PAULI_Y, PAULI_Z }; explicit PauliOperator(Complex coef = 1.) : _ptr(std::make_shared(coef)) {} explicit PauliOperator(Data data) : _ptr(std::make_shared(data)) {} @@ -110,12 +110,17 @@ class PauliOperator { namespace internal { template void bind_operator_pauli_operator_hpp(nb::module_& m) { - nb::enum_::PauliID>(m, "PauliID") - .value("I", PauliOperator::I) - .value("X", PauliOperator::X) - .value("Y", PauliOperator::Y) - .value("Z", PauliOperator::Z) - .export_values(); + auto pauli_enum = nb::enum_::PauliID>(m, "PauliID") + .value("PAULI_I", PauliOperator::PAULI_I) + .value("PAULI_X", PauliOperator::PAULI_X) + .value("PAULI_Y", PauliOperator::PAULI_Y) + .value("PAULI_Z", PauliOperator::PAULI_Z) + .export_values(); + + m.attr("PAULI_I") = (int)PauliOperator::PAULI_I; + m.attr("PAULI_X") = (int)PauliOperator::PAULI_X; + m.attr("PAULI_Y") = (int)PauliOperator::PAULI_Y; + m.attr("PAULI_Z") = (int)PauliOperator::PAULI_Z; nb::class_::Data>( m, "PauliOperatorData", "Internal data structure for PauliOperator.") diff --git a/python/scaluq/__init__.py b/python/scaluq/__init__.py index 9daedec..538bf0c 100644 --- a/python/scaluq/__init__.py +++ b/python/scaluq/__init__.py @@ -1,3 +1,3 @@ -from .scaluq_core import * +# from .scaluq_core import * from . import f64 from . import f32 diff --git a/python/scaluq/f32/__init__.py b/python/scaluq/f32/__init__.py index f515c96..394c02c 100644 --- a/python/scaluq/f32/__init__.py +++ b/python/scaluq/f32/__init__.py @@ -1,2 +1,2 @@ -from ..scaluq_core.f32 import * +# from ..scaluq_core.f64 import * from . import gate diff --git a/python/scaluq/f32/gate/__init__.py b/python/scaluq/f32/gate/__init__.py index d351ea5..b6e690f 100644 --- a/python/scaluq/f32/gate/__init__.py +++ b/python/scaluq/f32/gate/__init__.py @@ -1 +1 @@ -from ...scaluq_core.f32.gate import * +from . import * diff --git a/python/scaluq/f64/__init__.py b/python/scaluq/f64/__init__.py index d05af3b..394c02c 100644 --- a/python/scaluq/f64/__init__.py +++ b/python/scaluq/f64/__init__.py @@ -1,2 +1,2 @@ -from ..scaluq_core.f64 import * +# from ..scaluq_core.f64 import * from . import gate diff --git a/python/scaluq/f64/gate/__init__.py b/python/scaluq/f64/gate/__init__.py index ef7711b..b6e690f 100644 --- a/python/scaluq/f64/gate/__init__.py +++ b/python/scaluq/f64/gate/__init__.py @@ -1 +1 @@ -from ...scaluq_core.f64.gate import * +from . import * diff --git a/src/operator/pauli_operator.cpp b/src/operator/pauli_operator.cpp index 041b61a..4cec5d4 100644 --- a/src/operator/pauli_operator.cpp +++ b/src/operator/pauli_operator.cpp @@ -18,10 +18,10 @@ PauliOperator::Data::Data(std::string_view pauli_string, Complex coef) throw std::runtime_error("PauliOperator::PauliOperator: invalid pauli_string format"); } std::uint64_t pauli_id = [&] { - if (pauli == 'I' || pauli == 'i') return PauliOperator::I; - if (pauli == 'X' || pauli == 'x') return PauliOperator::X; - if (pauli == 'Y' || pauli == 'y') return PauliOperator::Y; - if (pauli == 'Z' || pauli == 'z') return PauliOperator::Z; + if (pauli == 'I' || pauli == 'i') return PauliOperator::PAULI_I; + if (pauli == 'X' || pauli == 'x') return PauliOperator::PAULI_X; + if (pauli == 'Y' || pauli == 'y') return PauliOperator::PAULI_Y; + if (pauli == 'Z' || pauli == 'z') return PauliOperator::PAULI_Z; throw std::runtime_error("PauliOperator::PauliOperator: invalid pauli_string format"); }(); if (pauli_id != 0) add_single_pauli(target, pauli_id); @@ -50,7 +50,7 @@ PauliOperator::Data::Data(const std::vector& pauli_id_par_qub Complex coef) : _coef(coef), _bit_flip_mask(0), _phase_flip_mask(0) { for (std::uint64_t i = 0; i < pauli_id_par_qubit.size(); ++i) { - if (pauli_id_par_qubit[i] != PauliOperator::I) { + if (pauli_id_par_qubit[i] != PauliOperator::PAULI_I) { add_single_pauli(i, pauli_id_par_qubit[i]); } } @@ -96,10 +96,10 @@ void PauliOperator::Data::add_single_pauli(std::uint64_t target_qubit, std:: "same " "qubit."); } - if (pauli_id == PauliOperator::X || pauli_id == PauliOperator::Y) { + if (pauli_id == PauliOperator::PAULI_X || pauli_id == PauliOperator::PAULI_Y) { _bit_flip_mask |= 1ULL << target_qubit; } - if (pauli_id == PauliOperator::Y || pauli_id == PauliOperator::Z) { + if (pauli_id == PauliOperator::PAULI_Y || pauli_id == PauliOperator::PAULI_Z) { _phase_flip_mask |= 1ULL << target_qubit; } } From 980271eeee2c5fd200606f17a6f565540a3ded80 Mon Sep 17 00:00:00 2001 From: Glacialte Date: Fri, 17 Jan 2025 11:18:21 +0900 Subject: [PATCH 03/13] undo changes --- include/scaluq/gate/gate_standard.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/scaluq/gate/gate_standard.hpp b/include/scaluq/gate/gate_standard.hpp index 817ac46..05de3e6 100644 --- a/include/scaluq/gate/gate_standard.hpp +++ b/include/scaluq/gate/gate_standard.hpp @@ -770,7 +770,7 @@ void bind_gate_gate_standard_hpp(nb::module_& m) { DEF_GATE(TGate, Fp, "Specific class of T gate, represented as $\\begin{bmatrix} 1 & 0 \\\\ 0 &" - "e^{i\\pi/4} \\end{bmatrix}$."); + "e^{i \\pi/4} \\end{bmatrix}$."); DEF_GATE(TdagGate, Fp, "Specific class of inverse of T gate."); DEF_GATE(SqrtXGate, Fp, @@ -784,11 +784,11 @@ void bind_gate_gate_standard_hpp(nb::module_& m) { DEF_GATE(SqrtYdagGate, Fp, "Specific class of inverse of sqrt(Y) gate."); DEF_GATE(P0Gate, Fp, - "Specific class of projection gate to $\\vert 0 \\rangle$.\n\n.. note:: This gate is " + "Specific class of projection gate to $\\ket{0}$.\n\n.. note:: This gate is " "not unitary."); DEF_GATE(P1Gate, Fp, - "Specific class of projection gate to $\\vert 1 \\rangle$.\n\n.. note:: This gate is " + "Specific class of projection gate to $\\ket{1}$.\n\n.. note:: This gate is " "not unitary."); #define DEF_ROTATION_GATE(GATE_TYPE, FLOAT, DESCRIPTION) \ @@ -815,7 +815,7 @@ void bind_gate_gate_standard_hpp(nb::module_& m) { Fp, "Specific class of IBMQ's U1 Gate, which is a rotation abount Z-axis, " "represented as " - "$\\begin{bmatrix} 1 & 0\\\\ 0 & e^{i\\lambda} \\end{bmatrix}$.") + "$\\begin{bmatrix} 1 & 0 \\\\ 0 & e^{i\\lambda} \\end{bmatrix}$.") .def( "lambda_", [](const U1Gate& gate) { return gate->lambda(); }, From 2c4ffc05c211ecd699a074e818fecfdc43d63270 Mon Sep 17 00:00:00 2001 From: Glacialte Date: Fri, 17 Jan 2025 13:08:07 +0900 Subject: [PATCH 04/13] iroiro fix --- doc/source/conf.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 656254e..8310d95 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -33,16 +33,6 @@ 'autoapi.extension', ] -mathjax3_config = { - 'tex': { - 'inlineMath': [['$', '$'], ['\\(', '\\)']], - 'displayMath': [['$$', '$$'], ['\\[', '\\]']], - 'packages': ['base', 'ams', 'braket', 'noerrors', 'noundefined'], - 'processEscapes': True, - 'processEnvironments': True - } -} - autoapi_type = "python" autoapi_keep_files = True @@ -66,9 +56,6 @@ html_theme_options = { 'math_number_all': True, } -# html_js_files = [ -# 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.0/es5/tex-mml-chtml.js' -# ] # `version` is only used for local build. # On Read the Docs, the latest version is `latest`` and the specific version From cbae27d08b8be43d1205b86476de0eca9ce17123 Mon Sep 17 00:00:00 2001 From: Glacialte Date: Fri, 24 Jan 2025 01:12:31 +0000 Subject: [PATCH 05/13] mini fix for conf.py, remove export_values() for pauli_enum in pauli_operator.hpp --- doc/source/conf.py | 3 ++- include/scaluq/operator/pauli_operator.hpp | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 8310d95..a7d8b13 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -40,6 +40,7 @@ autoapi_dirs = ["./stub/scaluq"] autoapi_add_toctree_entry = True autoapi_python_class_content = 'class' +# autoapi_python_class_content = 'both' autoapi_options = [ "members", @@ -49,7 +50,7 @@ "imported-members", ] -autodoc_typehints = 'none' +autodoc_typehints = 'description' html_theme = "sphinx_rtd_theme" diff --git a/include/scaluq/operator/pauli_operator.hpp b/include/scaluq/operator/pauli_operator.hpp index 2edcc5f..5a5aedc 100644 --- a/include/scaluq/operator/pauli_operator.hpp +++ b/include/scaluq/operator/pauli_operator.hpp @@ -110,17 +110,17 @@ class PauliOperator { namespace internal { template void bind_operator_pauli_operator_hpp(nb::module_& m) { - auto pauli_enum = nb::enum_::PauliID>(m, "PauliID") + auto pauli_enum = nb::enum_::PauliID>( + m, "PauliID", "Enumeration for Pauli operations.") .value("PAULI_I", PauliOperator::PAULI_I) .value("PAULI_X", PauliOperator::PAULI_X) .value("PAULI_Y", PauliOperator::PAULI_Y) - .value("PAULI_Z", PauliOperator::PAULI_Z) - .export_values(); + .value("PAULI_Z", PauliOperator::PAULI_Z); - m.attr("PAULI_I") = (int)PauliOperator::PAULI_I; - m.attr("PAULI_X") = (int)PauliOperator::PAULI_X; - m.attr("PAULI_Y") = (int)PauliOperator::PAULI_Y; - m.attr("PAULI_Z") = (int)PauliOperator::PAULI_Z; + // m.attr("PAULI_I") = (int)PauliOperator::PAULI_I; + // m.attr("PAULI_X") = (int)PauliOperator::PAULI_X; + // m.attr("PAULI_Y") = (int)PauliOperator::PAULI_Y; + // m.attr("PAULI_Z") = (int)PauliOperator::PAULI_Z; nb::class_::Data>( m, "PauliOperatorData", "Internal data structure for PauliOperator.") From b70955f01889cef378f9f2e015af84ec8c5f1a62 Mon Sep 17 00:00:00 2001 From: Glacialte Date: Tue, 28 Jan 2025 09:25:15 +0900 Subject: [PATCH 06/13] add concatenate_descriotion() to gate.hpp --- include/scaluq/gate/gate.hpp | 19 +++++++++++-------- include/scaluq/operator/pauli_operator.hpp | 5 ----- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/include/scaluq/gate/gate.hpp b/include/scaluq/gate/gate.hpp index da5cc35..0d7f638 100644 --- a/include/scaluq/gate/gate.hpp +++ b/include/scaluq/gate/gate.hpp @@ -390,14 +390,17 @@ namespace internal { template nb::class_> gate_base_def; -#define DEF_GATE(GATE_TYPE, FLOAT, DESCRIPTION) \ - ::scaluq::internal::gate_base_def.def(nb::init>(), \ - "Upcast from `" #GATE_TYPE "`."); \ - DEF_GATE_BASE( \ - GATE_TYPE, \ - FLOAT, \ - DESCRIPTION \ - "\n\n.. note:: Upcast is required to use gate-general functions (ex: add to Circuit).") \ +inline nb::sig concatenate_description(const std::string& desc) { + std::string combined = + desc + + "\n\n.. note:: Upcast is required to use gate-general functions (ex: add to Circuit)."; + return nb::sig(combined.c_str()); +} + +#define DEF_GATE(GATE_TYPE, FLOAT, DESCRIPTION) \ + ::scaluq::internal::gate_base_def.def(nb::init>(), \ + "Upcast from `" #GATE_TYPE "`."); \ + DEF_GATE_BASE(GATE_TYPE, FLOAT, concatenate_description(DESCRIPTION)) \ .def(nb::init>()) void bind_gate_gate_hpp_without_precision(nb::module_& m) { diff --git a/include/scaluq/operator/pauli_operator.hpp b/include/scaluq/operator/pauli_operator.hpp index 5a5aedc..ace2ac8 100644 --- a/include/scaluq/operator/pauli_operator.hpp +++ b/include/scaluq/operator/pauli_operator.hpp @@ -117,11 +117,6 @@ void bind_operator_pauli_operator_hpp(nb::module_& m) { .value("PAULI_Y", PauliOperator::PAULI_Y) .value("PAULI_Z", PauliOperator::PAULI_Z); - // m.attr("PAULI_I") = (int)PauliOperator::PAULI_I; - // m.attr("PAULI_X") = (int)PauliOperator::PAULI_X; - // m.attr("PAULI_Y") = (int)PauliOperator::PAULI_Y; - // m.attr("PAULI_Z") = (int)PauliOperator::PAULI_Z; - nb::class_::Data>( m, "PauliOperatorData", "Internal data structure for PauliOperator.") .def(nb::init>(), "coef"_a = 1., "Initialize data with coefficient.") From ddc91dfee97194aa5cd6885d91a0792bdaeb4f28 Mon Sep 17 00:00:00 2001 From: Glacialte Date: Tue, 28 Jan 2025 12:09:57 +0900 Subject: [PATCH 07/13] fix python package --- python/scaluq/__init__.py | 2 +- python/scaluq/f32/__init__.py | 2 +- python/scaluq/f32/gate/__init__.py | 2 +- python/scaluq/f64/__init__.py | 2 +- python/scaluq/f64/gate/__init__.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/scaluq/__init__.py b/python/scaluq/__init__.py index 538bf0c..9daedec 100644 --- a/python/scaluq/__init__.py +++ b/python/scaluq/__init__.py @@ -1,3 +1,3 @@ -# from .scaluq_core import * +from .scaluq_core import * from . import f64 from . import f32 diff --git a/python/scaluq/f32/__init__.py b/python/scaluq/f32/__init__.py index 394c02c..f515c96 100644 --- a/python/scaluq/f32/__init__.py +++ b/python/scaluq/f32/__init__.py @@ -1,2 +1,2 @@ -# from ..scaluq_core.f64 import * +from ..scaluq_core.f32 import * from . import gate diff --git a/python/scaluq/f32/gate/__init__.py b/python/scaluq/f32/gate/__init__.py index b6e690f..d351ea5 100644 --- a/python/scaluq/f32/gate/__init__.py +++ b/python/scaluq/f32/gate/__init__.py @@ -1 +1 @@ -from . import * +from ...scaluq_core.f32.gate import * diff --git a/python/scaluq/f64/__init__.py b/python/scaluq/f64/__init__.py index 394c02c..d05af3b 100644 --- a/python/scaluq/f64/__init__.py +++ b/python/scaluq/f64/__init__.py @@ -1,2 +1,2 @@ -# from ..scaluq_core.f64 import * +from ..scaluq_core.f64 import * from . import gate diff --git a/python/scaluq/f64/gate/__init__.py b/python/scaluq/f64/gate/__init__.py index b6e690f..ef7711b 100644 --- a/python/scaluq/f64/gate/__init__.py +++ b/python/scaluq/f64/gate/__init__.py @@ -1 +1 @@ -from . import * +from ...scaluq_core.f64.gate import * From d7a92d5139afed0455948071ba2a51526ea95c53 Mon Sep 17 00:00:00 2001 From: Glacialte Date: Fri, 31 Jan 2025 03:29:45 +0000 Subject: [PATCH 08/13] mini fix example, gate.hpp --- exe/main.py | 2 +- include/scaluq/gate/gate.hpp | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/exe/main.py b/exe/main.py index e8c76be..4aa58b3 100644 --- a/exe/main.py +++ b/exe/main.py @@ -18,7 +18,7 @@ def main(): print(operator.to_json()) - states = StateVectorBatched.Haar_random_state(2, 3) + states = StateVectorBatched.Haar_random_state(2, 3, False) prx = gate.ParamRX(0, 2.0, [1]) pry = gate.ParamRY(1, 2.0, [2]) params = { diff --git a/include/scaluq/gate/gate.hpp b/include/scaluq/gate/gate.hpp index 0d7f638..8711ab9 100644 --- a/include/scaluq/gate/gate.hpp +++ b/include/scaluq/gate/gate.hpp @@ -397,11 +397,10 @@ inline nb::sig concatenate_description(const std::string& desc) { return nb::sig(combined.c_str()); } -#define DEF_GATE(GATE_TYPE, FLOAT, DESCRIPTION) \ - ::scaluq::internal::gate_base_def.def(nb::init>(), \ - "Upcast from `" #GATE_TYPE "`."); \ - DEF_GATE_BASE(GATE_TYPE, FLOAT, concatenate_description(DESCRIPTION)) \ - .def(nb::init>()) +#define DEF_GATE(GATE_TYPE, FLOAT, DESCRIPTION) \ + ::scaluq::internal::gate_base_def.def(nb::init>(), \ + "Upcast from " #GATE_TYPE "."); \ + DEF_GATE_BASE(GATE_TYPE, FLOAT, DESCRIPTION) void bind_gate_gate_hpp_without_precision(nb::module_& m) { nb::enum_(m, "GateType", "Enum of Gate Type.") From 48a7065394ff27c231b78d67a967ff6fc973fcf1 Mon Sep 17 00:00:00 2001 From: Glacialte Date: Fri, 31 Jan 2025 13:21:26 +0900 Subject: [PATCH 09/13] reflect description for circuit, operator, paulioperator, statevectorbatched to ReadtheDocs --- include/scaluq/circuit/circuit.hpp | 11 +++- include/scaluq/operator/operator.hpp | 14 ++++- include/scaluq/operator/pauli_operator.hpp | 9 ++- include/scaluq/state/state_vector_batched.hpp | 55 ++++++++++++++++--- 4 files changed, 77 insertions(+), 12 deletions(-) diff --git a/include/scaluq/circuit/circuit.hpp b/include/scaluq/circuit/circuit.hpp index 416624b..4ca0671 100644 --- a/include/scaluq/circuit/circuit.hpp +++ b/include/scaluq/circuit/circuit.hpp @@ -105,7 +105,16 @@ class Circuit { namespace internal { template void bind_circuit_circuit_hpp(nb::module_& m) { - nb::class_>(m, "Circuit", "Quantum circuit represented as gate array") + nb::class_>(m, + "Circuit", + DocString() + .desc("Quantum circuit representation.") + .arg("n_qubits", "Number of qubits in the circuit.") + .ex(DocString::Code({">>> circuit = Circuit(3)", + ">>> print(circuit.to_json())", + "{\"gate_list\":[],\"n_qubits\":3}"})) + .build_as_google_style() + .c_str()) .def(nb::init(), "Initialize empty circuit of specified qubits.") .def("n_qubits", &Circuit::n_qubits, "Get property of `n_qubits`.") .def("gate_list", diff --git a/include/scaluq/operator/operator.hpp b/include/scaluq/operator/operator.hpp index b4e136e..6b55a39 100644 --- a/include/scaluq/operator/operator.hpp +++ b/include/scaluq/operator/operator.hpp @@ -92,7 +92,19 @@ class Operator { namespace internal { template void bind_operator_operator_hpp(nb::module_& m) { - nb::class_>(m, "Operator", "General quantum operator class.") + nb::class_>( + m, + "Operator", + DocString() + .desc("General quantum operator class.") + .ex(DocString::Code( + {">>> pauli = PauliOperator(\"X 3 Y 2\")", + ">>> operator = Operator(4)", + ">>> operator.add_operator(pauli)", + ">>> print(operator.to_json())", + "{\"coef\":{\"imag\":0.0,\"real\":1.0},\"pauli_string\":\"X 3 Y 2\"}"})) + .build_as_google_style() + .c_str()) .def(nb::init(), "qubit_count"_a, "Initialize operator with specified number of qubits.") diff --git a/include/scaluq/operator/pauli_operator.hpp b/include/scaluq/operator/pauli_operator.hpp index ace2ac8..5c4e78c 100644 --- a/include/scaluq/operator/pauli_operator.hpp +++ b/include/scaluq/operator/pauli_operator.hpp @@ -164,7 +164,14 @@ void bind_operator_pauli_operator_hpp(nb::module_& m) { nb::class_>( m, "PauliOperator", - "Pauli operator as coef and tensor product of single pauli for each qubit.") + DocString() + .desc("Pauli operator as coef and tensor product of single pauli for each qubit.") + .ex(DocString::Code( + {">>> pauli = PauliOperator(\"X 3 Y 2\")", + ">>> print(pauli.to_json())", + "{\"coef\":{\"imag\":0.0,\"real\":1.0},\"pauli_string\":\"X 3 Y 2\"}"})) + .build_as_google_style() + .c_str()) .def(nb::init>(), "coef"_a = 1., "Initialize operator which just multiplying coef.") diff --git a/include/scaluq/state/state_vector_batched.hpp b/include/scaluq/state/state_vector_batched.hpp index 4c71b01..26599dc 100644 --- a/include/scaluq/state/state_vector_batched.hpp +++ b/include/scaluq/state/state_vector_batched.hpp @@ -127,6 +127,31 @@ void bind_state_state_vector_batched_hpp(nb::module_& m) { .desc("Batched vector representation of quantum state.") .desc("Qubit index starts from 0. If the amplitudes of $\\ket{b_{n-1}\\dots b_0}$ " "are $b_i$, the state is $\\sum_i b_i 2^i$.") + .ex(DocString::Code({">>> states = StateVectorBatched(3, 2)", + ">>> print(states)", + "Qubit Count : 2", + "Dimension : 4", + "--------------------", + "Batch_id : 0", + "State vector : ", + " 00 : (1,0)", + " 01 : (0,0)", + " 10 : (0,0)", + " 11 : (0,0)", + "--------------------", + "Batch_id : 1", + "State vector : ", + " 00 : (1,0)", + " 01 : (0,0)", + " 10 : (0,0)", + " 11 : (0,0)", + "--------------------", + "Batch_id : 2", + "State vector : ", + " 00 : (1,0)", + " 01 : (0,0)", + " 10 : (0,0)", + " 11 : (0,0)"})) .build_as_google_style() .c_str()) // Constructor: batch size and number of qubits @@ -139,17 +164,29 @@ void bind_state_state_vector_batched_hpp(nb::module_& m) { .arg("n_qubits", "int", "Number of qubits in each state vector.") .ex(DocString::Code({">>> states = StateVectorBatched(3, 2)", ">>> print(states)", - " *** Quantum States ***", - " * Qubit Count : 2", - " * Dimension : 4", + "Qubit Count : 2", + "Dimension : 4", "--------------------", - " * Batch_id : 0", - " * State vector : ", - " 00 : (1,0)\n 01 : (0,0)\n 10 : (0,0)\n 11 : (0,0)", + "Batch_id : 0", + "State vector : ", + " 00 : (1,0)", + " 01 : (0,0)", + " 10 : (0,0)", + " 11 : (0,0)", "--------------------", - " * Batch_id : 1", - " * State vector : ", - " 00 : (1,0)\n 01 : (0,0)\n 10 : (0,0)\n 11 : (0,0)"})) + "Batch_id : 1", + "State vector : ", + " 00 : (1,0)", + " 01 : (0,0)", + " 10 : (0,0)", + " 11 : (0,0)", + "--------------------", + "Batch_id : 2", + "State vector : ", + " 00 : (1,0)", + " 01 : (0,0)", + " 10 : (0,0)", + " 11 : (0,0)"})) .build_as_google_style() .c_str()) // Constructor: Copy constructor From bcf4211672f74017d7b1c65f37d57b5e84805429 Mon Sep 17 00:00:00 2001 From: Glacialte Date: Fri, 14 Feb 2025 09:46:11 +0900 Subject: [PATCH 10/13] add description of constructors --- include/scaluq/operator/operator.hpp | 1 + include/scaluq/operator/pauli_operator.hpp | 19 +++++++ include/scaluq/state/state_vector_batched.hpp | 51 +++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/include/scaluq/operator/operator.hpp b/include/scaluq/operator/operator.hpp index 6b55a39..8f627bf 100644 --- a/include/scaluq/operator/operator.hpp +++ b/include/scaluq/operator/operator.hpp @@ -97,6 +97,7 @@ void bind_operator_operator_hpp(nb::module_& m) { "Operator", DocString() .desc("General quantum operator class.") + .desc("Given `qubit_count: int`, Initialize operator with specified number of qubits.") .ex(DocString::Code( {">>> pauli = PauliOperator(\"X 3 Y 2\")", ">>> operator = Operator(4)", diff --git a/include/scaluq/operator/pauli_operator.hpp b/include/scaluq/operator/pauli_operator.hpp index 5c4e78c..e76a045 100644 --- a/include/scaluq/operator/pauli_operator.hpp +++ b/include/scaluq/operator/pauli_operator.hpp @@ -166,6 +166,25 @@ void bind_operator_pauli_operator_hpp(nb::module_& m) { "PauliOperator", DocString() .desc("Pauli operator as coef and tensor product of single pauli for each qubit.") + .desc("Given `coef: Complex`, Initialize operator which just multiplying coef.") + .desc("Given `target_qubit_list: std::vector, pauli_id_list: " + "std::vector, coef: Complex`, Initialize pauli operator. For " + "each `i`, single pauli correspond to `pauli_id_list[i]` is applied to " + "`target_qubit_list`-th qubit.") + .desc("Given `pauli_string: std::string_view, coef: Complex`, Initialize pauli " + "operator. For each `i`, single pauli correspond to `pauli_id_list[i]` is " + "applied to `target_qubit_list`-th qubit.") + .desc("Given `pauli_id_par_qubit: std::vector, coef: Complex`, " + "Initialize pauli operator. For each `i`, single pauli correspond to " + "`paul_id_per_qubit` is applied to `i`-th qubit.") + .desc("Given `bit_flip_mask: std::uint64_t, phase_flip_mask: std::uint64_t, coef: " + "Complex`, Initialize pauli operator. For each `i`, single pauli applied to " + "`i`-th qubit is " + "got " + "from `i-th` bit of `bit_flip_mask` and `phase_flip_mask` as follows.\n\n.. " + "csv-table::\n\n \"bit_flip\",\"phase_flip\",\"pauli\"\n " + "\"0\",\"0\",\"I\"\n " + "\"0\",\"1\",\"Z\"\n \"1\",\"0\",\"X\"\n \"1\",\"1\",\"Y\"") .ex(DocString::Code( {">>> pauli = PauliOperator(\"X 3 Y 2\")", ">>> print(pauli.to_json())", diff --git a/include/scaluq/state/state_vector_batched.hpp b/include/scaluq/state/state_vector_batched.hpp index 26599dc..d946f29 100644 --- a/include/scaluq/state/state_vector_batched.hpp +++ b/include/scaluq/state/state_vector_batched.hpp @@ -127,6 +127,10 @@ void bind_state_state_vector_batched_hpp(nb::module_& m) { .desc("Batched vector representation of quantum state.") .desc("Qubit index starts from 0. If the amplitudes of $\\ket{b_{n-1}\\dots b_0}$ " "are $b_i$, the state is $\\sum_i b_i 2^i$.") + .desc("Given `batch_size: int, n_qubits: int`, construct a batched state vector with " + "specified batch size and qubits.") + .desc("Given `other: StateVectorBatched`, Construct a batched state vector by copying " + "another batched state.") .ex(DocString::Code({">>> states = StateVectorBatched(3, 2)", ">>> print(states)", "Qubit Count : 2", @@ -410,6 +414,33 @@ void bind_state_state_vector_batched_hpp(nb::module_& m) { DocString() .desc("Get string representation of the batched states.") .ret("str", "String representation of states.") + .ex(DocString::Code( + {">>> states = StateVectorBatched.Haar_random_state(2, 3, False)", + ">>> print(states.to_string())", + " Qubit Count : 3 ", + "Dimension : 8", + "--------------------", + "Batch_id : 0", + "State vector : ", + " 000 : (-0.135887,-0.331815)", + " 001 : (-0.194471,0.108649)", + " 010 : (-0.147649,-0.329848)", + " 011 : (-0.131489,0.131093)", + " 100 : (-0.262069,0.198882)", + " 101 : (-0.0797319,-0.313087)", + " 110 : (-0.140573,-0.0577208)", + " 111 : (0.181703,0.622905)", + "--------------------", + "Batch_id : 1", + "State vector : ", + " 000 : (-0.310841,0.342973)", + " 001 : (0.16157,-0.216366)", + " 010 : (-0.301031,0.2286)", + " 011 : (-0.430187,-0.341108)", + " 100 : (0.0126325,0.169034)", + " 101 : (0.356303,0.033349)", + " 110 : (-0.184462,-0.0361127)", + " 111 : (0.224724,-0.160959)"})) .build_as_google_style() .c_str()) .def("__str__", @@ -426,6 +457,26 @@ void bind_state_state_vector_batched_hpp(nb::module_& m) { DocString() .desc("Convert states to JSON string.") .ret("str", "JSON representation of states.") + .ex(DocString::Code( + {">>> states = StateVectorBatched.Haar_random_state(2, 3, False)", + ">>> print(states.to_json())", + "{\"batch_size\":2,\"batched_amplitudes\":[{\"amplitudes\":[{\"imag\":-0." + "06388485770655017,\"real\":-0.18444457531249306},{\"imag\":-0." + "19976277833680336,\"real\":0.02688995276721736},{\"imag\":-0." + "10325202586347756,\"real\":0.34750392103639344},{\"imag\":-0." + "08316405642178114,\"real\":-0.13786630724295332},{\"imag\":-0." + "12472230847944885,\"real\":0.14554495925352498},{\"imag\":-0." + "26280362129148116,\"real\":0.11742521097266628},{\"imag\":-0." + "2624948420923217,\"real\":0.020338934511145986},{\"imag\":0." + "03692345644121347,\"real\":0.7573990906654825}]},{\"amplitudes\":[{\"imag\":-" + "0.042863543360962014,\"real\":0.2002535190582227},{\"imag\":-0." + "26105089098208206,\"real\":0.033791318581512894},{\"imag\":-0." + "5467139724228703,\"real\":0.23960667554139148},{\"imag\":-0.1008220536735562," + "\"real\":0.3431287916056916},{\"imag\":0.26552531402802715,\"real\":-0." + "06501035752577479},{\"imag\":0.11913162732583721,\"real\":0." + "47146654843051494},{\"imag\":-0.1877230034941065,\"real\":0." + "04062968177663162},{\"imag\":-0.16209817213481867,\"real\":-0." + "1737591400014162}]}],\"n_qubits\":3}"})) .build_as_google_style() .c_str()) .def( From fc33700fd0cae5e834d8a6f1d7f7e7a991a508f7 Mon Sep 17 00:00:00 2001 From: Glacialte Date: Fri, 14 Feb 2025 09:48:04 +0900 Subject: [PATCH 11/13] mini fix --- doc/source/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index a7d8b13..f7b4263 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -40,7 +40,6 @@ autoapi_dirs = ["./stub/scaluq"] autoapi_add_toctree_entry = True autoapi_python_class_content = 'class' -# autoapi_python_class_content = 'both' autoapi_options = [ "members", From 6dff6f4adbc0ad9629ffa966d3c976ce231d2d15 Mon Sep 17 00:00:00 2001 From: Glacialte Date: Fri, 14 Feb 2025 09:59:36 +0900 Subject: [PATCH 12/13] remove unnecessary option in conf.py --- doc/source/conf.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index f7b4263..80167de 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -53,10 +53,6 @@ html_theme = "sphinx_rtd_theme" -html_theme_options = { - 'math_number_all': True, -} - # `version` is only used for local build. # On Read the Docs, the latest version is `latest`` and the specific version # is the Git tag name. From dc7e96709d9330f5755556bb825d4341013dda31 Mon Sep 17 00:00:00 2001 From: Glacialte Date: Tue, 25 Feb 2025 13:21:52 +0900 Subject: [PATCH 13/13] add more detailed description --- exe/main.cpp | 295 +++++----- include/scaluq/circuit/circuit.hpp | 20 +- include/scaluq/gate/gate.hpp | 11 +- include/scaluq/gate/gate_factory.hpp | 638 ++++++++++++--------- include/scaluq/gate/gate_standard.hpp | 4 +- include/scaluq/gate/param_gate.hpp | 11 +- include/scaluq/gate/param_gate_factory.hpp | 73 ++- include/scaluq/operator/operator.hpp | 6 + include/scaluq/operator/pauli_operator.hpp | 28 +- include/scaluq/state/state_vector.hpp | 1 + src/operator/pauli_operator.cpp | 14 +- 11 files changed, 634 insertions(+), 467 deletions(-) diff --git a/exe/main.cpp b/exe/main.cpp index d7abfe6..032fffc 100644 --- a/exe/main.cpp +++ b/exe/main.cpp @@ -7,159 +7,166 @@ using namespace nlohmann; int main() { scaluq::initialize(); // must be called before using any scaluq methods - { - std::uint64_t n_qubits = 3; - scaluq::StateVector state(n_qubits); - state.load({0, 1, 2, 3, 4, 5, 6, 7}); - Json j = state; - std::cout << j << std::endl; - state = j; - std::cout << state << std::endl; + // { + // std::uint64_t n_qubits = 3; + // scaluq::StateVector state(n_qubits); + // state.load({0, 1, 2, 3, 4, 5, 6, 7}); + // Json j = state; + // std::cout << j << std::endl; + // state = j; + // std::cout << state << std::endl; - scaluq::Circuit circuit(n_qubits); - circuit.add_gate(scaluq::gate::X(0)); - circuit.add_gate(scaluq::gate::CNot(0, 1)); - circuit.add_gate(scaluq::gate::Y(1)); - circuit.add_gate(scaluq::gate::RX(1, std::numbers::pi / 2)); - circuit.update_quantum_state(state); + // scaluq::Circuit circuit(n_qubits); + // circuit.add_gate(scaluq::gate::X(0)); + // circuit.add_gate(scaluq::gate::CNot(0, 1)); + // circuit.add_gate(scaluq::gate::Y(1)); + // circuit.add_gate(scaluq::gate::RX(1, std::numbers::pi / 2)); + // circuit.update_quantum_state(state); - scaluq::Operator observable(n_qubits); - observable.add_random_operator(1, 0); - auto value = observable.get_expectation_value(state); - std::cout << value << std::endl; - } - { - std::uint64_t n_qubits = 2, batch_size = 2; - scaluq::StateVectorBatched states(batch_size, n_qubits); - states.set_Haar_random_state(batch_size, n_qubits, false); + // scaluq::Operator observable(n_qubits); + // observable.add_random_operator(1, 0); + // auto value = observable.get_expectation_value(state); + // std::cout << value << std::endl; + // } + // { + // std::uint64_t n_qubits = 2, batch_size = 2; + // scaluq::StateVectorBatched states(batch_size, n_qubits); + // states.set_Haar_random_state(batch_size, n_qubits, false); - Circuit cirq(n_qubits); - cirq.add_param_gate(gate::ParamRX(1, {2}), "RX"); - std::map> params = {{"RX", {0.5, 1.5}}}; - cirq.update_quantum_state(states, params); + // Circuit cirq(n_qubits); + // cirq.add_param_gate(gate::ParamRX(1, {2}), "RX"); + // std::map> params = {{"RX", {0.5, 1.5}}}; + // cirq.update_quantum_state(states, params); - Json j = states; - std::cout << j << std::endl; - states = j; - std::cout << states << std::endl; - } - { - double coef = 2.0; - std::string pauli_string = "X 0 Z 1 Y 2"; - PauliOperator pauli(pauli_string, coef); - Json j = pauli; - std::cout << j << std::endl; - pauli = j; - } - { - std::uint64_t n_qubits = 3; - Operator op(n_qubits); - op.add_operator({0b001, 0b010, Complex(2)}); - op.add_operator({"X 2 Y 1", 1}); - Json j = op; - std::cout << j << std::endl; - op = j; - } - { - std::cout << Json(gate::I()) << std::endl; - std::cout << Json(gate::X(2, {0, 3})) << std::endl; - std::cout << Json(gate::Y(2, {0, 3})) << std::endl; - std::cout << Json(gate::Z(2, {0, 3})) << std::endl; - std::cout << Json(gate::H(2, {0, 3})) << std::endl; - std::cout << Json(gate::S(2, {0, 3})) << std::endl; - std::cout << Json(gate::Sdag(2, {0, 3})) << std::endl; - std::cout << Json(gate::T(2, {0, 3})) << std::endl; - std::cout << Json(gate::Tdag(2, {0, 3})) << std::endl; - std::cout << Json(gate::SqrtX(2, {0, 3})) << std::endl; - std::cout << Json(gate::SqrtXdag(2, {0, 3})) << std::endl; - std::cout << Json(gate::SqrtY(2, {0, 3})) << std::endl; - std::cout << Json(gate::SqrtYdag(2, {0, 3})) << std::endl; - std::cout << Json(gate::RX(2, 0.5, {0, 3})) << std::endl; - std::cout << Json(gate::RY(2, 0.5, {0, 3})) << std::endl; - std::cout << Json(gate::RZ(2, 0.5, {0, 3})) << std::endl; - std::cout << Json(gate::U1(2, 0.5, {0, 3})) << std::endl; - std::cout << Json(gate::U2(2, 0.5, 0.3, {0, 3})) << std::endl; - std::cout << Json(gate::U3(2, 0.5, 0.3, 0.1, {0, 3})) << std::endl; - std::cout << Json(gate::Swap(1, 2, {0, 3})) << std::endl; + // Json j = states; + // std::cout << j << std::endl; + // states = j; + // std::cout << states << std::endl; + // } + // { + // double coef = 2.0; + // std::string pauli_string = "X 0 Z 1 Y 2"; + // PauliOperator pauli(pauli_string, coef); + // Json j = pauli; + // std::cout << j << std::endl; + // pauli = j; + // } + // { + // std::uint64_t n_qubits = 3; + // Operator op(n_qubits); + // op.add_operator({0b001, 0b010, Complex(2)}); + // op.add_operator({"X 2 Y 1", 1}); + // Json j = op; + // std::cout << j << std::endl; + // op = j; + // } + // { + // std::cout << Json(gate::I()) << std::endl; + // std::cout << Json(gate::X(2, {0, 3})) << std::endl; + // std::cout << Json(gate::Y(2, {0, 3})) << std::endl; + // std::cout << Json(gate::Z(2, {0, 3})) << std::endl; + // std::cout << Json(gate::H(2, {0, 3})) << std::endl; + // std::cout << Json(gate::S(2, {0, 3})) << std::endl; + // std::cout << Json(gate::Sdag(2, {0, 3})) << std::endl; + // std::cout << Json(gate::T(2, {0, 3})) << std::endl; + // std::cout << Json(gate::Tdag(2, {0, 3})) << std::endl; + // std::cout << Json(gate::SqrtX(2, {0, 3})) << std::endl; + // std::cout << Json(gate::SqrtXdag(2, {0, 3})) << std::endl; + // std::cout << Json(gate::SqrtY(2, {0, 3})) << std::endl; + // std::cout << Json(gate::SqrtYdag(2, {0, 3})) << std::endl; + // std::cout << Json(gate::RX(2, 0.5, {0, 3})) << std::endl; + // std::cout << Json(gate::RY(2, 0.5, {0, 3})) << std::endl; + // std::cout << Json(gate::RZ(2, 0.5, {0, 3})) << std::endl; + // std::cout << Json(gate::U1(2, 0.5, {0, 3})) << std::endl; + // std::cout << Json(gate::U2(2, 0.5, 0.3, {0, 3})) << std::endl; + // std::cout << Json(gate::U3(2, 0.5, 0.3, 0.1, {0, 3})) << std::endl; + // std::cout << Json(gate::Swap(1, 2, {0, 3})) << std::endl; - PauliOperator pauli("X 2 Y 1"); - std::cout << Json(gate::Pauli(pauli)) << std::endl; - std::cout << Json(gate::PauliRotation(pauli, 0.5)) << std::endl; + // PauliOperator pauli("X 2 Y 1"); + // std::cout << Json(gate::Pauli(pauli)) << std::endl; + // std::cout << Json(gate::PauliRotation(pauli, 0.5)) << std::endl; - auto probgate = - gate::Probablistic({.1, .9}, {gate::X(0), gate::I()}); - std::cout << Json(probgate) << std::endl; + // auto probgate = + // gate::Probablistic({.1, .9}, {gate::X(0), gate::I()}); + // std::cout << Json(probgate) << std::endl; - std::cout << Json(gate::ParamRX(2, 1.5, {0, 3})) << std::endl; - std::cout << Json(gate::ParamRY(2, 1.5, {0, 3})) << std::endl; - std::cout << Json(gate::ParamRZ(2, 1.5, {0, 3})) << std::endl; - std::cout << Json(gate::ParamPauliRotation(pauli, 0.5)) << std::endl; + // std::cout << Json(gate::ParamRX(2, 1.5, {0, 3})) << std::endl; + // std::cout << Json(gate::ParamRY(2, 1.5, {0, 3})) << std::endl; + // std::cout << Json(gate::ParamRZ(2, 1.5, {0, 3})) << std::endl; + // std::cout << Json(gate::ParamPauliRotation(pauli, 0.5)) << std::endl; - auto paramprobgate = gate::ParamProbablistic( - {.1, .9}, {gate::ParamRX(0), gate::I()}); - std::cout << Json(paramprobgate) << std::endl; - } + // auto paramprobgate = gate::ParamProbablistic( + // {.1, .9}, {gate::ParamRX(0), gate::I()}); + // std::cout << Json(paramprobgate) << std::endl; + // } + // { + // auto x = gate::X(1, {2}); + // Json j = x; + // std::cout << j << std::endl; + // Gate gate = j; + // std::cout << gate << std::endl; + // } + // { + // auto x = gate::RX(1, 0.5, {2}); + // Json j = x; + // std::cout << j << std::endl; + // Gate gate = j; + // std::cout << gate << std::endl; + // } + // { + // auto x = gate::Swap(1, 3, {2}); + // Json j = x; + // std::cout << j << std::endl; + // Gate gate = j; + // std::cout << gate << std::endl; + // } + // { + // PauliOperator pauli("X 2 Y 1"); + // auto x = gate::PauliRotation(pauli, 1.5, {0, 3}); + // Json j = x; + // std::cout << j << std::endl; + // Gate gate = j; + // std::cout << gate << std::endl; + // } + // { + // auto probgate = + // gate::Probablistic({.1, .9}, {gate::X(0, {2, 3}), + // gate::I()}); + // Json j = probgate; + // std::cout << j << std::endl; + // Gate gate = j; + // std::cout << gate << std::endl; + // } + // { + // auto x = gate::ParamRX(1, {2}); + // Json j = x; + // std::cout << j << std::endl; + // ParamGate gate = j; + // std::cout << gate << std::endl; + // } + // { + // auto paramprobgate = gate::ParamProbablistic( + // {.1, .9}, {gate::ParamRX(0), gate::I()}); + // Json j = paramprobgate; + // std::cout << j << std::endl; + // ParamGate gate = j; + // std::cout << gate << std::endl; + // } + // { + // Circuit circuit(10); + // circuit.add_gate(gate::X(0, {3})); + // circuit.add_param_gate(gate::ParamRX(0, 0.5, {3}), "RX"); + // Json j = circuit; + // std::cout << j << std::endl; + // Circuit c = j; + // std::cout << Json(c) << std::endl; + // } { - auto x = gate::X(1, {2}); - Json j = x; - std::cout << j << std::endl; - Gate gate = j; - std::cout << gate << std::endl; + int n_qubits = 1; + StateVector state(n_qubits); + auto sqrtx = gate::SqrtX(0, {}); + auto mat = sqrtx->get_matrix(); + std::cout << mat << std::endl; } - { - auto x = gate::RX(1, 0.5, {2}); - Json j = x; - std::cout << j << std::endl; - Gate gate = j; - std::cout << gate << std::endl; - } - { - auto x = gate::Swap(1, 3, {2}); - Json j = x; - std::cout << j << std::endl; - Gate gate = j; - std::cout << gate << std::endl; - } - { - PauliOperator pauli("X 2 Y 1"); - auto x = gate::PauliRotation(pauli, 1.5, {0, 3}); - Json j = x; - std::cout << j << std::endl; - Gate gate = j; - std::cout << gate << std::endl; - } - { - auto probgate = - gate::Probablistic({.1, .9}, {gate::X(0, {2, 3}), gate::I()}); - Json j = probgate; - std::cout << j << std::endl; - Gate gate = j; - std::cout << gate << std::endl; - } - { - auto x = gate::ParamRX(1, {2}); - Json j = x; - std::cout << j << std::endl; - ParamGate gate = j; - std::cout << gate << std::endl; - } - { - auto paramprobgate = gate::ParamProbablistic( - {.1, .9}, {gate::ParamRX(0), gate::I()}); - Json j = paramprobgate; - std::cout << j << std::endl; - ParamGate gate = j; - std::cout << gate << std::endl; - } - { - Circuit circuit(10); - circuit.add_gate(gate::X(0, {3})); - circuit.add_param_gate(gate::ParamRX(0, 0.5, {3}), "RX"); - Json j = circuit; - std::cout << j << std::endl; - Circuit c = j; - std::cout << Json(c) << std::endl; - } - scaluq::finalize(); } diff --git a/include/scaluq/circuit/circuit.hpp b/include/scaluq/circuit/circuit.hpp index 4ca0671..f80adcf 100644 --- a/include/scaluq/circuit/circuit.hpp +++ b/include/scaluq/circuit/circuit.hpp @@ -115,7 +115,9 @@ void bind_circuit_circuit_hpp(nb::module_& m) { "{\"gate_list\":[],\"n_qubits\":3}"})) .build_as_google_style() .c_str()) - .def(nb::init(), "Initialize empty circuit of specified qubits.") + .def(nb::init(), + "n_qubits"_a, + "Initialize empty circuit of specified qubits.") .def("n_qubits", &Circuit::n_qubits, "Get property of `n_qubits`.") .def("gate_list", &Circuit::gate_list, @@ -123,24 +125,31 @@ void bind_circuit_circuit_hpp(nb::module_& m) { 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_gate_at", &Circuit::get_gate_at, "index"_a, "Get reference of i-th gate.") .def("get_param_key_at", &Circuit::get_param_key_at, + "index"_a, "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&>(&Circuit::add_gate), + "gate"_a, "Add gate. Given gate is copied.") .def( "add_param_gate", nb::overload_cast&, std::string_view>(&Circuit::add_param_gate), + "param_gate"_a, + "param_key"_a, "Add parametric gate with specifing key. Given param_gate is copied.") .def("add_circuit", nb::overload_cast&>(&Circuit::add_circuit), + "other"_a, "Add all gates in specified circuit. Given gates are copied.") .def("update_quantum_state", nb::overload_cast&, const std::map&>( &Circuit::update_quantum_state, nb::const_), + "state"_a, + "params"_a, "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.") @@ -153,6 +162,8 @@ void bind_circuit_circuit_hpp(nb::module_& m) { } circuit.update_quantum_state(state, parameters); }, + "state"_a, + "kwargs"_a, "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.") @@ -161,6 +172,8 @@ void bind_circuit_circuit_hpp(nb::module_& m) { nb::overload_cast&, const std::map>&>( &Circuit::update_quantum_state, nb::const_), + "state"_a, + "params"_a, "Apply gate to the StateVectorBatched. StateVectorBatched in args is directly updated. " "If the circuit contains parametric gate, you have to give real value of parameter as " "dict[str, list[float]] in 2nd arg.") @@ -173,6 +186,8 @@ void bind_circuit_circuit_hpp(nb::module_& m) { } circuit.update_quantum_state(states, parameters); }, + "state"_a, + "kwargs"_a, "Apply gate to the StateVectorBatched. StateVectorBatched in args is directly updated. " "If the circuit contains parametric gate, you have to give real value of parameter as " "\"name=[value1, value2, ...]\" format in kwargs.") @@ -189,6 +204,7 @@ void bind_circuit_circuit_hpp(nb::module_& m) { [](Circuit& circuit, const std::string& str) { circuit = nlohmann::json::parse(str); }, + "json_str"_a, "Read an object from the JSON representation of the circuit."); } } // namespace internal diff --git a/include/scaluq/gate/gate.hpp b/include/scaluq/gate/gate.hpp index 8711ab9..e7fb876 100644 --- a/include/scaluq/gate/gate.hpp +++ b/include/scaluq/gate/gate.hpp @@ -363,6 +363,7 @@ namespace internal { [](const GATE_TYPE& gate, StateVector& state_vector) { \ gate->update_quantum_state(state_vector); \ }, \ + "state"_a, \ "Apply gate to `state_vector`. `state_vector` in args is directly updated.") \ .def( \ "get_matrix", \ @@ -385,18 +386,12 @@ namespace internal { [](GATE_TYPE& gate, const std::string& str) { \ gate = nlohmann::json::parse(str); \ }, \ + "json_str"_a, \ "Read an object from the JSON representation of the gate.") template nb::class_> gate_base_def; -inline nb::sig concatenate_description(const std::string& desc) { - std::string combined = - desc + - "\n\n.. note:: Upcast is required to use gate-general functions (ex: add to Circuit)."; - return nb::sig(combined.c_str()); -} - #define DEF_GATE(GATE_TYPE, FLOAT, DESCRIPTION) \ ::scaluq::internal::gate_base_def.def(nb::init>(), \ "Upcast from " #GATE_TYPE "."); \ @@ -438,7 +433,7 @@ void bind_gate_gate_hpp(nb::module_& m) { gate_base_def = DEF_GATE_BASE(Gate, Fp, - "General class of QuantumGate.\n\n.. note:: Downcast to requred to use " + "General class of QuantumGate.\n\nNotes:\n\tDowncast to required to use " "gate-specific functions.") .def(nb::init>(), "Just copy shallowly."); } diff --git a/include/scaluq/gate/gate_factory.hpp b/include/scaluq/gate/gate_factory.hpp index aee21d0..ae399ba 100644 --- a/include/scaluq/gate/gate_factory.hpp +++ b/include/scaluq/gate/gate_factory.hpp @@ -238,21 +238,25 @@ inline Gate Probablistic(const std::vector& distribution, namespace internal { template void bind_gate_gate_factory_hpp(nb::module_& mgate) { - mgate.def("I", - &gate::I, - DocString() - .desc("Generate identity gate.") - .ret("Gate", "Identity gate instance") - .ex(DocString::Code({">>> gate = I()", ">>> print(gate)", "Identity Gate"})) - .build_as_google_style() - .c_str()); + mgate.def( + "I", + &gate::I, + DocString() + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.IGate`.") + .ret("Gate", "Identity gate instance") + .ex(DocString::Code({">>> gate = I()", ">>> print(gate)", "Identity Gate"})) + .build_as_google_style() + .c_str()); mgate.def( "GlobalPhase", &gate::GlobalPhase, "phase"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate global phase gate.") + .desc("Generate general :class:`~f64.Gate` class instance of " + ":class:`~f64.GlobalPhaseGate`.") + .note("If you need to use functions specific to the :class:`~f64.GlobalPhaseGate` " + "class, please downcast it.") .arg("phase", "float", "Global phase angle in radians") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "Global phase gate instance") @@ -266,8 +270,11 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "target"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate Pauli-X (NOT) gate.") - .desc("Performs bit flip operation.") + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.XGate`. " + "Performs bit flip operation.") + .note("XGate represents the Pauli-X (NOT) gate class.If you need to use functions " + "specific to the :class:`~f64.XGate` " + "class, please downcast it.") .arg("target", "int", "Target qubit index") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "Pauli-X gate instance") @@ -278,11 +285,14 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { mgate.def( "Y", &gate::Y, - "taget"_a, + "target"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate Pauli-Y gate.") - .desc("Performs bit flip and phase flip operation.") + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.YGate`. " + "Performs bit flip and phase flip operation.") + .note("YGate represents the Pauli-Y gate class. If you need to use functions specific " + "to the :class:`~f64.YGate` " + "class, please downcast it.") .arg("target", "int", "Target qubit index") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "Pauli-Y gate instance") @@ -296,8 +306,11 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "target"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate Pauli-Z gate.") - .desc("Performs phase flip operation.") + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.ZGate`. " + "Performs bit flip and phase flip operation.") + .note("ZGate represents the Pauli-Z gate class. If you need to use functions specific " + "to the :class:`~f64.ZGate` " + "class, please downcast it.") .arg("target", "int", "Target qubit index") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "Pauli-Z gate instance") @@ -311,8 +324,10 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "target"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate Hadamard gate.") - .desc("Performs superposition operation.") + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.HGate`. " + "Performs superposition operation.") + .note("If you need to use functions specific to the :class:`~f64.HGate` class, please " + "downcast it.") .arg("target", "int", "Target qubit index") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "Hadamard gate instance") @@ -326,8 +341,9 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "target"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate general Gate class instance of S.") - .desc("Performs phase flip operation.") + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.SGate`.") + .note("If you need to use functions specific to the :class:`~f64.SGate` class, please " + "downcast it.") .arg("target", "int", "Target qubit index") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "S gate instance") @@ -335,29 +351,33 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { ">>> gate = S(1, [0]) # Controlled-S with control on qubit 0"})) .build_as_google_style() .c_str()); - mgate.def("Sdag", - &gate::Sdag, - "target"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate general Gate class instance of Sdag.") - .desc("Performs phase flip operation.") - .arg("target", "int", "Target qubit index") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "Sdag gate instance") - .ex(DocString::Code( - {">>> gate = Sdag(0) # Sdag gate on qubit 0", - ">>> gate = Sdag(1, [0]) # Controlled-Sdag with control on qubit 0"})) - .build_as_google_style() - .c_str()); + mgate.def( + "Sdag", + &gate::Sdag, + "target"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.SdagGate`.") + .note( + "If you need to use functions specific to the :class:`~f64.SdagGate` class, please " + "downcast it.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "Sdag gate instance") + .ex(DocString::Code( + {">>> gate = Sdag(0) # Sdag gate on qubit 0", + ">>> gate = Sdag(1, [0]) # Controlled-Sdag with control on qubit 0"})) + .build_as_google_style() + .c_str()); mgate.def( "T", &gate::T, "target"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate general Gate class instance of T.") - .desc("Performs phase flip operation.") + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.TGate`.") + .note("If you need to use functions specific to the :class:`~f64.TGate` class, please " + "downcast it.") .arg("target", "int", "Target qubit index") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "T gate instance") @@ -365,28 +385,34 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { ">>> gate = T(1, [0]) # Controlled-T with control on qubit 0"})) .build_as_google_style() .c_str()); - mgate.def("Tdag", - &gate::Tdag, - "target"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate general Gate class instance of Tdag.") - .desc("Performs phase flip operation.") - .arg("target", "int", "Target qubit index") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "Tdag gate instance") - .ex(DocString::Code( - {">>> gate = Tdag(0) # Tdag gate on qubit 0", - ">>> gate = Tdag(1, [0]) # Controlled-Tdag with control on qubit 0"})) - .build_as_google_style() - .c_str()); + mgate.def( + "Tdag", + &gate::Tdag, + "target"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.TdagGate`.") + .note( + "If you need to use functions specific to the :class:`~f64.TdagGate` class, please " + "downcast it.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "Tdag gate instance") + .ex(DocString::Code( + {">>> gate = Tdag(0) # Tdag gate on qubit 0", + ">>> gate = Tdag(1, [0]) # Controlled-Tdag with control on qubit 0"})) + .build_as_google_style() + .c_str()); mgate.def("SqrtX", &gate::SqrtX, "target"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate general Gate class instance of SqrtX.") - .desc("Performs phase flip operation.") + .desc("Generate general :class:`~f64.Gate` class instance of " + ":class:`~f64.SqrtXGate`, represented as " + "$\\frac{1}{2}\\begin{bmatrix} 1+i & 1-i \\\\ 1-i & 1+i \\end{bmatrix}$.") + .note("If you need to use functions specific to the :class:`~f64.SqrtXGate` " + "class, please downcast it.") .arg("target", "int", "Target qubit index") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "SqrtX gate instance") @@ -399,8 +425,12 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "target"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate general Gate class instance of SqrtXdag.") - .desc("Performs phase flip operation.") + .desc("Generate general :class:`~f64.Gate` class instance of " + ":class:`~f64.SqrtXdagGate`, represented as " + "$\\begin{bmatrix} 1-i & 1+i\\\\ 1+i " + "& 1-i \\end{bmatrix}$.") + .note("If you need to use functions specific to the :class:`~f64.SqrtXdagGate` " + "class, please downcast it.") .arg("target", "int", "Target qubit index") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "SqrtXdag gate instance") @@ -413,8 +443,12 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "target"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate general Gate class instance of SqrtY.") - .desc("Performs phase flip operation.") + .desc("Generate general :class:`~f64.Gate` class instance of " + ":class:`~f64.SqrtYGate`, represented as " + "$\\begin{bmatrix} 1+i & -1-i " + "\\\\ 1+i & 1+i \\end{bmatrix}$.") + .note("If you need to use functions specific to the :class:`~f64.SqrtYGate` " + "class, please downcast it.") .arg("target", "int", "Target qubit index") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "SqrtY gate instance") @@ -427,8 +461,12 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "target"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate general Gate class instance of SqrtYdag.") - .desc("Performs phase flip operation.") + .desc("Generate general :class:`~f64.Gate` class instance of " + ":class:`~f64.SqrtYdagGate`, represented as " + "$\\begin{bmatrix} 1-i & 1-i " + "\\\\ -1+i & 1-i \\end{bmatrix}$.") + .note("If you need to use functions specific to the :class:`~f64.SqrtYdagGate` " + "class, please downcast it.") .arg("target", "int", "Target qubit index") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "SqrtYdag gate instance") @@ -436,117 +474,131 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { ">>> gate = SqrtYdag(1, [0]) # Controlled-SqrtYdag"})) .build_as_google_style() .c_str()); - mgate.def("P0", - &gate::P0, - "target"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate general Gate class instance of P0.") - .desc("Performs phase flip operation.") - .arg("target", "int", "Target qubit index") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "P0 gate instance") - .ex(DocString::Code({">>> gate = P0(0) # P0 gate on qubit 0", - ">>> gate = P0(1, [0]) # Controlled-P0"})) - .build_as_google_style() - .c_str()); - mgate.def("P1", - &gate::P1, - "target"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate general Gate class instance of P1.") - .desc("Performs phase flip operation.") - .arg("target", "int", "Target qubit index") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "P1 gate instance") - .ex(DocString::Code({">>> gate = P1(0) # P1 gate on qubit 0", - ">>> gate = P1(1, [0]) # Controlled-P1"})) - .build_as_google_style() - .c_str()); - mgate.def("RX", - &gate::RX, - "target"_a, - "angle"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate rotation gate around X-axis.") - .desc("Rotation angle is specified in radians.") - .arg("target", "int", "Target qubit index") - .arg("angle", "float", "Rotation angle in radians") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "RX gate instance") - .ex(DocString::Code({">>> gate = RX(0, math.pi/2) # π/2 rotation around X-axis", - ">>> gate = RX(1, math.pi, [0]) # Controlled-RX"})) - .build_as_google_style() - .c_str()); - mgate.def("RY", - &gate::RY, - "target"_a, - "angle"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate rotation gate around Y-axis.") - .desc("Rotation angle is specified in radians.") - .arg("target", "int", "Target qubit index") - .arg("angle", "float", "Rotation angle in radians") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "RY gate instance") - .ex(DocString::Code({">>> gate = RY(0, math.pi/2) # π/2 rotation around Y-axis", - ">>> gate = RY(1, math.pi, [0]) # Controlled-RY"})) - .build_as_google_style() - .c_str()); - mgate.def("RZ", - &gate::RZ, - "target"_a, - "angle"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate rotation gate around Z-axis.") - .desc("Rotation angle is specified in radians.") - .arg("target", "int", "Target qubit index") - .arg("angle", "float", "Rotation angle in radians") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "RZ gate instance") - .ex(DocString::Code({">>> gate = RZ(0, math.pi/2) # π/2 rotation around Z-axis", - ">>> gate = RZ(1, math.pi, [0]) # Controlled-RZ"})) - .build_as_google_style() - .c_str()); - mgate.def("U1", - &gate::U1, - "target"_a, - "lambda_"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate general Gate class instance of U1.") - .desc("Performs phase flip operation.") - .arg("target", "int", "Target qubit index") - .arg("lambda_", "float", "Rotation angle in radians") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "U1 gate instance") - .ex(DocString::Code({">>> gate = U1(0, math.pi/2) # π/2 rotation around Z-axis", - ">>> gate = U1(1, math.pi, [0]) # Controlled-U1"})) - .build_as_google_style() - .c_str()); - mgate.def("U2", - &gate::U2, - "target"_a, - "phi"_a, - "lambda_"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate general Gate class instance of U2.") - .desc("Performs phase flip operation.") - .arg("target", "int", "Target qubit index") - .arg("phi", "float", "Rotation angle in radians") - .arg("lambda_", "float", "Rotation angle in radians") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "U2 gate instance") - .ex(DocString::Code( - {">>> gate = U2(0, math.pi/2, math.pi) # π/2 rotation around Z-axis", - ">>> gate = U2(1, math.pi, math.pi/2, [0]) # Controlled-U2"})) - .build_as_google_style() - .c_str()); + mgate.def( + "P0", + &gate::P0, + "target"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.P0Gate`.") + .note("If you need to use functions specific to the :class:`~f64.P0Gate` class, please " + "downcast it.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "P0 gate instance") + .ex(DocString::Code({">>> gate = P0(0) # P0 gate on qubit 0", + ">>> gate = P0(1, [0]) # Controlled-P0"})) + .build_as_google_style() + .c_str()); + mgate.def( + "P1", + &gate::P1, + "target"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.P1Gate`.") + .note("If you need to use functions specific to the :class:`~f64.P1Gate` class, please " + "downcast it.") + .arg("target", "int", "Target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "P1 gate instance") + .ex(DocString::Code({">>> gate = P1(0) # P1 gate on qubit 0", + ">>> gate = P1(1, [0]) # Controlled-P1"})) + .build_as_google_style() + .c_str()); + mgate.def( + "RX", + &gate::RX, + "target"_a, + "angle"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate rotation gate around X-axis. Rotation angle is specified in radians.") + .note("If you need to use functions specific to the :class:`~f64.RXGate` class, please " + "downcast it.") + .arg("target", "int", "Target qubit index") + .arg("angle", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "RX gate instance") + .ex(DocString::Code({">>> gate = RX(0, math.pi/2) # π/2 rotation around X-axis", + ">>> gate = RX(1, math.pi, [0]) # Controlled-RX"})) + .build_as_google_style() + .c_str()); + mgate.def( + "RY", + &gate::RY, + "target"_a, + "angle"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate rotation gate around Y-axis. Rotation angle is specified in radians.") + .note("If you need to use functions specific to the :class:`~f64.RYGate` class, please " + "downcast it.") + .arg("target", "int", "Target qubit index") + .arg("angle", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "RY gate instance") + .ex(DocString::Code({">>> gate = RY(0, math.pi/2) # π/2 rotation around Y-axis", + ">>> gate = RY(1, math.pi, [0]) # Controlled-RY"})) + .build_as_google_style() + .c_str()); + mgate.def( + "RZ", + &gate::RZ, + "target"_a, + "angle"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate rotation gate around Z-axis. Rotation angle is specified in radians.") + .note("If you need to use functions specific to the :class:`~f64.RZGate` class, please " + "downcast it.") + .arg("target", "int", "Target qubit index") + .arg("angle", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "RZ gate instance") + .ex(DocString::Code({">>> gate = RZ(0, math.pi/2) # π/2 rotation around Z-axis", + ">>> gate = RZ(1, math.pi, [0]) # Controlled-RZ"})) + .build_as_google_style() + .c_str()); + mgate.def( + "U1", + &gate::U1, + "target"_a, + "lambda_"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.U1Gate`.") + .note("If you need to use functions specific to the :class:`~f64.U1Gate` class, please " + "downcast it.") + .arg("target", "int", "Target qubit index") + .arg("lambda_", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "U1 gate instance") + .ex(DocString::Code({">>> gate = U1(0, math.pi/2) # π/2 rotation around Z-axis", + ">>> gate = U1(1, math.pi, [0]) # Controlled-U1"})) + .build_as_google_style() + .c_str()); + mgate.def( + "U2", + &gate::U2, + "target"_a, + "phi"_a, + "lambda_"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.U2Gate`.") + .note("If you need to use functions specific to the :class:`~f64.U2Gate` class, please " + "downcast it.") + .arg("target", "int", "Target qubit index") + .arg("phi", "float", "Rotation angle in radians") + .arg("lambda_", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "U2 gate instance") + .ex(DocString::Code( + {">>> gate = U2(0, math.pi/2, math.pi) # π/2 rotation around Z-axis", + ">>> gate = U2(1, math.pi, math.pi/2, [0]) # Controlled-U2"})) + .build_as_google_style() + .c_str()); mgate.def( "U3", &gate::U3, @@ -556,8 +608,9 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "lambda_"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate general Gate class instance of U3.") - .desc("Performs phase flip operation.") + .desc("Generate general :class:`~f64.Gate` class instance of :class:`~f64.U3Gate`.") + .note("If you need to use functions specific to the :class:`~f64.U3Gate` class, please " + "downcast it.") .arg("target", "int", "Target qubit index") .arg("theta", "float", "Rotation angle in radians") .arg("phi", "float", "Rotation angle in radians") @@ -569,29 +622,33 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { ">>> gate = U3(1, math.pi, math.pi/2, math.pi, [0]) # Controlled-U3"})) .build_as_google_style() .c_str()); - mgate.def("Swap", - &gate::Swap, - "target1"_a, - "target2"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate SWAP gate.") - .desc("Swaps the states of two qubits.") - .arg("target1", "int", "First target qubit index") - .arg("target2", "int", "Second target qubit index") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "SWAP gate instance") - .ex(DocString::Code({">>> gate = Swap(0, 1) # Swap qubits 0 and 1", - ">>> gate = Swap(1, 2, [0]) # Controlled-SWAP"})) - .build_as_google_style() - .c_str()); + mgate.def( + "Swap", + &gate::Swap, + "target1"_a, + "target2"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate SWAP gate. Swaps the states of two qubits.") + .note("If you need to use functions specific to the :class:`~f64.SwapGate` class, " + "please downcast it.") + .arg("target1", "int", "First target qubit index") + .arg("target2", "int", "Second target qubit index") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "SWAP gate instance") + .ex(DocString::Code({">>> gate = Swap(0, 1) # Swap qubits 0 and 1", + ">>> gate = Swap(1, 2, [0]) # Controlled-SWAP"})) + .build_as_google_style() + .c_str()); mgate.def("CX", &gate::CX, "control"_a, "target"_a, DocString() - .desc("Generate general Gate class instance of CX.") - .desc("Performs controlled-X operation.") + .desc("Generate general :class:`~f64.Gate` class instance of CXGate. Performs " + "controlled-X operation.") + .note("CX is a specialization of X. If you need to use functions specific to the " + "CXGate class, please downcast it.") .arg("control", "int", "Control qubit index") .arg("target", "int", "Target qubit index") .ret("Gate", "CX gate instance") @@ -605,8 +662,10 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "control"_a, "target"_a, DocString() - .desc("Generate general Gate class instance of CNot.") - .desc("Performs controlled-X operation.") + .desc("Generate general :class:`~f64.Gate` class instance of CNotGate. Performs " + "controlled-X operation.") + .note("CNot is an alias of CX. If you need to use functions specific to the CNotGate " + "class, please downcast it.") .arg("control", "int", "Control qubit index") .arg("target", "int", "Target qubit index") .ret("Gate", "CNot gate instance") @@ -619,8 +678,10 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "control"_a, "target"_a, DocString() - .desc("Generate general Gate class instance of CZ.") - .desc("Performs controlled-Z operation.") + .desc("Generate general :class:`~f64.Gate` class instance of CZGate. Performs " + "controlled-Z operation.") + .note("If you need to use functions specific to the CZGate class, please " + "downcast it.") .arg("control", "int", "Control qubit index") .arg("target", "int", "Target qubit index") .ret("Gate", "CZ gate instance") @@ -634,8 +695,10 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "control2"_a, "target"_a, DocString() - .desc("Generate general Gate class instance of CCX.") - .desc("Performs controlled-controlled-X operation.") + .desc("Generate general :class:`~f64.Gate` class instance of CCXGate. Performs " + "controlled-controlled-X operation.") + .note("If you need to use functions specific to the CCXGate class, please " + "downcast it.") .arg("control1", "int", "First control qubit index") .arg("control2", "int", "Second control qubit index") .arg("target", "int", "Target qubit index") @@ -651,8 +714,10 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "control2"_a, "target"_a, DocString() - .desc("Generate general Gate class instance of CCNot.") - .desc("Performs controlled-controlled-X operation.") + .desc("Generate general :class:`~f64.Gate` class instance of CCNotGate. Performs " + "controlled-controlled-X operation.") + .note("CCNot is an alias of CCX. If you need to use functions specific to the " + "CCNotGate class, please downcast it.") .arg("control1", "int", "First control qubit index") .arg("control2", "int", "Second control qubit index") .arg("target", "int", "Target qubit index") @@ -669,9 +734,10 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { "control2"_a, "target"_a, DocString() - .desc("Toffoli is an alias of CCX.") - .desc("Generate general Gate class instance of Toffoli.") - .desc("Performs controlled-controlled-X operation.") + .desc("Generate general :class:`~f64.Gate` class instance of ToffoliGate. Performs " + "controlled-controlled-X operation.") + .note("Toffoli is an alias of CCX. If you need to use functions specific to the " + "ToffoliGate class, please downcast it.") .arg("control1", "int", "First control qubit index") .arg("control2", "int", "Second control qubit index") .arg("target", "int", "Target qubit index") @@ -681,92 +747,112 @@ void bind_gate_gate_factory_hpp(nb::module_& mgate) { ">>> gate = Toffoli(1, 2, 3) # Toffoli gate with controls on qubits 1 and 2"})) .build_as_google_style() .c_str()); - mgate.def("DenseMatrix", - &gate::DenseMatrix, - "targets"_a, - "matrix"_a, - "controls"_a = std::vector{}, - "is_unitary"_a = false, - DocString() - .desc("Generate general Gate class instance of DenseMatrix.") - .desc("Performs dense matrix operation.") - .arg("targets", "list[int]", "Target qubit indices") - .arg("matrix", "numpy.ndarray", "Matrix to be applied") - .arg("controls", "list[int]", true, "Control qubit indices") - .arg("is_unitary", "bool", true, "Whether the matrix is unitary") - .ret("Gate", "DenseMatrix gate instance") - .ex(DocString::Code( - {">>> matrix = np.array([[1, 0], [0, 1]])", - ">>> gate = DenseMatrix([0], matrix)", - ">>> gate = DenseMatrix([0], matrix, [1]) # Controlled-DenseMatrix"})) - .build_as_google_style() - .c_str()); - mgate.def("SparseMatrix", - &gate::SparseMatrix, - "targets"_a, - "matrix"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate general Gate class instance of SparseMatrix.") - .desc("Performs sparse matrix operation.") - .arg("targets", "list[int]", "Target qubit indices") - .arg("matrix", "scipy.sparse.csr_matrix", "Matrix to be applied") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "SparseMatrix gate instance") - .ex(DocString::Code( - {">>> matrix = scipy.sparse.csr_matrix([[1, 0], [0, 1]])", - ">>> gate = SparseMatrix([0], matrix)", - ">>> gate = SparseMatrix([0], matrix, [1]) # Controlled-SparseMatrix"})) - .build_as_google_style() - .c_str()); + mgate.def( + "DenseMatrix", + &gate::DenseMatrix, + "targets"_a, + "matrix"_a, + "controls"_a = std::vector{}, + "is_unitary"_a = false, + DocString() + .desc("Generate general :class:`~f64.Gate` class instance of " + ":class:`~f64.DenseMatrixGate`. Performs dense matrix operation.") + .note("If you need to use functions specific to the :class:`~f64.DenseMatrixGate` " + "class, please downcast it.") + .arg("targets", "list[int]", "Target qubit indices") + .arg("matrix", "numpy.ndarray", "Matrix to be applied") + .arg("controls", "list[int]", true, "Control qubit indices") + .arg("is_unitary", + "bool", + true, + "Whether the matrix is unitary. When the flag indicating that the gate is " + "unitary is set to True, a more efficient implementation is used.") + .ret("Gate", "DenseMatrix gate instance") + .ex(DocString::Code( + {">>> matrix = np.array([[1, 0], [0, 1]])", + ">>> gate = DenseMatrix([0], matrix)", + ">>> gate = DenseMatrix([0], matrix, [1]) # Controlled-DenseMatrix"})) + .build_as_google_style() + .c_str()); + mgate.def( + "SparseMatrix", + &gate::SparseMatrix, + "targets"_a, + "matrix"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate general :class:`~f64.Gate` class instance of " + ":class:`~f64.SparseMatrixGate`. Performs sparse matrix operation.") + .note("If you need to use functions specific to the :class:`~f64.SparseMatrixGate` " + "class, please downcast it.") + .arg("targets", "list[int]", "Target qubit indices") + .arg("matrix", "scipy.sparse.csr_matrix", "Matrix to be applied") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "SparseMatrix gate instance") + .ex(DocString::Code( + {">>> matrix = scipy.sparse.csr_matrix([[1, 0], [0, 1]])", + ">>> gate = SparseMatrix([0], matrix)", + ">>> gate = SparseMatrix([0], matrix, [1]) # Controlled-SparseMatrix"})) + .build_as_google_style() + .c_str()); mgate.def("Pauli", &gate::Pauli, "pauli"_a, "controls"_a = std::vector{}, DocString() - .desc("Generate general Gate class instance of Pauli.") - .desc("Performs Pauli operation.") + .desc("Generate general :class:`~f64.Gate` class instance of " + ":class:`~f64.PauliGate`. Performs Pauli operation.") + .note("If you need to use functions specific to the :class:`~f64.PauliGate` " + "class, please downcast it.") .arg("pauli", "PauliOperator", "Pauli operator") .arg("controls", "list[int]", true, "Control qubit indices") .ret("Gate", "Pauli gate instance") - .ex(DocString::Code({">>> pauli = PauliOperator('X', 0)", + .ex(DocString::Code({">>> pauli = PauliOperator('X 0')", ">>> gate = Pauli(pauli)", ">>> gate = Pauli(pauli, [1]) # Controlled-Pauli"})) .build_as_google_style() .c_str()); - mgate.def("PauliRotation", - &gate::PauliRotation, - "pauli"_a, - "angle"_a, - "controls"_a = std::vector{}, - DocString() - .desc("Generate general Gate class instance of PauliRotation.") - .desc("Performs Pauli rotation operation.") - .arg("pauli", "PauliOperator", "Pauli operator") - .arg("angle", "float", "Rotation angle in radians") - .arg("controls", "list[int]", true, "Control qubit indices") - .ret("Gate", "PauliRotation gate instance") - .ex(DocString::Code( - {">>> pauli = PauliOperator('X', 0)", - ">>> gate = PauliRotation(pauli, math.pi/2)", - ">>> gate = PauliRotation(pauli, math.pi/2, [1]) # Controlled-Pauli"})) - .build_as_google_style() - .c_str()); - mgate.def("Probablistic", - &gate::Probablistic, - "distribution"_a, - "gate_list"_a, - DocString() - .desc("Generate general Gate class instance of Probablistic.") - .desc("Performs probablistic operation.") - .arg("distribution", "list[float]", "Probablistic distribution") - .arg("gate_list", "list[Gate]", "List of gates") - .ret("Gate", "Probablistic gate instance") - .ex(DocString::Code({">>> distribution = [0.5, 0.5]", - ">>> gate_list = [X(0), Y(0)]", - ">>> gate = Probablistic(distribution, gate_list)"})) - .build_as_google_style() - .c_str()); + mgate.def( + "PauliRotation", + &gate::PauliRotation, + "pauli"_a, + "angle"_a, + "controls"_a = std::vector{}, + DocString() + .desc("Generate general :class:`~f64.Gate` class instance of " + ":class:`~f64.PauliRotationGate`. Performs Pauli rotation operation.") + .note("If you need to use functions specific to the :class:`~f64.PauliRotationGate` " + "class, please downcast it.") + .arg("pauli", "PauliOperator", "Pauli operator") + .arg("angle", "float", "Rotation angle in radians") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "PauliRotation gate instance") + .ex(DocString::Code( + {">>> pauli = PauliOperator('X', 0)", + ">>> gate = PauliRotation(pauli, math.pi/2)", + ">>> gate = PauliRotation(pauli, math.pi/2, [1]) # Controlled-Pauli"})) + .build_as_google_style() + .c_str()); + mgate.def( + "Probablistic", + &gate::Probablistic, + "distribution"_a, + "gate_list"_a, + DocString() + .desc("Generate general :class:`~f64.Gate` class instance of " + ":class:`~f64.ProbablisticGate`. Performs probablistic operation.") + .note("If you need to use functions specific to the :class:`~f64.ProbablisticGate` " + "class, please downcast it.") + .arg("distribution", "list[float]", "Probablistic distribution") + .arg("gate_list", "list[Gate]", "List of gates") + .ret("Gate", "Probablistic gate instance") + .ex(DocString::Code( + {">>> distribution = [0.3, 0.7]", + ">>> gate_list = [X(0), Y(0)]", + ">>> # X is applied with probability 0.3, Y is applied with probability 0.7", + ">>> gate = Probablistic(distribution, gate_list)"})) + .build_as_google_style() + .c_str()); } } // namespace internal #endif diff --git a/include/scaluq/gate/gate_standard.hpp b/include/scaluq/gate/gate_standard.hpp index 05de3e6..3971b50 100644 --- a/include/scaluq/gate/gate_standard.hpp +++ b/include/scaluq/gate/gate_standard.hpp @@ -784,11 +784,11 @@ void bind_gate_gate_standard_hpp(nb::module_& m) { DEF_GATE(SqrtYdagGate, Fp, "Specific class of inverse of sqrt(Y) gate."); DEF_GATE(P0Gate, Fp, - "Specific class of projection gate to $\\ket{0}$.\n\n.. note:: This gate is " + "Specific class of projection gate to $\\ket{0}$.\n\nNotes:\n\tThis gate is " "not unitary."); DEF_GATE(P1Gate, Fp, - "Specific class of projection gate to $\\ket{1}$.\n\n.. note:: This gate is " + "Specific class of projection gate to $\\ket{1}$.\n\nNotes:\n\tThis gate is " "not unitary."); #define DEF_ROTATION_GATE(GATE_TYPE, FLOAT, DESCRIPTION) \ diff --git a/include/scaluq/gate/param_gate.hpp b/include/scaluq/gate/param_gate.hpp index cbdacb7..44760be 100644 --- a/include/scaluq/gate/param_gate.hpp +++ b/include/scaluq/gate/param_gate.hpp @@ -232,6 +232,8 @@ namespace internal { [](const PARAM_GATE_TYPE& param_gate, \ StateVector& state_vector, \ FLOAT param) { param_gate->update_quantum_state(state_vector, param); }, \ + "state"_a, \ + "param"_a, \ "Apply gate to `state_vector` with holding the parameter. `state_vector` in args is " \ "directly updated.") \ .def( \ @@ -239,6 +241,8 @@ namespace internal { [](const PARAM_GATE_TYPE& param_gate, \ StateVectorBatched& states, \ std::vector params) { param_gate->update_quantum_state(states, params); }, \ + "states"_a, \ + "params"_a, \ "Apply gate to `states` with holding the parameter. `states` in args is directly " \ "updated.") \ .def( \ @@ -246,6 +250,7 @@ namespace internal { [](const PARAM_GATE_TYPE& gate, FLOAT param) { \ return gate->get_matrix(param); \ }, \ + "param"_a, \ "Get matrix representation of the gate with holding the parameter.") \ .def( \ "to_string", \ @@ -264,6 +269,7 @@ namespace internal { [](PARAM_GATE_TYPE& gate, const std::string& str) { \ gate = nlohmann::json::parse(str); \ }, \ + "json_str"_a, \ "Read an object from the JSON representation of the gate.") template @@ -271,12 +277,13 @@ nb::class_> param_gate_base_def; #define DEF_PARAM_GATE(PARAM_GATE_TYPE, FLOAT, DESCRIPTION) \ ::scaluq::internal::param_gate_base_def.def(nb::init>(), \ + "param_gate"_a, \ "Upcast from `" #PARAM_GATE_TYPE "`."); \ DEF_PARAM_GATE_BASE( \ PARAM_GATE_TYPE, \ FLOAT, \ DESCRIPTION \ - "\n\n.. note:: Upcast is required to use gate-general functions (ex: add to Circuit).") \ + "\n\nNotes:\n\tUpcast is required to use gate-general functions (ex: add to Circuit).") \ .def(nb::init>()) void bind_gate_param_gate_hpp_without_precision(nb::module_& m) { @@ -293,7 +300,7 @@ void bind_gate_param_gate_hpp(nb::module_& m) { DEF_PARAM_GATE_BASE( ParamGate, Fp, - "General class of parametric quantum gate.\n\n.. note:: Downcast to requred to use " + "General class of parametric quantum gate.\n\nNotes:\n\tDowncast to required to use " "gate-specific functions.") .def(nb::init>(), "Just copy shallowly."); } diff --git a/include/scaluq/gate/param_gate_factory.hpp b/include/scaluq/gate/param_gate_factory.hpp index 1031d61..a8cc5bf 100644 --- a/include/scaluq/gate/param_gate_factory.hpp +++ b/include/scaluq/gate/param_gate_factory.hpp @@ -58,28 +58,68 @@ template void bind_gate_param_gate_factory(nb::module_& mgate) { mgate.def("ParamRX", &gate::ParamRX, - "Generate general ParamGate class instance of ParamRX.", "target"_a, "coef"_a = 1., - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general ParamGate class instance of ParamRX.") + .arg("target", "int", "tTarget qubit index") + .arg("coef", "float", true, "Parameter coefficient") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "ParamRX gate instance") + .ex(DocString::Code({">>> gate = ParamRX(0) # ParamRX gate on qubit 0", + ">>> gate = ParamRX(1, [0]) # Controlled-ParamRX"})) + .build_as_google_style() + .c_str()); mgate.def("ParamRY", &gate::ParamRY, - "Generate general ParamGate class instance of ParamRY.", "target"_a, "coef"_a = 1., - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general ParamGate class instance of ParamRY.") + .arg("target", "int", "Target qubit index") + .arg("coef", "float", true, "Parameter coefficient") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "ParamRY gate instance") + .ex(DocString::Code({">>> gate = ParamRY(0) # ParamRY gate on qubit 0", + ">>> gate = ParamRY(1, [0]) # Controlled-ParamRY"})) + .build_as_google_style() + .c_str()); mgate.def("ParamRZ", &gate::ParamRZ, "Generate general ParamGate class instance of ParamRZ.", "target"_a, "coef"_a = 1., - "controls"_a = std::vector{}); - mgate.def("ParamPauliRotation", - &gate::ParamPauliRotation, - "Generate general ParamGate class instance of ParamPauliRotation.", - "pauli"_a, - "coef"_a = 1., - "controls"_a = std::vector{}); + "controls"_a = std::vector{}, + DocString() + .desc("Generate general ParamGate class instance of ParamRZ.") + .arg("target", "int", "Target qubit index") + .arg("coef", "float", true, "Parameter coefficient") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "ParamRZ gate instance") + .ex(DocString::Code({">>> gate = ParamRZ(0) # ParamRZ gate on qubit 0", + ">>> gate = ParamRZ(1, [0]) # Controlled-ParamRZ"})) + .build_as_google_style() + .c_str()); + mgate.def( + "ParamPauliRotation", + &gate::ParamPauliRotation, + "pauli"_a, + "coef"_a = 1., + "controls"_a = std::vector{}, + DocString() + .desc("Generate general ParamGate class instance of ParamPauliRotation.") + .arg("pauli", "PauliOperator", "Pauli operator") + .arg("coef", "float", true, "Parameter coefficient") + .arg("controls", "list[int]", true, "Control qubit indices") + .ret("Gate", "ParamPauliRotation gate instance") + .ex(DocString::Code({">>> gate = ParamPauliRotation(PauliOperator(), 0.5) # Pauli " + "rotation gate with PauliOperator and coefficient 0.5", + ">>> gate = ParamPauliRotation(PauliOperator(), 0.5, [0]) # " + "Controlled-ParamPauliRotation"})) + .build_as_google_style() + .c_str()); mgate.def("ParamProbablistic", &gate::ParamProbablistic, "Generate general ParamGate class instance of ParamProbablistic."); @@ -97,7 +137,16 @@ void bind_gate_param_gate_factory(nb::module_& mgate) { } return gate::ParamProbablistic(distribution, gate_list); }, - "Generate general ParamGate class instance of ParamProbablistic."); + DocString() + .desc("Generate general ParamGate class instance of ParamProbablistic.") + .arg("prob_gate_list", + "list[tuple[float, Union[Gate, ParamGate]]]", + "List of tuple of probability and gate") + .ret("Gate", "ParamProbablistic gate instance") + .ex(DocString::Code({">>> gate = ParamProbablistic([(0.1, X(0)), (0.9, I(0))]) # " + "Probablistic gate with X and I"})) + .build_as_google_style() + .c_str()); } } // namespace internal #endif diff --git a/include/scaluq/operator/operator.hpp b/include/scaluq/operator/operator.hpp index 8f627bf..87a2c2d 100644 --- a/include/scaluq/operator/operator.hpp +++ b/include/scaluq/operator/operator.hpp @@ -116,6 +116,7 @@ void bind_operator_operator_hpp(nb::module_& m) { .def("to_string", &Operator::to_string, "Get string representation of the operator.") .def("add_operator", nb::overload_cast&>(&Operator::add_operator), + "pauli"_a, "Add a Pauli operator to this operator.") .def( "add_random_operator", @@ -134,12 +135,16 @@ void bind_operator_operator_hpp(nb::module_& m) { "Get the adjoint (Hermitian conjugate) of the operator.") .def("apply_to_state", &Operator::apply_to_state, + "state"_a, "Apply the operator to a state vector.") .def("get_expectation_value", &Operator::get_expectation_value, + "state"_a, "Get the expectation value of the operator with respect to a state vector.") .def("get_transition_amplitude", &Operator::get_transition_amplitude, + "source"_a, + "target"_a, "Get the transition amplitude of the operator between two state vectors.") .def(nb::self *= Complex()) .def(nb::self * Complex()) @@ -164,6 +169,7 @@ void bind_operator_operator_hpp(nb::module_& m) { .def( "load_json", [](Operator& op, const std::string& str) { op = nlohmann::json::parse(str); }, + "json_str"_a, "Read an object from the JSON representation of the operator."); } } // namespace internal diff --git a/include/scaluq/operator/pauli_operator.hpp b/include/scaluq/operator/pauli_operator.hpp index e76a045..7e30aa1 100644 --- a/include/scaluq/operator/pauli_operator.hpp +++ b/include/scaluq/operator/pauli_operator.hpp @@ -53,7 +53,7 @@ class PauliOperator { std::shared_ptr _ptr; public: - enum PauliID : std::uint64_t { PAULI_I, PAULI_X, PAULI_Y, PAULI_Z }; + enum PauliID : std::uint64_t { I, X, Y, Z }; explicit PauliOperator(Complex coef = 1.) : _ptr(std::make_shared(coef)) {} explicit PauliOperator(Data data) : _ptr(std::make_shared(data)) {} @@ -110,13 +110,6 @@ class PauliOperator { namespace internal { template void bind_operator_pauli_operator_hpp(nb::module_& m) { - auto pauli_enum = nb::enum_::PauliID>( - m, "PauliID", "Enumeration for Pauli operations.") - .value("PAULI_I", PauliOperator::PAULI_I) - .value("PAULI_X", PauliOperator::PAULI_X) - .value("PAULI_Y", PauliOperator::PAULI_Y) - .value("PAULI_Z", PauliOperator::PAULI_Z); - nb::class_::Data>( m, "PauliOperatorData", "Internal data structure for PauliOperator.") .def(nb::init>(), "coef"_a = 1., "Initialize data with coefficient.") @@ -170,13 +163,13 @@ void bind_operator_pauli_operator_hpp(nb::module_& m) { .desc("Given `target_qubit_list: std::vector, pauli_id_list: " "std::vector, coef: Complex`, Initialize pauli operator. For " "each `i`, single pauli correspond to `pauli_id_list[i]` is applied to " - "`target_qubit_list`-th qubit.") + "`target_qubit_list[i]`-th qubit.") .desc("Given `pauli_string: std::string_view, coef: Complex`, Initialize pauli " "operator. For each `i`, single pauli correspond to `pauli_id_list[i]` is " - "applied to `target_qubit_list`-th qubit.") + "applied to `target_qubit_list[i]`-th qubit.") .desc("Given `pauli_id_par_qubit: std::vector, coef: Complex`, " "Initialize pauli operator. For each `i`, single pauli correspond to " - "`paul_id_per_qubit` is applied to `i`-th qubit.") + "`paul_id_per_qubit[i]` is applied to `i`-th qubit.") .desc("Given `bit_flip_mask: std::uint64_t, phase_flip_mask: std::uint64_t, coef: " "Complex`, Initialize pauli operator. For each `i`, single pauli applied to " "`i`-th qubit is " @@ -201,7 +194,7 @@ void bind_operator_pauli_operator_hpp(nb::module_& m) { "pauli_id_list"_a, "coef"_a = 1., "Initialize pauli operator. For each `i`, single pauli correspond to " - "`pauli_id_list[i]` is applied to `target_qubit_list`-th qubit.") + "`pauli_id_list[i]` is applied to `target_qubit_list[i]`-th qubit.") .def(nb::init>(), "pauli_string"_a, "coef"_a = 1., @@ -212,7 +205,7 @@ void bind_operator_pauli_operator_hpp(nb::module_& m) { "pauli_id_par_qubit"_a, "coef"_a = 1., "Initialize pauli operator. For each `i`, single pauli correspond to " - "`paul_id_per_qubit` is applied to `i`-th qubit.") + "`paul_id_per_qubit[i]` is applied to `i`-th qubit.") .def(nb::init>(), "bit_flip_mask"_a, "phase_flip_mask"_a, @@ -245,12 +238,18 @@ void bind_operator_pauli_operator_hpp(nb::module_& m) { &PauliOperator::get_qubit_count, "Get num of qubits to applied with, when count from 0-th qubit. Subset of $[0, " "\\mathrm{qubit_count})$ is the target.") - .def("apply_to_state", &PauliOperator::apply_to_state, "Apply pauli to state vector.") + .def("apply_to_state", + &PauliOperator::apply_to_state, + "state"_a, + "Apply pauli to state vector.") .def("get_expectation_value", &PauliOperator::get_expectation_value, + "state"_a, "Get expectation value of measuring state vector. $\\bra{\\psi}P\\ket{\\psi}$.") .def("get_transition_amplitude", &PauliOperator::get_transition_amplitude, + "source"_a, + "target"_a, "Get transition amplitude of measuring state vector. $\\bra{\\chi}P\\ket{\\psi}$.") .def(nb::self * nb::self) .def(nb::self * Complex()) @@ -263,6 +262,7 @@ void bind_operator_pauli_operator_hpp(nb::module_& m) { [](PauliOperator& pauli, const std::string& str) { pauli = nlohmann::json::parse(str); }, + "json_str"_a, "Read an object from the JSON representation of the Pauli operator."); } } // namespace internal diff --git a/include/scaluq/state/state_vector.hpp b/include/scaluq/state/state_vector.hpp index a3d8292..a47db03 100644 --- a/include/scaluq/state/state_vector.hpp +++ b/include/scaluq/state/state_vector.hpp @@ -519,6 +519,7 @@ void bind_state_state_vector_hpp(nb::module_& m) { [](StateVector& state, const std::string& str) { state = nlohmann::json::parse(str); }, + "json_str"_a, DocString() .desc("Read an object from the JSON representation of the state vector.") .build_as_google_style() diff --git a/src/operator/pauli_operator.cpp b/src/operator/pauli_operator.cpp index 4cec5d4..041b61a 100644 --- a/src/operator/pauli_operator.cpp +++ b/src/operator/pauli_operator.cpp @@ -18,10 +18,10 @@ PauliOperator::Data::Data(std::string_view pauli_string, Complex coef) throw std::runtime_error("PauliOperator::PauliOperator: invalid pauli_string format"); } std::uint64_t pauli_id = [&] { - if (pauli == 'I' || pauli == 'i') return PauliOperator::PAULI_I; - if (pauli == 'X' || pauli == 'x') return PauliOperator::PAULI_X; - if (pauli == 'Y' || pauli == 'y') return PauliOperator::PAULI_Y; - if (pauli == 'Z' || pauli == 'z') return PauliOperator::PAULI_Z; + if (pauli == 'I' || pauli == 'i') return PauliOperator::I; + if (pauli == 'X' || pauli == 'x') return PauliOperator::X; + if (pauli == 'Y' || pauli == 'y') return PauliOperator::Y; + if (pauli == 'Z' || pauli == 'z') return PauliOperator::Z; throw std::runtime_error("PauliOperator::PauliOperator: invalid pauli_string format"); }(); if (pauli_id != 0) add_single_pauli(target, pauli_id); @@ -50,7 +50,7 @@ PauliOperator::Data::Data(const std::vector& pauli_id_par_qub Complex coef) : _coef(coef), _bit_flip_mask(0), _phase_flip_mask(0) { for (std::uint64_t i = 0; i < pauli_id_par_qubit.size(); ++i) { - if (pauli_id_par_qubit[i] != PauliOperator::PAULI_I) { + if (pauli_id_par_qubit[i] != PauliOperator::I) { add_single_pauli(i, pauli_id_par_qubit[i]); } } @@ -96,10 +96,10 @@ void PauliOperator::Data::add_single_pauli(std::uint64_t target_qubit, std:: "same " "qubit."); } - if (pauli_id == PauliOperator::PAULI_X || pauli_id == PauliOperator::PAULI_Y) { + if (pauli_id == PauliOperator::X || pauli_id == PauliOperator::Y) { _bit_flip_mask |= 1ULL << target_qubit; } - if (pauli_id == PauliOperator::PAULI_Y || pauli_id == PauliOperator::PAULI_Z) { + if (pauli_id == PauliOperator::Y || pauli_id == PauliOperator::Z) { _phase_flip_mask |= 1ULL << target_qubit; } }