Loading lib/mirror_rb/clifford_gate_utils.cpp +13 −3 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ GenRot_t computeRotationInPauliFrame(const GenRot_t &in_rot, PauliLabel in_netPauli) { auto [theta1, theta2, theta3] = in_rot; theta1 = mod_2pi(theta1); theta2 = mod_2pi(theta2); theta3 = mod_2pi(theta3); if (in_netPauli == PauliLabel::X || in_netPauli == PauliLabel::Z) { theta2 *= -1.0; } Loading @@ -33,12 +36,12 @@ GenRot_t computeRotationInPauliFrame(const GenRot_t &in_rot, } // if x or y if (in_newPauli == PauliLabel::X || in_netPauli == PauliLabel::Y) { if (in_newPauli == PauliLabel::X || in_newPauli == PauliLabel::Y) { theta1 = -theta1 + M_PI; theta2 = theta2 + M_PI; } // if y or z if (in_newPauli == PauliLabel::Y || in_netPauli == PauliLabel::Z) { if (in_newPauli == PauliLabel::Y || in_newPauli == PauliLabel::Z) { theta1 = theta1 + M_PI; } Loading @@ -46,7 +49,14 @@ GenRot_t computeRotationInPauliFrame(const GenRot_t &in_rot, theta1 = mod_2pi(theta1); theta2 = mod_2pi(theta2); theta3 = mod_2pi(theta3); return std::make_tuple(theta1, theta2, theta3); } GenRot_t invU3Gate(const GenRot_t &in_rot) { auto [theta1, theta2, theta3] = in_rot; theta1 = mod_2pi(M_PI - theta1); theta2 = mod_2pi(-theta2); theta3 = mod_2pi(-theta3 + M_PI); return std::make_tuple(theta1, theta2, theta3); } Loading Loading @@ -226,7 +236,7 @@ Srep_t composeCliffords(const Srep_t &C1, const Srep_t &C2) { } Mat_t u = Mat_t::Zero(2 * n, 2 * n); u(Eigen::seq(n, 2 * n), Eigen::seq(0, n)) = Mat_t::Identity(n, n); u(Eigen::seq(n, 2 * n - 1), Eigen::seq(0, n - 1)) = Mat_t::Identity(n, n); Vec_t vec1 = s1.transpose() * p2; Mat_t inner = (s2.transpose() * u) * s2; Loading lib/mirror_rb/clifford_gate_utils.hpp +21 −2 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ #include <vector> #include <string> #include <unordered_map> #include <iostream> namespace qcor { namespace utils { // Generalized rotation (3 angles) Loading @@ -12,6 +12,22 @@ using GenRot_t = std::tuple<double, double, double>; enum class PauliLabel { I, X, Y, Z }; static inline std::vector<PauliLabel> ALL_PAULI_OPS({PauliLabel::I, PauliLabel::X, PauliLabel::Y, PauliLabel::Z}); inline std::ostream &operator<<(std::ostream &out, PauliLabel value) { std::string s; #define PROCESS_VAL(p) \ case (p): \ s = #p; \ break; switch (value) { PROCESS_VAL(PauliLabel::I); PROCESS_VAL(PauliLabel::X); PROCESS_VAL(PauliLabel::Y); PROCESS_VAL(PauliLabel::Z); } #undef PROCESS_VAL return out << s.back(); } // Symplectic matrix and phase vector representations using Smatrix_t = std::vector<std::vector<int>>; Loading @@ -26,7 +42,10 @@ using CliffordGateLayer_t = GenRot_t computeRotationInPauliFrame(const GenRot_t &in_rot, PauliLabel in_newPauli, PauliLabel in_netPauli); // makes a compiled version of the inverse of a compiled general unitary // negate angles for inverse based on central pauli, account for recompiling the // X(-pi/2) into X(pi/2) GenRot_t invU3Gate(const GenRot_t &in_rot); // Creates a dictionary of the symplectic representations of // Clifford gates. // Returns a dictionary of (s matrix, phase vector) pairs, Loading lib/mirror_rb/mirror_circuit_rb.cpp +49 −14 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ getLayer(std::shared_ptr<xacc::CompositeInstruction> circuit, int layerId) { std::vector<std::shared_ptr<xacc::Instruction>> result; assert(layerId < circuit->depth()); auto graphView = circuit->toGraph(); for (int i = 1; i < graphView->order() - 2; i++) { for (int i = 1; i < graphView->order() - 1; i++) { auto node = graphView->getVertexProperties(i); if (node.get<int>("layer") == layerId) { result.emplace_back( Loading Loading @@ -64,7 +64,51 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { } return result; }; for (int layer = 0; layer < in_circuit->depth(); ++layer) { // in_circuit->as_xacc()->toGraph()->write(std::cout); const auto decomposeU3Angle = [](xacc::InstPtr u3_gate) { const double theta = InstructionParameterToDouble(u3_gate->getParameter(0)); const double phi = InstructionParameterToDouble(u3_gate->getParameter(1)); const double lam = InstructionParameterToDouble(u3_gate->getParameter(2)); // Convert to 3 rz angles: const double theta1 = lam; const double theta2 = theta + M_PI; const double theta3 = phi + 3.0 * M_PI; return std::make_tuple(theta1, theta2, theta3); }; const auto createU3GateFromAngle = [](size_t qubit, double theta1, double theta2, double theta3) { auto gateProvider = xacc::getService<xacc::IRProvider>("quantum"); return gateProvider->createInstruction( "U", {qubit}, {theta2 - M_PI, theta3 - 3.0 * M_PI, theta1}); }; const auto d = in_circuit->depth(); for (int layer = d - 1; layer >= 0; --layer) { auto current_layers = getLayer(in_circuit->as_xacc(), layer); for (const auto &gate : current_layers) { // Only handle "U3" gate for now. // TODO: convert all single-qubit gates to U3 if (gate->name() == "U") { const auto u3_angles = decomposeU3Angle(gate); const auto [theta1_inv, theta2_inv, theta3_inv] = qcor::utils::invU3Gate(u3_angles); const size_t qubit = gate->bits()[0]; in_circuit->addInstruction( gateProvider->createInstruction("Rz", {qubit}, {theta3_inv})); in_circuit->addInstruction( gateProvider->createInstruction("Rx", {qubit}, {M_PI / 2.0})); in_circuit->addInstruction( gateProvider->createInstruction("Rz", {qubit}, {theta2_inv})); in_circuit->addInstruction( gateProvider->createInstruction("Rx", {qubit}, {M_PI / 2.0})); in_circuit->addInstruction( gateProvider->createInstruction("Rz", {qubit}, {theta1_inv})); } } } for (int layer = 0; layer < d; ++layer) { auto current_layers = getLayer(in_circuit->as_xacc(), layer); // New random Pauli layer const std::vector<qcor::utils::PauliLabel> new_paulis = [](int nQubits) { Loading Loading @@ -93,23 +137,14 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { // TODO: convert all single-qubit gates to U3 if (gate->name() == "U") { const size_t qubit = gate->bits()[0]; const double theta = InstructionParameterToDouble(gate->getParameter(0)); const double phi = InstructionParameterToDouble(gate->getParameter(1)); const double lam = InstructionParameterToDouble(gate->getParameter(2)); // Convert to 3 rz angles: const double theta1 = lam; const double theta2 = theta + M_PI; const double theta3 = phi + 3.0 * M_PI; const auto [theta1, theta2, theta3] = decomposeU3Angle(gate); // Compute the pseudo_inverse gate: const auto [theta1_new, theta2_new, theta3_new] = qcor::utils::computeRotationInPauliFrame( std::make_tuple(theta1, theta2, theta3), new_paulis[qubit], net_paulis[qubit]); mirrorCircuit.emplace_back(gateProvider->createInstruction( "U", {qubit}, {theta2_new - M_PI, theta3_new - 3.0 * M_PI, theta1_new})); mirrorCircuit.emplace_back( createU3GateFromAngle(qubit, theta1_new, theta2_new, theta3_new)); } } } Loading lib/mirror_rb/tests/CMakeLists.txt +2 −2 Original line number Diff line number Diff line Loading @@ -6,6 +6,6 @@ endif() add_executable(MirrorCircuitTester MirrorCircuitTester.cpp) add_test(NAME qcor_MirrorCircuitTester COMMAND MirrorCircuitTester) target_include_directories(MirrorCircuitTester PRIVATE ../../ ../../../base ${XACC_ROOT}/include/gtest) target_link_libraries(MirrorCircuitTester ${XACC_TEST_LIBRARIES} xacc::xacc xacc::quantum_gate) target_include_directories(MirrorCircuitTester PRIVATE .. ${XACC_ROOT}/include/gtest) target_link_libraries(MirrorCircuitTester ${XACC_TEST_LIBRARIES} xacc::xacc xacc::quantum_gate qcor-mirror-rb) lib/mirror_rb/tests/MirrorCircuitTester.cpp +32 −4 Original line number Diff line number Diff line Loading @@ -2,12 +2,40 @@ #include "xacc_service.hpp" #include <gtest/gtest.h> #include <fstream> TEST(MirrorCircuitTester, checkSimple) { // TODO #include "mirror_circuit_rb.hpp" #include "qcor_ir.hpp" #include <random> namespace { double random_angle() { static std::uniform_real_distribution<double> dis(-M_PI, M_PI); static std::default_random_engine re; return dis(re); } } // namespace TEST(MirrorCircuitTester, checkU3Inverse) { auto provider = xacc::getIRProvider("quantum"); constexpr int NUM_TESTS = 1000; for (int i = 0; i < NUM_TESTS; ++i) { auto circuit = provider->createComposite("test"); const double theta = random_angle(); const double phi = random_angle(); const double lambda = random_angle(); circuit->addInstruction(provider->createInstruction( "U", {0}, std::vector<xacc::InstructionParameter>{theta, phi, lambda})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); auto accelerator = xacc::getAccelerator("qpp", {{"shots", 1024}}); // circuit->addInstructions(mirror_cir->getInstructions()); circuit->addInstruction(provider->createInstruction("Measure", {0})); // std::cout << "HOWDY: \n" << circuit->toString() << "\n"; auto buffer = xacc::qalloc(1); accelerator->execute(buffer, circuit); buffer->print(); EXPECT_EQ(buffer->getMeasurementCounts().size(), 1); EXPECT_EQ(buffer->getMeasurementCounts()["0"], 1024); } } int main(int argc, char **argv) { xacc::Initialize(); Loading Loading
lib/mirror_rb/clifford_gate_utils.cpp +13 −3 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ GenRot_t computeRotationInPauliFrame(const GenRot_t &in_rot, PauliLabel in_netPauli) { auto [theta1, theta2, theta3] = in_rot; theta1 = mod_2pi(theta1); theta2 = mod_2pi(theta2); theta3 = mod_2pi(theta3); if (in_netPauli == PauliLabel::X || in_netPauli == PauliLabel::Z) { theta2 *= -1.0; } Loading @@ -33,12 +36,12 @@ GenRot_t computeRotationInPauliFrame(const GenRot_t &in_rot, } // if x or y if (in_newPauli == PauliLabel::X || in_netPauli == PauliLabel::Y) { if (in_newPauli == PauliLabel::X || in_newPauli == PauliLabel::Y) { theta1 = -theta1 + M_PI; theta2 = theta2 + M_PI; } // if y or z if (in_newPauli == PauliLabel::Y || in_netPauli == PauliLabel::Z) { if (in_newPauli == PauliLabel::Y || in_newPauli == PauliLabel::Z) { theta1 = theta1 + M_PI; } Loading @@ -46,7 +49,14 @@ GenRot_t computeRotationInPauliFrame(const GenRot_t &in_rot, theta1 = mod_2pi(theta1); theta2 = mod_2pi(theta2); theta3 = mod_2pi(theta3); return std::make_tuple(theta1, theta2, theta3); } GenRot_t invU3Gate(const GenRot_t &in_rot) { auto [theta1, theta2, theta3] = in_rot; theta1 = mod_2pi(M_PI - theta1); theta2 = mod_2pi(-theta2); theta3 = mod_2pi(-theta3 + M_PI); return std::make_tuple(theta1, theta2, theta3); } Loading Loading @@ -226,7 +236,7 @@ Srep_t composeCliffords(const Srep_t &C1, const Srep_t &C2) { } Mat_t u = Mat_t::Zero(2 * n, 2 * n); u(Eigen::seq(n, 2 * n), Eigen::seq(0, n)) = Mat_t::Identity(n, n); u(Eigen::seq(n, 2 * n - 1), Eigen::seq(0, n - 1)) = Mat_t::Identity(n, n); Vec_t vec1 = s1.transpose() * p2; Mat_t inner = (s2.transpose() * u) * s2; Loading
lib/mirror_rb/clifford_gate_utils.hpp +21 −2 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ #include <vector> #include <string> #include <unordered_map> #include <iostream> namespace qcor { namespace utils { // Generalized rotation (3 angles) Loading @@ -12,6 +12,22 @@ using GenRot_t = std::tuple<double, double, double>; enum class PauliLabel { I, X, Y, Z }; static inline std::vector<PauliLabel> ALL_PAULI_OPS({PauliLabel::I, PauliLabel::X, PauliLabel::Y, PauliLabel::Z}); inline std::ostream &operator<<(std::ostream &out, PauliLabel value) { std::string s; #define PROCESS_VAL(p) \ case (p): \ s = #p; \ break; switch (value) { PROCESS_VAL(PauliLabel::I); PROCESS_VAL(PauliLabel::X); PROCESS_VAL(PauliLabel::Y); PROCESS_VAL(PauliLabel::Z); } #undef PROCESS_VAL return out << s.back(); } // Symplectic matrix and phase vector representations using Smatrix_t = std::vector<std::vector<int>>; Loading @@ -26,7 +42,10 @@ using CliffordGateLayer_t = GenRot_t computeRotationInPauliFrame(const GenRot_t &in_rot, PauliLabel in_newPauli, PauliLabel in_netPauli); // makes a compiled version of the inverse of a compiled general unitary // negate angles for inverse based on central pauli, account for recompiling the // X(-pi/2) into X(pi/2) GenRot_t invU3Gate(const GenRot_t &in_rot); // Creates a dictionary of the symplectic representations of // Clifford gates. // Returns a dictionary of (s matrix, phase vector) pairs, Loading
lib/mirror_rb/mirror_circuit_rb.cpp +49 −14 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ getLayer(std::shared_ptr<xacc::CompositeInstruction> circuit, int layerId) { std::vector<std::shared_ptr<xacc::Instruction>> result; assert(layerId < circuit->depth()); auto graphView = circuit->toGraph(); for (int i = 1; i < graphView->order() - 2; i++) { for (int i = 1; i < graphView->order() - 1; i++) { auto node = graphView->getVertexProperties(i); if (node.get<int>("layer") == layerId) { result.emplace_back( Loading Loading @@ -64,7 +64,51 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { } return result; }; for (int layer = 0; layer < in_circuit->depth(); ++layer) { // in_circuit->as_xacc()->toGraph()->write(std::cout); const auto decomposeU3Angle = [](xacc::InstPtr u3_gate) { const double theta = InstructionParameterToDouble(u3_gate->getParameter(0)); const double phi = InstructionParameterToDouble(u3_gate->getParameter(1)); const double lam = InstructionParameterToDouble(u3_gate->getParameter(2)); // Convert to 3 rz angles: const double theta1 = lam; const double theta2 = theta + M_PI; const double theta3 = phi + 3.0 * M_PI; return std::make_tuple(theta1, theta2, theta3); }; const auto createU3GateFromAngle = [](size_t qubit, double theta1, double theta2, double theta3) { auto gateProvider = xacc::getService<xacc::IRProvider>("quantum"); return gateProvider->createInstruction( "U", {qubit}, {theta2 - M_PI, theta3 - 3.0 * M_PI, theta1}); }; const auto d = in_circuit->depth(); for (int layer = d - 1; layer >= 0; --layer) { auto current_layers = getLayer(in_circuit->as_xacc(), layer); for (const auto &gate : current_layers) { // Only handle "U3" gate for now. // TODO: convert all single-qubit gates to U3 if (gate->name() == "U") { const auto u3_angles = decomposeU3Angle(gate); const auto [theta1_inv, theta2_inv, theta3_inv] = qcor::utils::invU3Gate(u3_angles); const size_t qubit = gate->bits()[0]; in_circuit->addInstruction( gateProvider->createInstruction("Rz", {qubit}, {theta3_inv})); in_circuit->addInstruction( gateProvider->createInstruction("Rx", {qubit}, {M_PI / 2.0})); in_circuit->addInstruction( gateProvider->createInstruction("Rz", {qubit}, {theta2_inv})); in_circuit->addInstruction( gateProvider->createInstruction("Rx", {qubit}, {M_PI / 2.0})); in_circuit->addInstruction( gateProvider->createInstruction("Rz", {qubit}, {theta1_inv})); } } } for (int layer = 0; layer < d; ++layer) { auto current_layers = getLayer(in_circuit->as_xacc(), layer); // New random Pauli layer const std::vector<qcor::utils::PauliLabel> new_paulis = [](int nQubits) { Loading Loading @@ -93,23 +137,14 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { // TODO: convert all single-qubit gates to U3 if (gate->name() == "U") { const size_t qubit = gate->bits()[0]; const double theta = InstructionParameterToDouble(gate->getParameter(0)); const double phi = InstructionParameterToDouble(gate->getParameter(1)); const double lam = InstructionParameterToDouble(gate->getParameter(2)); // Convert to 3 rz angles: const double theta1 = lam; const double theta2 = theta + M_PI; const double theta3 = phi + 3.0 * M_PI; const auto [theta1, theta2, theta3] = decomposeU3Angle(gate); // Compute the pseudo_inverse gate: const auto [theta1_new, theta2_new, theta3_new] = qcor::utils::computeRotationInPauliFrame( std::make_tuple(theta1, theta2, theta3), new_paulis[qubit], net_paulis[qubit]); mirrorCircuit.emplace_back(gateProvider->createInstruction( "U", {qubit}, {theta2_new - M_PI, theta3_new - 3.0 * M_PI, theta1_new})); mirrorCircuit.emplace_back( createU3GateFromAngle(qubit, theta1_new, theta2_new, theta3_new)); } } } Loading
lib/mirror_rb/tests/CMakeLists.txt +2 −2 Original line number Diff line number Diff line Loading @@ -6,6 +6,6 @@ endif() add_executable(MirrorCircuitTester MirrorCircuitTester.cpp) add_test(NAME qcor_MirrorCircuitTester COMMAND MirrorCircuitTester) target_include_directories(MirrorCircuitTester PRIVATE ../../ ../../../base ${XACC_ROOT}/include/gtest) target_link_libraries(MirrorCircuitTester ${XACC_TEST_LIBRARIES} xacc::xacc xacc::quantum_gate) target_include_directories(MirrorCircuitTester PRIVATE .. ${XACC_ROOT}/include/gtest) target_link_libraries(MirrorCircuitTester ${XACC_TEST_LIBRARIES} xacc::xacc xacc::quantum_gate qcor-mirror-rb)
lib/mirror_rb/tests/MirrorCircuitTester.cpp +32 −4 Original line number Diff line number Diff line Loading @@ -2,12 +2,40 @@ #include "xacc_service.hpp" #include <gtest/gtest.h> #include <fstream> TEST(MirrorCircuitTester, checkSimple) { // TODO #include "mirror_circuit_rb.hpp" #include "qcor_ir.hpp" #include <random> namespace { double random_angle() { static std::uniform_real_distribution<double> dis(-M_PI, M_PI); static std::default_random_engine re; return dis(re); } } // namespace TEST(MirrorCircuitTester, checkU3Inverse) { auto provider = xacc::getIRProvider("quantum"); constexpr int NUM_TESTS = 1000; for (int i = 0; i < NUM_TESTS; ++i) { auto circuit = provider->createComposite("test"); const double theta = random_angle(); const double phi = random_angle(); const double lambda = random_angle(); circuit->addInstruction(provider->createInstruction( "U", {0}, std::vector<xacc::InstructionParameter>{theta, phi, lambda})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); auto accelerator = xacc::getAccelerator("qpp", {{"shots", 1024}}); // circuit->addInstructions(mirror_cir->getInstructions()); circuit->addInstruction(provider->createInstruction("Measure", {0})); // std::cout << "HOWDY: \n" << circuit->toString() << "\n"; auto buffer = xacc::qalloc(1); accelerator->execute(buffer, circuit); buffer->print(); EXPECT_EQ(buffer->getMeasurementCounts().size(), 1); EXPECT_EQ(buffer->getMeasurementCounts()["0"], 1024); } } int main(int argc, char **argv) { xacc::Initialize(); Loading