diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index e17c9e2..8d49a60 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -102,6 +102,7 @@ endfunction() add_application(circuit_test circuit_test.cpp) add_application(observable_test observable_test.cpp) add_application(target_test target_test.cpp) +add_application(parameterized_circuit_test parameterized_circuit_test.cpp) if(QRMI_ROOT OR QISKIT_IBM_RUNTIME_C_ROOT OR SQC_ROOT) add_application(sampler_test sampler_test.cpp) diff --git a/samples/parameterized_circuit_test.cpp b/samples/parameterized_circuit_test.cpp new file mode 100644 index 0000000..d29eb5a --- /dev/null +++ b/samples/parameterized_circuit_test.cpp @@ -0,0 +1,53 @@ +/* +# This code is part of Qiskit. +# +# (C) Copyright IBM 2024. 2026. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +*/ + +// Test parameterized circuit of Qiskit C++ + +#define _USE_MATH_DEFINES +#include +#include +#include +#include + +#include "circuit/quantumcircuit.hpp" + +using namespace Qiskit::circuit; + +int main() +{ + QuantumRegister qr(4); + ClassicalRegister cr(4); + QuantumCircuit circ(qr, cr); + + Parameter theta("t"); + Parameter a = theta + 0.5; + + circ.h(0); + circ.rx(a, 1); + + circ.measure(qr, cr); + + circ.print(); + + circ.draw(); + + + Parameter p1 = Parameter(M_PI/2.0); + Parameter p2 = Parameter(M_PI/2.0); + std::cout << (p1 == p2) << std::endl; + + + return 0; +} + diff --git a/samples/target_test.cpp b/samples/target_test.cpp index 07e6f33..52f9dee 100644 --- a/samples/target_test.cpp +++ b/samples/target_test.cpp @@ -43,7 +43,7 @@ int main() } std::cout << "input circuit" << std::endl; - circ.print(); + circ.draw(); auto target = Target({"h", "cx"}, {{0, 1}, {1, 0}, {1, 3}, {3, 1}, {0, 2}, {2, 0}, {2, 3}, {3, 2}}); @@ -53,7 +53,7 @@ int main() auto transpiled = pass.run(circ); std::cout << "transpiled circuit" << std::endl; - transpiled.print(); + transpiled.draw(); return 0; } diff --git a/src/circuit/instruction.hpp b/src/circuit/instruction.hpp index 7488a04..71cddfb 100644 --- a/src/circuit/instruction.hpp +++ b/src/circuit/instruction.hpp @@ -38,7 +38,7 @@ class Instruction { std::string name_; uint_t num_qubits_; uint_t num_clbits_; - std::vector params_; + std::vector params_; std::string label_; QkGate map_ = QkGate_I; bool is_standard_gate_ = false; @@ -107,14 +107,14 @@ class Instruction { /// @brief Return parameters of the instruction /// @return parameters of the instruction - const std::vector& params(void) const + const std::vector& params(void) const { return params_; } /// @brief set parameters to the instruction /// @param parameters to be set - void set_params(const std::vector& params) + void set_params(const std::vector& params) { params_ = params; } diff --git a/src/circuit/parameter.hpp b/src/circuit/parameter.hpp index 8c203c9..1164599 100644 --- a/src/circuit/parameter.hpp +++ b/src/circuit/parameter.hpp @@ -93,7 +93,7 @@ class Parameter /// @brief get string expression of the Parameter /// @return a string expression of the Parameter - std::string as_str(void) + std::string as_str(void) const { char* str = qk_param_str(qiskit_param_.get()); std::string ret = str; @@ -329,6 +329,25 @@ class Parameter return !qk_param_equal(qiskit_param_.get(), rhs.qiskit_param_.get()); } + + /// @brief compare the Parameter with a scalar + /// @param rhs a scalar to be compared + /// @return true if 2 are equal + bool operator==(const double rhs) const + { + Parameter r(rhs); + return *this == r; + } + + /// @brief compare the Parameter with a scalar + /// @param rhs a scalar to be compared + /// @return true if 2 are not equal + bool operator!=(const double rhs) const + { + Parameter r(rhs); + return *this != r; + } + /// @brief calculate exponent of this Parameter /// @return a new Parameter for the result Parameter exp(void) @@ -453,6 +472,9 @@ class Parameter /// @return a new substituted Parameter Parameter subs(const std::vector& symbols, const std::vector& others); #endif + + friend std::ostream& operator<<(std::ostream& os, const Parameter& p); + }; #ifdef QISKIT_CAPI_HAS_SUBS @@ -502,9 +524,14 @@ Parameter Parameter::subs(const std::vector& symbol, const std::vecto } #endif +std::ostream& operator<<(std::ostream& os, const Parameter& p) +{ + os << p.as_str(); + return os; +} -} // namespace circuit +} // namespace circui } // namespace Qiskit #endif // __qiskitcpp_circuit_parameter_hpp__ diff --git a/src/circuit/quantumcircuit_def.hpp b/src/circuit/quantumcircuit_def.hpp index 6083330..e08cf96 100644 --- a/src/circuit/quantumcircuit_def.hpp +++ b/src/circuit/quantumcircuit_def.hpp @@ -689,6 +689,8 @@ class QuantumCircuit /// @brief print circuit (this is for debug) void print(void) const; + /// @brief draw the circuit + void draw(void) const; /// @brief compare two circuits /// @param other a circuit to be compared with this circuit diff --git a/src/circuit/quantumcircuit_impl.hpp b/src/circuit/quantumcircuit_impl.hpp index 1e2c537..770cca6 100644 --- a/src/circuit/quantumcircuit_impl.hpp +++ b/src/circuit/quantumcircuit_impl.hpp @@ -168,8 +168,7 @@ void QuantumCircuit::set_qiskit_circuit(std::shared_ptr circ, cons num_clbits_ = qk_circuit_num_clbits(circ.get()); qubit_map_.resize(map.size()); - for (int i = 0; i < map.size(); i++) - { + for (int i = 0; i < map.size(); i++) { qubit_map_[i] = (uint_t)map[i]; } @@ -177,15 +176,14 @@ void QuantumCircuit::set_qiskit_circuit(std::shared_ptr circ, cons uint_t nops; nops = qk_circuit_num_instructions(rust_circuit_.get()); - for (uint_t i = 0; i < nops; i++) - { - QkCircuitInstruction *op = new QkCircuitInstruction; - qk_circuit_get_instruction(rust_circuit_.get(), i, op); - if (strcmp(op->name, "measure") == 0) - { + for (uint_t i = 0; i < nops; i++) { + QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); + if (kind == QkOperationKind_Measure) { + QkCircuitInstruction *op = new QkCircuitInstruction; + qk_circuit_get_instruction(rust_circuit_.get(), i, op); measure_map_.push_back(std::pair((uint_t)op->qubits[0], (uint_t)op->clbits[0])); + qk_circuit_instruction_clear(op); } - qk_circuit_instruction_clear(op); } } @@ -278,10 +276,10 @@ void QuantumCircuit::p(const double phase, const uint_t qubit) void QuantumCircuit::p(const Parameter &phase, const uint_t qubit) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit}; + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {phase.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_p(rust_circuit_.get(), theta.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_Phase, qubits, params); } void QuantumCircuit::r(const double theta, const double phi, const uint_t qubit) @@ -294,10 +292,10 @@ void QuantumCircuit::r(const double theta, const double phi, const uint_t qubit) void QuantumCircuit::r(const Parameter &theta, const Parameter &phi, const uint_t qubit) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit}; + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_r(rust_circuit_.get(), theta.expr_, phi.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_R, qubits, params); } void QuantumCircuit::rx(const double theta, const uint_t qubit) @@ -309,10 +307,10 @@ void QuantumCircuit::rx(const double theta, const uint_t qubit) void QuantumCircuit::rx(const Parameter &theta, const uint_t qubit) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit}; + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_rx(rust_circuit_.get(), theta.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RX, qubits, params); } void QuantumCircuit::ry(const double theta, const uint_t qubit) @@ -324,10 +322,10 @@ void QuantumCircuit::ry(const double theta, const uint_t qubit) void QuantumCircuit::ry(const Parameter &theta, const uint_t qubit) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit}; + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_ry(rust_circuit_.get(), theta.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RY, qubits, params); } void QuantumCircuit::rz(const double theta, const uint_t qubit) @@ -339,10 +337,10 @@ void QuantumCircuit::rz(const double theta, const uint_t qubit) void QuantumCircuit::rz(const Parameter &theta, const uint_t qubit) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit}; + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_rz(rust_circuit_.get(), theta.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RZ, qubits, params); } void QuantumCircuit::s(const uint_t qubit) @@ -397,10 +395,10 @@ void QuantumCircuit::u(const double theta, const double phi, const double lam, c void QuantumCircuit::u(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t qubit) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit}; + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_u(rust_circuit_.get(), theta.expr_, phi.expr_, lam.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U, qubits, params); } void QuantumCircuit::u1(const double theta, const uint_t qubit) @@ -413,10 +411,10 @@ void QuantumCircuit::u1(const double theta, const uint_t qubit) void QuantumCircuit::u1(const Parameter &theta, const uint_t qubit) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit}; + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_u(rust_circuit_.get(), theta.expr_, phi.expr_, lam.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U1, qubits, params); } void QuantumCircuit::u2(const double phi, const double lam, const uint_t qubit) @@ -429,10 +427,10 @@ void QuantumCircuit::u2(const double phi, const double lam, const uint_t qubit) void QuantumCircuit::u2(const Parameter &phi, const Parameter &lam, const uint_t qubit) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit}; + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {phi.qiskit_param_.get(), lam.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_u(rust_circuit_.get(), theta.expr_, phi.expr_, lam.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U2, qubits, params); } void QuantumCircuit::u3(const double theta, const double phi, const double lam, const uint_t qubit) @@ -445,10 +443,10 @@ void QuantumCircuit::u3(const double theta, const double phi, const double lam, void QuantumCircuit::u3(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t qubit) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit}; + std::uint32_t qubits[] = {(std::uint32_t)qubit}; + QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_u(rust_circuit_.get(), theta.expr_, phi.expr_, lam.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_U3, qubits, params); } void QuantumCircuit::unitary(const std::vector &unitary, const reg_t &qubits) @@ -526,10 +524,10 @@ void QuantumCircuit::cp(const double phase, const uint_t cqubit, const uint_t tq void QuantumCircuit::cp(const Parameter &phase, const uint_t cqubit, const uint_t tqubit) { - // std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {phase.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_p(rust_circuit_.get(), theta.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CPhase, qubits, params); } void QuantumCircuit::crx(const double theta, const uint_t cqubit, const uint_t tqubit) @@ -541,10 +539,10 @@ void QuantumCircuit::crx(const double theta, const uint_t cqubit, const uint_t t void QuantumCircuit::crx(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) { - // std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_p(rust_circuit_.get(), theta.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CRX, qubits, params); } void QuantumCircuit::cry(const double theta, const uint_t cqubit, const uint_t tqubit) @@ -556,10 +554,10 @@ void QuantumCircuit::cry(const double theta, const uint_t cqubit, const uint_t t void QuantumCircuit::cry(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) { - // std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_p(rust_circuit_.get(), theta.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CRY, qubits, params); } void QuantumCircuit::crz(const double theta, const uint_t cqubit, const uint_t tqubit) @@ -571,10 +569,10 @@ void QuantumCircuit::crz(const double theta, const uint_t cqubit, const uint_t t void QuantumCircuit::crz(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) { - // std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_p(rust_circuit_.get(), theta.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CRZ, qubits, params); } void QuantumCircuit::cs(const uint_t cqubit, const uint_t tqubit) @@ -608,10 +606,10 @@ void QuantumCircuit::cu(const double theta, const double phi, const double lam, void QuantumCircuit::cu(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t cqubit, const uint_t tqubit) { - // std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_u(rust_circuit_.get(), theta.expr_, phi.expr_, lam.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CU, qubits, params); } void QuantumCircuit::cu1(const double theta, const uint_t cqubit, const uint_t tqubit) @@ -624,10 +622,10 @@ void QuantumCircuit::cu1(const double theta, const uint_t cqubit, const uint_t t void QuantumCircuit::cu1(const Parameter &theta, const uint_t cqubit, const uint_t tqubit) { - // std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_u(rust_circuit_.get(), theta.expr_, phi.expr_, lam.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CU1, qubits, params); } void QuantumCircuit::cu3(const double theta, const double phi, const double lam, const uint_t cqubit, const uint_t tqubit) @@ -640,10 +638,10 @@ void QuantumCircuit::cu3(const double theta, const double phi, const double lam, void QuantumCircuit::cu3(const Parameter &theta, const Parameter &phi, const Parameter &lam, const uint_t cqubit, const uint_t tqubit) { - // std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + std::uint32_t qubits[] = {(std::uint32_t)cqubit, (std::uint32_t)tqubit}; + QkParam* params[] = {theta.qiskit_param_.get(), phi.qiskit_param_.get(), lam.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_u(rust_circuit_.get(), theta.expr_, phi.expr_, lam.expr_, qubit); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_CU3, qubits, params); } void QuantumCircuit::rxx(const double theta, const uint_t qubit1, const uint_t qubit2) @@ -655,10 +653,10 @@ void QuantumCircuit::rxx(const double theta, const uint_t qubit1, const uint_t q void QuantumCircuit::rxx(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_rzz(rust_circuit_.get(), theta.expr_, qubit1, qubit2); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RXX, qubits, params); } void QuantumCircuit::ryy(const double theta, const uint_t qubit1, const uint_t qubit2) @@ -670,10 +668,10 @@ void QuantumCircuit::ryy(const double theta, const uint_t qubit1, const uint_t q void QuantumCircuit::ryy(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_rzz(rust_circuit_.get(), theta.expr_, qubit1, qubit2); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RYY, qubits, params); } void QuantumCircuit::rzz(const double theta, const uint_t qubit1, const uint_t qubit2) @@ -685,10 +683,10 @@ void QuantumCircuit::rzz(const double theta, const uint_t qubit1, const uint_t q void QuantumCircuit::rzz(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_rzz(rust_circuit_.get(), theta.expr_, qubit1, qubit2); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RZZ, qubits, params); } void QuantumCircuit::rzx(const double theta, const uint_t qubit1, const uint_t qubit2) @@ -700,10 +698,10 @@ void QuantumCircuit::rzx(const double theta, const uint_t qubit1, const uint_t q void QuantumCircuit::rzx(const Parameter &theta, const uint_t qubit1, const uint_t qubit2) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression - // qc_rzz(rust_circuit_.get(), theta.expr_, qubit1, qubit2); + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_RZX, qubits, params); } void QuantumCircuit::xx_minus_yy(const double theta, const double beta, const uint_t qubit1, const uint_t qubit2) @@ -716,9 +714,10 @@ void QuantumCircuit::xx_minus_yy(const double theta, const double beta, const ui void QuantumCircuit::xx_minus_yy(const Parameter &theta, const Parameter &beta, const uint_t qubit1, const uint_t qubit2) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get(), beta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_XXMinusYY, qubits, params); } void QuantumCircuit::xx_plus_yy(const double theta, const double beta, const uint_t qubit1, const uint_t qubit2) @@ -731,9 +730,10 @@ void QuantumCircuit::xx_plus_yy(const double theta, const double beta, const uin void QuantumCircuit::xx_plus_yy(const Parameter &theta, const Parameter &beta, const uint_t qubit1, const uint_t qubit2) { - // std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + std::uint32_t qubits[] = {(std::uint32_t)qubit1, (std::uint32_t)qubit2}; + QkParam* params[] = {theta.qiskit_param_.get(), beta.qiskit_param_.get()}; pre_add_gate(); - // TO DO support parameter expression + qk_circuit_parameterized_gate(rust_circuit_.get(), QkGate_XXPlusYY, qubits, params); } void QuantumCircuit::ccx(const uint_t cqubit1, const uint_t cqubit2, const uint_t tqubit) @@ -864,8 +864,7 @@ IfElseOp &QuantumCircuit::if_test(const std::uint32_t clbit, const std::uint32_t uint_t QuantumCircuit::num_parameters(void) const { - // TO DO : add support for Parameter in Qiskit C-API - return 0; // qc_num_parameters(rust_circuit_); + return qk_circuit_num_param_symbols(rust_circuit_.get()); } void QuantumCircuit::assign_parameters(const std::vector keys, const std::vector values) @@ -937,13 +936,11 @@ void QuantumCircuit::compose(QuantumCircuit &circ, const reg_t &qubits, const re pre_add_gate(); uint_t size = std::min(qubits.size(), clbits.size()); std::vector vqubits(size); - for (uint_t i = 0; i < size; i++) - { + for (uint_t i = 0; i < size; i++) { vqubits[i] = (std::uint32_t)qubits[i]; } std::vector vclbits(size); - for (uint_t i = 0; i < size; i++) - { + for (uint_t i = 0; i < size; i++) { vclbits[i] = (std::uint32_t)clbits[i]; } @@ -951,80 +948,67 @@ void QuantumCircuit::compose(QuantumCircuit &circ, const reg_t &qubits, const re nops = qk_circuit_num_instructions(circ.rust_circuit_.get()); auto name_map = get_standard_gate_name_mapping(); - for (uint_t i = 0; i < nops; i++) - { + for (uint_t i = 0; i < nops; i++) { QkCircuitInstruction *op = new QkCircuitInstruction; qk_circuit_get_instruction(circ.rust_circuit_.get(), i, op); std::vector vqubits(op->num_qubits); std::vector vclbits; - for (uint_t j = 0; j < op->num_qubits; j++) - { + for (uint_t j = 0; j < op->num_qubits; j++) { vqubits[j] = (std::uint32_t)qubits[op->qubits[j]]; } - if (op->num_clbits > 0) - { + if (op->num_clbits > 0) { vclbits.resize(op->num_clbits); - for (uint_t j = 0; j < op->num_clbits; j++) - { + for (uint_t j = 0; j < op->num_clbits; j++) { vclbits[j] = (std::uint32_t)clbits[op->clbits[j]]; } } - - if (std::string("reset") == op->name) - { + QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); + if (kind == QkOperationKind_Measure) { + qk_circuit_measure(rust_circuit_.get(), vqubits[0], vclbits[0]); + } else if (kind == QkOperationKind_Reset) { qk_circuit_reset(rust_circuit_.get(), vqubits[0]); - } - else if (std::string("barrier") == op->name) - { + } else if (kind == QkOperationKind_Barrier) { qk_circuit_barrier(rust_circuit_.get(), vqubits.data(), (uint32_t)vqubits.size()); - } - else if (std::string("measure") == op->name) - { - qk_circuit_measure(rust_circuit_.get(), vqubits[0], vclbits[0]); - } - else - { - qk_circuit_gate(rust_circuit_.get(), name_map[op->name].gate_map(), vqubits.data(), op->params); + } else if (kind == QkOperationKind_Gate) { + qk_circuit_parameterized_gate(rust_circuit_.get(), name_map[op->name].gate_map(), vqubits.data(), op->params); + } else if (kind == QkOperationKind_Unitary) { + // TO DO : how we can get unitary matrix from Rust ? } qk_circuit_instruction_clear(op); } - for (auto m : circ.measure_map_) - { + for (auto m : circ.measure_map_) { measure_map_.push_back(m); } } void QuantumCircuit::append(const Instruction &op, const reg_t &qubits) { - if (op.num_qubits() == qubits.size()) - { + if (op.num_qubits() == qubits.size()) { std::vector vqubits(qubits.size()); - for (uint_t i = 0; i < qubits.size(); i++) - { + for (uint_t i = 0; i < qubits.size(); i++) { vqubits[i] = (std::uint32_t)qubits[i]; } pre_add_gate(); - if (op.is_standard_gate()) - { - if (op.num_params() > 0) - qk_circuit_gate(rust_circuit_.get(), op.gate_map(), vqubits.data(), op.params().data()); + if (op.is_standard_gate()) { + if (op.num_params() > 0) { + std::vector params; + for (auto &p : op.params()) { + params.push_back(p.qiskit_param_.get()); + } + qk_circuit_parameterized_gate(rust_circuit_.get(), op.gate_map(), vqubits.data(), params.data()); + } else qk_circuit_gate(rust_circuit_.get(), op.gate_map(), vqubits.data(), nullptr); - } - else - { - if (std::string("reset") == op.name()) - { + } else { + if (std::string("reset") == op.name()) { qk_circuit_reset(rust_circuit_.get(), vqubits[0]); } - else if (std::string("barrier") == op.name()) - { + else if (std::string("barrier") == op.name()) { qk_circuit_barrier(rust_circuit_.get(), vqubits.data(), (uint32_t)vqubits.size()); } - else if (std::string("measure") == op.name()) - { + else if (std::string("measure") == op.name()) { qk_circuit_measure(rust_circuit_.get(), vqubits[0], vqubits[0]); measure_map_.push_back(std::pair(qubits[0], qubits[0])); } @@ -1034,28 +1018,26 @@ void QuantumCircuit::append(const Instruction &op, const reg_t &qubits) void QuantumCircuit::append(const Instruction &op, const std::vector &qubits) { - if (op.num_qubits() == qubits.size()) - { + if (op.num_qubits() == qubits.size()) { pre_add_gate(); - if (op.is_standard_gate()) - { - if (op.num_params() > 0) - qk_circuit_gate(rust_circuit_.get(), op.gate_map(), qubits.data(), op.params().data()); + if (op.is_standard_gate()) { + if (op.num_params() > 0) { + std::vector params; + for (auto &p : op.params()) { + params.push_back(p.qiskit_param_.get()); + } + qk_circuit_parameterized_gate(rust_circuit_.get(), op.gate_map(), qubits.data(), params.data()); + } else qk_circuit_gate(rust_circuit_.get(), op.gate_map(), qubits.data(), nullptr); - } - else - { - if (std::string("reset") == op.name()) - { + } else { + if (std::string("reset") == op.name()) { qk_circuit_reset(rust_circuit_.get(), qubits[0]); } - else if (std::string("barrier") == op.name()) - { + else if (std::string("barrier") == op.name()) { qk_circuit_barrier(rust_circuit_.get(), qubits.data(), (uint32_t)qubits.size()); } - else if (std::string("measure") == op.name()) - { + else if (std::string("measure") == op.name()) { qk_circuit_measure(rust_circuit_.get(), qubits[0], qubits[0]); measure_map_.push_back(std::pair((uint_t)qubits[0], (uint_t)qubits[0])); } @@ -1066,30 +1048,28 @@ void QuantumCircuit::append(const Instruction &op, const std::vector vqubits(inst.qubits().size()); - for (uint_t i = 0; i < inst.qubits().size(); i++) - { + for (uint_t i = 0; i < inst.qubits().size(); i++) { vqubits[i] = (std::uint32_t)inst.qubits()[i]; } pre_add_gate(); - if (inst.instruction().is_standard_gate()) - { - if (inst.instruction().num_params() > 0) - qk_circuit_gate(rust_circuit_.get(), inst.instruction().gate_map(), vqubits.data(), inst.instruction().params().data()); + if (inst.instruction().is_standard_gate()) { + if (inst.instruction().num_params() > 0) { + std::vector params; + for (auto &p : inst.instruction().params()) { + params.push_back(p.qiskit_param_.get()); + } + qk_circuit_parameterized_gate(rust_circuit_.get(), inst.instruction().gate_map(), vqubits.data(), params.data()); + } else qk_circuit_gate(rust_circuit_.get(), inst.instruction().gate_map(), vqubits.data(), nullptr); - } - else - { - if (std::string("reset") == inst.instruction().name()) - { + } else { + if (std::string("reset") == inst.instruction().name()) { qk_circuit_reset(rust_circuit_.get(), vqubits[0]); } - else if (std::string("barrier") == inst.instruction().name()) - { + else if (std::string("barrier") == inst.instruction().name()) { qk_circuit_barrier(rust_circuit_.get(), vqubits.data(), (uint32_t)vqubits.size()); } - else if (std::string("measure") == inst.instruction().name()) - { + else if (std::string("measure") == inst.instruction().name()) { qk_circuit_measure(rust_circuit_.get(), vqubits[0], (std::uint32_t)inst.clbits()[0]); measure_map_.push_back(std::pair(inst.qubits()[0], inst.clbits()[0])); } @@ -1103,9 +1083,10 @@ uint_t QuantumCircuit::num_instructions(void) CircuitInstruction QuantumCircuit::operator[](uint_t i) { - if (i < qk_circuit_num_instructions(rust_circuit_.get())) - { + if (i < qk_circuit_num_instructions(rust_circuit_.get())) { auto name_map = get_standard_gate_name_mapping(); + + QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); QkCircuitInstruction *op = new QkCircuitInstruction; qk_circuit_get_instruction(rust_circuit_.get(), i, op); reg_t qubits; @@ -1114,52 +1095,43 @@ CircuitInstruction QuantumCircuit::operator[](uint_t i) for (int i = 0; i < op->num_qubits; i++) qubits[i] = op->qubits[i]; } - std::vector params; + + reg_t clbits; + if (op->num_clbits > 0) { + clbits.resize(op->num_clbits); + for (int i = 0; i < op->num_clbits; i++) + clbits[i] = op->clbits[i]; + } + + std::vector params; if (op->num_params > 0) { params.resize(op->num_params); for (int i = 0; i < op->num_params; i++) - params[i] = op->params[i]; + params[i] = Parameter(qk_param_copy(op->params[i])); } - auto gate = name_map.find(op->name); - if (gate == name_map.end()) - { - reg_t clbits; - if (op->num_clbits > 0) { - clbits.resize(op->num_clbits); - for (int i = 0; i < op->num_clbits; i++) - clbits[i] = op->clbits[i]; - } - if (strcmp(op->name, "measure") == 0) - { - qk_circuit_instruction_clear(op); - auto inst = Measure(); - return CircuitInstruction(inst, qubits, clbits); - } - else if (strcmp(op->name, "reset") == 0) - { - qk_circuit_instruction_clear(op); - auto inst = Reset(); - return CircuitInstruction(inst, qubits, clbits); - } - else if (strcmp(op->name, "barrier") == 0) - { - qk_circuit_instruction_clear(op); - auto inst = Barrier(); - return CircuitInstruction(inst, qubits, clbits); - } + std::string name = op->name; + qk_circuit_instruction_clear(op); + + if (kind == QkOperationKind_Measure) { + auto inst = Measure(); + return CircuitInstruction(inst, qubits, clbits); + } else if (kind == QkOperationKind_Reset) { + auto inst = Reset(); + return CircuitInstruction(inst, qubits, clbits); + } else if (kind == QkOperationKind_Barrier) { + auto inst = Barrier(); + return CircuitInstruction(inst, qubits, clbits); } - else - { - // standard gates + + // standard gates + auto gate = name_map.find(name); + if (gate != name_map.end()) { auto inst = gate->second; - if (params.size() > 0) - { + if (params.size() > 0) { inst.set_params(params); } - qk_circuit_instruction_clear(op); return CircuitInstruction(inst, qubits); } - qk_circuit_instruction_clear(op); } return CircuitInstruction(); } @@ -1170,13 +1142,12 @@ void QuantumCircuit::print(void) const uint_t nops; nops = qk_circuit_num_instructions(rust_circuit_.get()); - for (uint_t i = 0; i < nops; i++) - { + for (uint_t i = 0; i < nops; i++) { + QkOperationKind kind = qk_circuit_instruction_kind(rust_circuit_.get(), i); QkCircuitInstruction *op = new QkCircuitInstruction; qk_circuit_get_instruction(rust_circuit_.get(), i, op); std::cout << op->name; - if (op->num_qubits > 0) - { + if (op->num_qubits > 0) { std::cout << "("; for (uint_t j = 0; j < op->num_qubits; j++) { @@ -1186,8 +1157,7 @@ void QuantumCircuit::print(void) const } std::cout << ") "; } - if (op->num_clbits > 0) - { + if (op->num_clbits > 0) { std::cout << "("; for (uint_t j = 0; j < op->num_clbits; j++) { @@ -1197,12 +1167,12 @@ void QuantumCircuit::print(void) const } std::cout << ") "; } - if (op->num_params > 0) - { + if (op->num_params > 0) { std::cout << "["; - for (uint_t j = 0; j < op->num_params; j++) - { - std::cout << op->params[j]; + for (uint_t j = 0; j < op->num_params; j++) { + char* param = qk_param_str(op->params[j]); + std::cout << param; + qk_str_free(param); if (j != op->num_params - 1) std::cout << ", "; } @@ -1213,6 +1183,20 @@ void QuantumCircuit::print(void) const } } +void QuantumCircuit::draw(void) const +{ + QkCircuitDrawerConfig conf; + conf.bundle_cregs = true; + conf.merge_wires = false; + conf.fold = 0; + + char* out = qk_circuit_draw(rust_circuit_.get(), &conf); + std::cout << out << std::endl; + qk_str_free(out); +} + + + std::string QuantumCircuit::to_qasm3(void) { add_pending_control_flow_op(); @@ -1227,10 +1211,8 @@ std::string QuantumCircuit::to_qasm3(void) bool cs = false; bool sxdg = false; QkOpCounts opcounts = qk_circuit_count_ops(rust_circuit_.get()); - for (int i = 0; i < opcounts.len; i++) - { - if (opcounts.data[i].count != 0) - { + for (int i = 0; i < opcounts.len; i++) { + if (opcounts.data[i].count != 0) { auto op = name_map[opcounts.data[i].name].gate_map(); switch (op) { @@ -1519,8 +1501,7 @@ std::string QuantumCircuit::to_qasm3(void) // so we need to combined them in a single quantum register "q"; const std::string qreg_name = "q"; qasm3 << "qubit[" << num_qubits() << "] " << qreg_name << ";" << std::endl; - for(const auto& creg : cregs_) - { + for(const auto& creg : cregs_) { qasm3 << "bit[" << creg.size() << "] " << creg.name() << ";" << std::endl; } @@ -1533,47 +1514,36 @@ std::string QuantumCircuit::to_qasm3(void) return std::make_pair(it->name(), index - it->base_index()); }; - for (uint_t i = 0; i < nops; i++) - { + for (uint_t i = 0; i < nops; i++) { QkCircuitInstruction *op = new QkCircuitInstruction; qk_circuit_get_instruction(rust_circuit_.get(), i, op); - if (op->num_clbits > 0) - { - if (op->num_qubits == op->num_clbits) - { - for (uint_t j = 0; j < op->num_qubits; j++) - { + if (op->num_clbits > 0) { + if (op->num_qubits == op->num_clbits) { + for (uint_t j = 0; j < op->num_qubits; j++) { const auto creg_data = recover_reg_data(op->clbits[j]); qasm3 << creg_data.first << "[" << creg_data.second << "] = " << op->name << " " << qreg_name << "[" << op->qubits[j] << "];" << std::endl; } } - } - else - { - if (strcmp(op->name, "u") == 0) - { + } else { + if (strcmp(op->name, "u") == 0) { qasm3 << "U"; - } - else - { + } else { qasm3 << op->name; } - if (op->num_params > 0) - { + if (op->num_params > 0) { qasm3 << "("; - for (uint_t j = 0; j < op->num_params; j++) - { - qasm3 << op->params[j]; + for (uint_t j = 0; j < op->num_params; j++) { + char* param = qk_param_str(op->params[j]); + qasm3 << param; + qk_str_free(param); if (j != op->num_params - 1) qasm3 << ", "; } qasm3 << ")"; } - if (op->num_qubits > 0) - { + if (op->num_qubits > 0) { qasm3 << " "; - for (uint_t j = 0; j < op->num_qubits; j++) - { + for (uint_t j = 0; j < op->num_qubits; j++) { qasm3 << qreg_name << "[" << op->qubits[j] << "]"; if (j != op->num_qubits - 1) qasm3 << ", "; @@ -1588,6 +1558,8 @@ std::string QuantumCircuit::to_qasm3(void) } +#define QC_COMPARE_EPS (1e-15) + bool QuantumCircuit::operator==(const QuantumCircuit& other) const { if (global_phase_ != other.global_phase_) { @@ -1627,7 +1599,11 @@ bool QuantumCircuit::operator==(const QuantumCircuit& other) const } } for (int j = 0; j < op->num_params; j++) { - if (op->params[j] != op_other->params[j]) { + QkParam* sub = qk_param_zero(); + qk_param_sub(sub, op->params[j], op_other->params[j]); + double diff = qk_param_as_real(sub); + qk_param_free(sub); + if (fabs(diff) > QC_COMPARE_EPS) { qk_circuit_instruction_clear(op); qk_circuit_instruction_clear(op_other); return false; diff --git a/src/transpiler/passmanager.hpp b/src/transpiler/passmanager.hpp index 1b3d941..f3811c8 100644 --- a/src/transpiler/passmanager.hpp +++ b/src/transpiler/passmanager.hpp @@ -158,21 +158,32 @@ circuit::QuantumCircuit StagedPassManager::run(circuit::QuantumCircuit& circ) if (dag == nullptr) { return circ.copy(); } - QkTranspileLayout* layout = nullptr; + QkTranspilerStageState* state = nullptr; for (auto stage : stages_) { if (stage == "init") { - ret = qk_transpile_stage_init(dag, target_.rust_target(), &options, &layout, &error); + ret = qk_transpile_stage_init(dag, target_.rust_target(), &options, &state, &error); if (ret != QkExitCode_Success) { std::cerr << "StagedPassManager Error in init stage (" << ret << ") : " << error << std::endl; } } else if (stage == "layout") { - ret = qk_transpile_stage_layout(dag, target_.rust_target(), &options, &layout, &error); + ret = qk_transpile_stage_layout(dag, target_.rust_target(), &options, &state, &error); if (ret != QkExitCode_Success) { std::cerr << "StagedPassManager Error in layout stage (" << ret << ") : " << error << std::endl; } } else if (stage == "routing") { - ret = qk_transpile_stage_routing(dag, target_.rust_target(), &options, layout, &error); + if (state == nullptr) { + int nq_dag = qk_dag_num_qubits(dag); + std::vector def_map(nq_dag + 1, 0); + for (int i = 0; i < nq_dag; i++) { + def_map[i] = (uint32_t)i; + } + QkTranspileLayout* def_layout = qk_transpile_layout_generate_from_mapping(dag, target_.rust_target(), def_map.data()); + qk_transpile_state_new(&state); + qk_transpile_state_layout_set(state, def_layout); + } + + ret = qk_transpile_stage_routing(dag, target_.rust_target(), &options, state, &error); if (ret != QkExitCode_Success) { std::cerr << "StagedPassManager Error in routing stage (" << ret << ") : " << error << std::endl; } @@ -182,7 +193,18 @@ circuit::QuantumCircuit StagedPassManager::run(circuit::QuantumCircuit& circ) std::cerr << "StagedPassManager Error in transplation stage (" << ret << ") : " << error << std::endl; } } else if (stage == "optimization") { - ret = qk_transpile_stage_optimization(dag, target_.rust_target(), &options, &error, layout); + if (state == nullptr) { + int nq_dag = qk_dag_num_qubits(dag); + std::vector def_map(nq_dag + 1, 0); + for (int i = 0; i < nq_dag; i++) { + def_map[i] = (uint32_t)i; + } + QkTranspileLayout* def_layout = qk_transpile_layout_generate_from_mapping(dag, target_.rust_target(), def_map.data()); + qk_transpile_state_new(&state); + qk_transpile_state_layout_set(state, def_layout); + } + + ret = qk_transpile_stage_optimization(dag, target_.rust_target(), &options, &error, state); if (ret != QkExitCode_Success) { std::cerr << "StagedPassManager Error in optimization stage (" << ret << ") : " << error << std::endl; } @@ -193,13 +215,14 @@ circuit::QuantumCircuit StagedPassManager::run(circuit::QuantumCircuit& circ) QkCircuit* result_circ = qk_dag_to_circuit(dag); circuit::QuantumCircuit transpiled = circ; - if (layout) { + if (state) { + QkTranspileLayout* layout = qk_transpile_state_layout(state); std::vector layout_map(qk_transpile_layout_num_output_qubits(layout)); qk_transpile_layout_final_layout(layout, false, layout_map.data()); transpiled.set_qiskit_circuit(std::shared_ptr(result_circ, qk_circuit_free), layout_map); - qk_transpile_layout_free(layout); + qk_transpile_state_free(state); } else { std::vector layout_map; transpiled.set_qiskit_circuit(std::shared_ptr(result_circ, qk_circuit_free), layout_map); diff --git a/test/test_circuit.hpp b/test/test_circuit.hpp index 8f402de..19722a6 100644 --- a/test/test_circuit.hpp +++ b/test/test_circuit.hpp @@ -27,7 +27,7 @@ static int test_standard_gates(void) { CircuitInstruction op; std::string name; reg_t qubits; - std::vector params; + std::vector params; circ.i(0); op = circ[count++]; @@ -538,7 +538,7 @@ static int test_append(void) { CircuitInstruction op; std::string name; reg_t qubits; - std::vector params; + std::vector params; circ.h(0); @@ -573,7 +573,7 @@ static int test_compose(void) { CircuitInstruction op; std::string name; reg_t qubits; - std::vector params; + std::vector params; circ.h(0); for (uint_t i = 1; i < num_qubits; i++) {