Loading lib/mirror_rb/mirror_circuit_rb.cpp +163 −52 Original line number Diff line number Diff line #include "mirror_circuit_rb.hpp" #include "AllGateVisitor.hpp" #include "clifford_gate_utils.hpp" #include "qcor_ir.hpp" #include "qcor_pimpl_impl.hpp" Loading @@ -7,6 +8,136 @@ #include <cassert> #include <random> namespace xacc { namespace quantum { // Helper to convert a gate class GateConverterVisitor : public AllGateVisitor { public: GateConverterVisitor() { m_gateRegistry = xacc::getService<xacc::IRProvider>("quantum"); m_program = m_gateRegistry->createComposite("temp_composite"); } // Keep these 2 gates: void visit(CNOT &cnot) override { m_program->addInstruction(cnot.clone()); } void visit(U &u) override { m_program->addInstruction(u.clone()); } // Rotation gates: void visit(Ry &ry) override { const double theta = InstructionParameterToDouble(ry.getParameter(0)); m_program->addInstruction(m_gateRegistry->createInstruction( "U", {ry.bits()[0]}, {theta, 0.0, 0.0})); } void visit(Rx &rx) override { const double theta = InstructionParameterToDouble(rx.getParameter(0)); m_program->addInstruction(m_gateRegistry->createInstruction( "U", {rx.bits()[0]}, {theta, -1.0 * M_PI / 2.0, M_PI / 2.0})); } void visit(Rz &rz) override { const double theta = InstructionParameterToDouble(rz.getParameter(0)); m_program->addInstruction(m_gateRegistry->createInstruction( "U", {rz.bits()[0]}, {0.0, theta, 0.0})); } void visit(X &x) override { Rx rx(x.bits()[0], M_PI); visit(rx); } void visit(Y &y) override { Ry ry(y.bits()[0], M_PI); visit(ry); } void visit(Z &z) override { Rz rz(z.bits()[0], M_PI); visit(rz); } void visit(S &s) override { Rz rz(s.bits()[0], M_PI / 2.0); visit(rz); } void visit(Sdg &sdg) override { Rz rz(sdg.bits()[0], -M_PI / 2.0); visit(rz); } void visit(T &t) override { Rz rz(t.bits()[0], M_PI / 4.0); visit(rz); } void visit(Tdg &tdg) override { Rz rz(tdg.bits()[0], -M_PI / 4.0); visit(rz); } void visit(Hadamard &h) override { m_program->addInstruction(m_gateRegistry->createInstruction( "U", {h.bits()[0]}, {M_PI / 2.0, 0.0, M_PI})); } void visit(Measure &measure) override { xacc::error("The mirror circuit must not contain measure gates."); } void visit(Identity &i) override {} void visit(CY &cy) override { // controlled-Y = Sdg(target) - CX - S(target) CNOT c1(cy.bits()); Sdg sdg(cy.bits()[1]); S s(cy.bits()[1]); visit(sdg); visit(c1); visit(s); } void visit(CZ &cz) override { // CZ = H(target) - CX - H(target) CNOT c1(cz.bits()); Hadamard h1(cz.bits()[1]); Hadamard h2(cz.bits()[1]); visit(h1); visit(c1); visit(h2); } void visit(CRZ &crz) override { const auto theta = InstructionParameterToDouble(crz.getParameter(0)); // Decompose Rz rz1(crz.bits()[1], theta / 2); CNOT c1(crz.bits()); Rz rz2(crz.bits()[1], -theta / 2); CNOT c2(crz.bits()); // Revisit: visit(rz1); visit(c1); visit(rz2); visit(c2); } void visit(CH &ch) override { // controlled-H = Ry(pi/4, target) - CX - Ry(-pi/4, target) CNOT c1(ch.bits()); Ry ry1(ch.bits()[1], M_PI_4); Ry ry2(ch.bits()[1], -M_PI_4); visit(ry1); visit(c1); visit(ry2); } std::shared_ptr<CompositeInstruction> getProgram() { return m_program; } private: std::shared_ptr<CompositeInstruction> m_program; std::shared_ptr<xacc::IRProvider> m_gateRegistry; }; } // namespace quantum } // namespace xacc namespace { std::vector<std::shared_ptr<xacc::Instruction>> getLayer(std::shared_ptr<xacc::CompositeInstruction> circuit, int layerId) { Loading @@ -23,27 +154,6 @@ getLayer(std::shared_ptr<xacc::CompositeInstruction> circuit, int layerId) { assert(!result.empty()); return result; } std::shared_ptr<xacc::Instruction> rotationToU3Gate(std::shared_ptr<xacc::Instruction> gate) { assert(gate->bits().size() == 1); const double theta = InstructionParameterToDouble(gate->getParameter(0)); auto gateProvider = xacc::getService<xacc::IRProvider>("quantum"); if (gate->name() == "Rx") { return gateProvider->createInstruction( "U", {gate->bits()[0]}, {theta, -1.0 * M_PI / 2.0, M_PI / 2.0}); } if (gate->name() == "Ry") { return gateProvider->createInstruction("U", {gate->bits()[0]}, {theta, 0.0, 0.0}); } if (gate->name() == "Rz") { return gateProvider->createInstruction("U", {gate->bits()[0]}, {0.0, theta, 0.0}); } assert(false); return nullptr; } } // namespace namespace qcor { Loading @@ -52,7 +162,18 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { std::vector<std::shared_ptr<xacc::Instruction>> mirrorCircuit; auto gateProvider = xacc::getService<xacc::IRProvider>("quantum"); const int n = in_circuit->nPhysicalBits(); // Gate conversion: xacc::quantum::GateConverterVisitor visitor; xacc::InstructionIterator it(in_circuit->as_xacc()); while (it.hasNext()) { auto nextInst = it.next(); if (nextInst->isEnabled() && !nextInst->isComposite()) { nextInst->accept(&visitor); } } auto program = visitor.getProgram(); const int n = program->nPhysicalBits(); // Tracking the Pauli layer as it is commuted through std::vector<qcor::utils::PauliLabel> net_paulis(n, qcor::utils::PauliLabel::I); Loading Loading @@ -85,7 +206,7 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { return result; }; // in_circuit->as_xacc()->toGraph()->write(std::cout); // program->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)); Loading @@ -103,36 +224,29 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { return gateProvider->createInstruction( "U", {qubit}, {theta2 - M_PI, theta3 - 3.0 * M_PI, theta1}); }; static const std::vector<std::string> SELF_ADJOINT_CLIFFORD_GATES{ "H", "X", "Y", "Z", "CNOT", "Swap"}; const auto d = in_circuit->depth(); const auto d = program->depth(); for (int layer = d - 1; layer >= 0; --layer) { auto current_layers = getLayer(in_circuit->as_xacc(), layer); auto current_layers = getLayer(program, layer); for (const auto &gate : current_layers) { if (gate->name() == "U" || gate->name() == "Rx" || gate->name() == "Ry" || gate->name() == "Rz") { auto u3Gate = gate->name() == "U" ? gate : rotationToU3Gate(gate); const auto u3_angles = decomposeU3Angle(u3Gate); if (gate->bits().size() == 1) { assert(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( program->addInstruction(gateProvider->createInstruction( "U", {qubit}, {theta2_inv - M_PI, theta1_inv - 3.0 * M_PI, theta3_inv})); } else if (xacc::container::contains(SELF_ADJOINT_CLIFFORD_GATES, gate->name())) { // Handle Clifford gates: in_circuit->addInstruction(gate->clone()); } else { xacc::error( "Gate " + gate->name() + " is not currently supported. Thien, please implement it!!!"); assert(gate->name() == "CNOT"); program->addInstruction(gate->clone()); } } } const int newDepth = in_circuit->depth(); const int newDepth = program->depth(); for (int layer = 0; layer < newDepth; ++layer) { auto current_layers = getLayer(in_circuit->as_xacc(), layer); auto current_layers = getLayer(program, layer); // New random Pauli layer const std::vector<qcor::utils::PauliLabel> new_paulis = [](int nQubits) { static std::random_device rd; Loading Loading @@ -174,9 +288,8 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { const auto current_net_paulis_as_layer = pauliListToLayer(net_paulis); for (const auto &gate : current_layers) { if (gate->name() == "U" || gate->name() == "Rx" || gate->name() == "Ry" || gate->name() == "Rz") { auto u3Gate = gate->name() == "U" ? gate : rotationToU3Gate(gate); if (gate->bits().size() == 1) { assert(gate->name() == "U"); const auto new_paulis_as_layer = pauliListToLayer(new_paulis); const auto new_net_paulis_reps = qcor::utils::computeCircuitSymplecticRepresentations( Loading @@ -195,7 +308,7 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { } const size_t qubit = gate->bits()[0]; const auto [theta1, theta2, theta3] = decomposeU3Angle(u3Gate); const auto [theta1, theta2, theta3] = decomposeU3Angle(gate); // Compute the pseudo_inverse gate: const auto [theta1_new, theta2_new, theta3_new] = qcor::utils::computeRotationInPauliFrame( Loading @@ -203,8 +316,7 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { net_paulis[qubit]); mirrorCircuit.emplace_back( createU3GateFromAngle(qubit, theta1_new, theta2_new, theta3_new)); } else if (xacc::container::contains(SELF_ADJOINT_CLIFFORD_GATES, gate->name())) { } else { mirrorCircuit.emplace_back(gate->clone()); // we need to account for how the net pauli changes when it gets passed // through the clifford layers Loading Loading @@ -236,8 +348,7 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { target_bitString.emplace_back(telp_p[i] == 2); } auto mirror_comp = gateProvider->createComposite(in_circuit->name() + "_MIRROR"); auto mirror_comp = gateProvider->createComposite(program->name() + "_MIRROR"); mirror_comp->addInstructions(mirrorCircuit); return std::make_pair(std::make_shared<CompositeInstruction>(mirror_comp), target_bitString); Loading lib/mirror_rb/tests/MirrorCircuitTester.cpp +42 −8 Original line number Diff line number Diff line Loading @@ -29,14 +29,14 @@ TEST(MirrorCircuitTester, checkU3Inverse) { std::make_shared<qcor::CompositeInstruction>(circuit)); EXPECT_EQ(expected_result.size(), 1); EXPECT_EQ(mirror_cir->nInstructions(), 2); std::cout << "Expected: " << expected_result[0] << "\n"; std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; // std::cout << "Expected: " << expected_result[0] << "\n"; // std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; auto mirror_circuit = provider->createComposite("test_mirror"); mirror_circuit->addInstructions(mirror_cir->getInstructions()); mirror_circuit->addInstruction(provider->createInstruction("Measure", {0})); auto mc_buffer = xacc::qalloc(1); accelerator->execute(mc_buffer, mirror_circuit); mc_buffer->print(); // mc_buffer->print(); EXPECT_EQ(mc_buffer->getMeasurementCounts().size(), 1); EXPECT_EQ( mc_buffer->getMeasurementCounts()[std::to_string(expected_result[0])], Loading Loading @@ -70,15 +70,15 @@ TEST(MirrorCircuitTester, checkMultipleU3) { std::make_shared<qcor::CompositeInstruction>(circuit)); EXPECT_EQ(expected_result.size(), 2); EXPECT_EQ(mirror_cir->nInstructions(), 4); std::cout << "Expected: " << expected_result[0] << expected_result[1] << "\n"; std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; // std::cout << "Expected: " << expected_result[0] << expected_result[1] << "\n"; // std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; auto mirror_circuit = provider->createComposite("test_mirror"); mirror_circuit->addInstructions(mirror_cir->getInstructions()); mirror_circuit->addInstruction(provider->createInstruction("Measure", {0})); mirror_circuit->addInstruction(provider->createInstruction("Measure", {1})); auto mc_buffer = xacc::qalloc(2); accelerator->execute(mc_buffer, mirror_circuit); mc_buffer->print(); // mc_buffer->print(); const std::string expectedBitString = std::to_string(expected_result[0]) + std::to_string(expected_result[1]); EXPECT_EQ(mc_buffer->getMeasurementCounts().size(), 1); Loading Loading @@ -116,8 +116,39 @@ TEST(MirrorCircuitTester, checkCliffordGates) { std::make_shared<qcor::CompositeInstruction>(circuit)); const std::string expectedBitString = std::to_string(expected_result[0]) + std::to_string(expected_result[1]); // std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; // std::cout << "Expected bitstring: " << expectedBitString << "\n"; auto mirror_circuit = provider->createComposite("test_mirror"); mirror_circuit->addInstructions(mirror_cir->getInstructions()); mirror_circuit->addInstruction(provider->createInstruction("Measure", {0})); mirror_circuit->addInstruction(provider->createInstruction("Measure", {1})); auto mc_buffer = xacc::qalloc(2); accelerator->execute(mc_buffer, mirror_circuit); //mc_buffer->print(); EXPECT_EQ(mc_buffer->getMeasurementCounts().size(), 1); EXPECT_EQ(mc_buffer->getMeasurementCounts()[expectedBitString], 1024); allBitStrings.emplace(expectedBitString); } // Cover both cases (randomized Pauli worked) EXPECT_EQ(allBitStrings.size(), 4); } TEST(MirrorCircuitTester, checkDeuteron) { auto provider = xacc::getIRProvider("quantum"); constexpr int NUM_TESTS = 1000; auto accelerator = xacc::getAccelerator("qpp", {{"shots", 1024}}); std::set<std::string> allBitStrings; for (int i = 0; i < NUM_TESTS; ++i) { auto circuit = provider->createComposite(std::string("test") + std::to_string(i)); circuit->addInstruction(provider->createInstruction("X", {0})); circuit->addInstruction(provider->createInstruction( "Ry", {1}, std::vector<xacc::InstructionParameter>{random_angle()})); circuit->addInstruction(provider->createInstruction("CNOT", {1, 0})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); std::cout << "Expected: " << expected_result[0] << expected_result[1] << "\n"; std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; std::cout << "Expected bitstring: " << expectedBitString << "\n"; auto mirror_circuit = provider->createComposite("test_mirror"); mirror_circuit->addInstructions(mirror_cir->getInstructions()); mirror_circuit->addInstruction(provider->createInstruction("Measure", {0})); Loading @@ -125,11 +156,14 @@ TEST(MirrorCircuitTester, checkCliffordGates) { auto mc_buffer = xacc::qalloc(2); accelerator->execute(mc_buffer, mirror_circuit); mc_buffer->print(); const std::string expectedBitString = std::to_string(expected_result[0]) + std::to_string(expected_result[1]); EXPECT_EQ(mc_buffer->getMeasurementCounts().size(), 1); EXPECT_EQ(mc_buffer->getMeasurementCounts()[expectedBitString], 1024); allBitStrings.emplace(expectedBitString); } // Cover both cases (randomized Pauli worked) // We should have seen all 4 possible cases with that number of randomized // Pauli runs EXPECT_EQ(allBitStrings.size(), 4); } Loading Loading
lib/mirror_rb/mirror_circuit_rb.cpp +163 −52 Original line number Diff line number Diff line #include "mirror_circuit_rb.hpp" #include "AllGateVisitor.hpp" #include "clifford_gate_utils.hpp" #include "qcor_ir.hpp" #include "qcor_pimpl_impl.hpp" Loading @@ -7,6 +8,136 @@ #include <cassert> #include <random> namespace xacc { namespace quantum { // Helper to convert a gate class GateConverterVisitor : public AllGateVisitor { public: GateConverterVisitor() { m_gateRegistry = xacc::getService<xacc::IRProvider>("quantum"); m_program = m_gateRegistry->createComposite("temp_composite"); } // Keep these 2 gates: void visit(CNOT &cnot) override { m_program->addInstruction(cnot.clone()); } void visit(U &u) override { m_program->addInstruction(u.clone()); } // Rotation gates: void visit(Ry &ry) override { const double theta = InstructionParameterToDouble(ry.getParameter(0)); m_program->addInstruction(m_gateRegistry->createInstruction( "U", {ry.bits()[0]}, {theta, 0.0, 0.0})); } void visit(Rx &rx) override { const double theta = InstructionParameterToDouble(rx.getParameter(0)); m_program->addInstruction(m_gateRegistry->createInstruction( "U", {rx.bits()[0]}, {theta, -1.0 * M_PI / 2.0, M_PI / 2.0})); } void visit(Rz &rz) override { const double theta = InstructionParameterToDouble(rz.getParameter(0)); m_program->addInstruction(m_gateRegistry->createInstruction( "U", {rz.bits()[0]}, {0.0, theta, 0.0})); } void visit(X &x) override { Rx rx(x.bits()[0], M_PI); visit(rx); } void visit(Y &y) override { Ry ry(y.bits()[0], M_PI); visit(ry); } void visit(Z &z) override { Rz rz(z.bits()[0], M_PI); visit(rz); } void visit(S &s) override { Rz rz(s.bits()[0], M_PI / 2.0); visit(rz); } void visit(Sdg &sdg) override { Rz rz(sdg.bits()[0], -M_PI / 2.0); visit(rz); } void visit(T &t) override { Rz rz(t.bits()[0], M_PI / 4.0); visit(rz); } void visit(Tdg &tdg) override { Rz rz(tdg.bits()[0], -M_PI / 4.0); visit(rz); } void visit(Hadamard &h) override { m_program->addInstruction(m_gateRegistry->createInstruction( "U", {h.bits()[0]}, {M_PI / 2.0, 0.0, M_PI})); } void visit(Measure &measure) override { xacc::error("The mirror circuit must not contain measure gates."); } void visit(Identity &i) override {} void visit(CY &cy) override { // controlled-Y = Sdg(target) - CX - S(target) CNOT c1(cy.bits()); Sdg sdg(cy.bits()[1]); S s(cy.bits()[1]); visit(sdg); visit(c1); visit(s); } void visit(CZ &cz) override { // CZ = H(target) - CX - H(target) CNOT c1(cz.bits()); Hadamard h1(cz.bits()[1]); Hadamard h2(cz.bits()[1]); visit(h1); visit(c1); visit(h2); } void visit(CRZ &crz) override { const auto theta = InstructionParameterToDouble(crz.getParameter(0)); // Decompose Rz rz1(crz.bits()[1], theta / 2); CNOT c1(crz.bits()); Rz rz2(crz.bits()[1], -theta / 2); CNOT c2(crz.bits()); // Revisit: visit(rz1); visit(c1); visit(rz2); visit(c2); } void visit(CH &ch) override { // controlled-H = Ry(pi/4, target) - CX - Ry(-pi/4, target) CNOT c1(ch.bits()); Ry ry1(ch.bits()[1], M_PI_4); Ry ry2(ch.bits()[1], -M_PI_4); visit(ry1); visit(c1); visit(ry2); } std::shared_ptr<CompositeInstruction> getProgram() { return m_program; } private: std::shared_ptr<CompositeInstruction> m_program; std::shared_ptr<xacc::IRProvider> m_gateRegistry; }; } // namespace quantum } // namespace xacc namespace { std::vector<std::shared_ptr<xacc::Instruction>> getLayer(std::shared_ptr<xacc::CompositeInstruction> circuit, int layerId) { Loading @@ -23,27 +154,6 @@ getLayer(std::shared_ptr<xacc::CompositeInstruction> circuit, int layerId) { assert(!result.empty()); return result; } std::shared_ptr<xacc::Instruction> rotationToU3Gate(std::shared_ptr<xacc::Instruction> gate) { assert(gate->bits().size() == 1); const double theta = InstructionParameterToDouble(gate->getParameter(0)); auto gateProvider = xacc::getService<xacc::IRProvider>("quantum"); if (gate->name() == "Rx") { return gateProvider->createInstruction( "U", {gate->bits()[0]}, {theta, -1.0 * M_PI / 2.0, M_PI / 2.0}); } if (gate->name() == "Ry") { return gateProvider->createInstruction("U", {gate->bits()[0]}, {theta, 0.0, 0.0}); } if (gate->name() == "Rz") { return gateProvider->createInstruction("U", {gate->bits()[0]}, {0.0, theta, 0.0}); } assert(false); return nullptr; } } // namespace namespace qcor { Loading @@ -52,7 +162,18 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { std::vector<std::shared_ptr<xacc::Instruction>> mirrorCircuit; auto gateProvider = xacc::getService<xacc::IRProvider>("quantum"); const int n = in_circuit->nPhysicalBits(); // Gate conversion: xacc::quantum::GateConverterVisitor visitor; xacc::InstructionIterator it(in_circuit->as_xacc()); while (it.hasNext()) { auto nextInst = it.next(); if (nextInst->isEnabled() && !nextInst->isComposite()) { nextInst->accept(&visitor); } } auto program = visitor.getProgram(); const int n = program->nPhysicalBits(); // Tracking the Pauli layer as it is commuted through std::vector<qcor::utils::PauliLabel> net_paulis(n, qcor::utils::PauliLabel::I); Loading Loading @@ -85,7 +206,7 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { return result; }; // in_circuit->as_xacc()->toGraph()->write(std::cout); // program->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)); Loading @@ -103,36 +224,29 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { return gateProvider->createInstruction( "U", {qubit}, {theta2 - M_PI, theta3 - 3.0 * M_PI, theta1}); }; static const std::vector<std::string> SELF_ADJOINT_CLIFFORD_GATES{ "H", "X", "Y", "Z", "CNOT", "Swap"}; const auto d = in_circuit->depth(); const auto d = program->depth(); for (int layer = d - 1; layer >= 0; --layer) { auto current_layers = getLayer(in_circuit->as_xacc(), layer); auto current_layers = getLayer(program, layer); for (const auto &gate : current_layers) { if (gate->name() == "U" || gate->name() == "Rx" || gate->name() == "Ry" || gate->name() == "Rz") { auto u3Gate = gate->name() == "U" ? gate : rotationToU3Gate(gate); const auto u3_angles = decomposeU3Angle(u3Gate); if (gate->bits().size() == 1) { assert(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( program->addInstruction(gateProvider->createInstruction( "U", {qubit}, {theta2_inv - M_PI, theta1_inv - 3.0 * M_PI, theta3_inv})); } else if (xacc::container::contains(SELF_ADJOINT_CLIFFORD_GATES, gate->name())) { // Handle Clifford gates: in_circuit->addInstruction(gate->clone()); } else { xacc::error( "Gate " + gate->name() + " is not currently supported. Thien, please implement it!!!"); assert(gate->name() == "CNOT"); program->addInstruction(gate->clone()); } } } const int newDepth = in_circuit->depth(); const int newDepth = program->depth(); for (int layer = 0; layer < newDepth; ++layer) { auto current_layers = getLayer(in_circuit->as_xacc(), layer); auto current_layers = getLayer(program, layer); // New random Pauli layer const std::vector<qcor::utils::PauliLabel> new_paulis = [](int nQubits) { static std::random_device rd; Loading Loading @@ -174,9 +288,8 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { const auto current_net_paulis_as_layer = pauliListToLayer(net_paulis); for (const auto &gate : current_layers) { if (gate->name() == "U" || gate->name() == "Rx" || gate->name() == "Ry" || gate->name() == "Rz") { auto u3Gate = gate->name() == "U" ? gate : rotationToU3Gate(gate); if (gate->bits().size() == 1) { assert(gate->name() == "U"); const auto new_paulis_as_layer = pauliListToLayer(new_paulis); const auto new_net_paulis_reps = qcor::utils::computeCircuitSymplecticRepresentations( Loading @@ -195,7 +308,7 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { } const size_t qubit = gate->bits()[0]; const auto [theta1, theta2, theta3] = decomposeU3Angle(u3Gate); const auto [theta1, theta2, theta3] = decomposeU3Angle(gate); // Compute the pseudo_inverse gate: const auto [theta1_new, theta2_new, theta3_new] = qcor::utils::computeRotationInPauliFrame( Loading @@ -203,8 +316,7 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { net_paulis[qubit]); mirrorCircuit.emplace_back( createU3GateFromAngle(qubit, theta1_new, theta2_new, theta3_new)); } else if (xacc::container::contains(SELF_ADJOINT_CLIFFORD_GATES, gate->name())) { } else { mirrorCircuit.emplace_back(gate->clone()); // we need to account for how the net pauli changes when it gets passed // through the clifford layers Loading Loading @@ -236,8 +348,7 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { target_bitString.emplace_back(telp_p[i] == 2); } auto mirror_comp = gateProvider->createComposite(in_circuit->name() + "_MIRROR"); auto mirror_comp = gateProvider->createComposite(program->name() + "_MIRROR"); mirror_comp->addInstructions(mirrorCircuit); return std::make_pair(std::make_shared<CompositeInstruction>(mirror_comp), target_bitString); Loading
lib/mirror_rb/tests/MirrorCircuitTester.cpp +42 −8 Original line number Diff line number Diff line Loading @@ -29,14 +29,14 @@ TEST(MirrorCircuitTester, checkU3Inverse) { std::make_shared<qcor::CompositeInstruction>(circuit)); EXPECT_EQ(expected_result.size(), 1); EXPECT_EQ(mirror_cir->nInstructions(), 2); std::cout << "Expected: " << expected_result[0] << "\n"; std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; // std::cout << "Expected: " << expected_result[0] << "\n"; // std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; auto mirror_circuit = provider->createComposite("test_mirror"); mirror_circuit->addInstructions(mirror_cir->getInstructions()); mirror_circuit->addInstruction(provider->createInstruction("Measure", {0})); auto mc_buffer = xacc::qalloc(1); accelerator->execute(mc_buffer, mirror_circuit); mc_buffer->print(); // mc_buffer->print(); EXPECT_EQ(mc_buffer->getMeasurementCounts().size(), 1); EXPECT_EQ( mc_buffer->getMeasurementCounts()[std::to_string(expected_result[0])], Loading Loading @@ -70,15 +70,15 @@ TEST(MirrorCircuitTester, checkMultipleU3) { std::make_shared<qcor::CompositeInstruction>(circuit)); EXPECT_EQ(expected_result.size(), 2); EXPECT_EQ(mirror_cir->nInstructions(), 4); std::cout << "Expected: " << expected_result[0] << expected_result[1] << "\n"; std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; // std::cout << "Expected: " << expected_result[0] << expected_result[1] << "\n"; // std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; auto mirror_circuit = provider->createComposite("test_mirror"); mirror_circuit->addInstructions(mirror_cir->getInstructions()); mirror_circuit->addInstruction(provider->createInstruction("Measure", {0})); mirror_circuit->addInstruction(provider->createInstruction("Measure", {1})); auto mc_buffer = xacc::qalloc(2); accelerator->execute(mc_buffer, mirror_circuit); mc_buffer->print(); // mc_buffer->print(); const std::string expectedBitString = std::to_string(expected_result[0]) + std::to_string(expected_result[1]); EXPECT_EQ(mc_buffer->getMeasurementCounts().size(), 1); Loading Loading @@ -116,8 +116,39 @@ TEST(MirrorCircuitTester, checkCliffordGates) { std::make_shared<qcor::CompositeInstruction>(circuit)); const std::string expectedBitString = std::to_string(expected_result[0]) + std::to_string(expected_result[1]); // std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; // std::cout << "Expected bitstring: " << expectedBitString << "\n"; auto mirror_circuit = provider->createComposite("test_mirror"); mirror_circuit->addInstructions(mirror_cir->getInstructions()); mirror_circuit->addInstruction(provider->createInstruction("Measure", {0})); mirror_circuit->addInstruction(provider->createInstruction("Measure", {1})); auto mc_buffer = xacc::qalloc(2); accelerator->execute(mc_buffer, mirror_circuit); //mc_buffer->print(); EXPECT_EQ(mc_buffer->getMeasurementCounts().size(), 1); EXPECT_EQ(mc_buffer->getMeasurementCounts()[expectedBitString], 1024); allBitStrings.emplace(expectedBitString); } // Cover both cases (randomized Pauli worked) EXPECT_EQ(allBitStrings.size(), 4); } TEST(MirrorCircuitTester, checkDeuteron) { auto provider = xacc::getIRProvider("quantum"); constexpr int NUM_TESTS = 1000; auto accelerator = xacc::getAccelerator("qpp", {{"shots", 1024}}); std::set<std::string> allBitStrings; for (int i = 0; i < NUM_TESTS; ++i) { auto circuit = provider->createComposite(std::string("test") + std::to_string(i)); circuit->addInstruction(provider->createInstruction("X", {0})); circuit->addInstruction(provider->createInstruction( "Ry", {1}, std::vector<xacc::InstructionParameter>{random_angle()})); circuit->addInstruction(provider->createInstruction("CNOT", {1, 0})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( std::make_shared<qcor::CompositeInstruction>(circuit)); std::cout << "Expected: " << expected_result[0] << expected_result[1] << "\n"; std::cout << "HOWDY: \n" << mirror_cir->toString() << "\n"; std::cout << "Expected bitstring: " << expectedBitString << "\n"; auto mirror_circuit = provider->createComposite("test_mirror"); mirror_circuit->addInstructions(mirror_cir->getInstructions()); mirror_circuit->addInstruction(provider->createInstruction("Measure", {0})); Loading @@ -125,11 +156,14 @@ TEST(MirrorCircuitTester, checkCliffordGates) { auto mc_buffer = xacc::qalloc(2); accelerator->execute(mc_buffer, mirror_circuit); mc_buffer->print(); const std::string expectedBitString = std::to_string(expected_result[0]) + std::to_string(expected_result[1]); EXPECT_EQ(mc_buffer->getMeasurementCounts().size(), 1); EXPECT_EQ(mc_buffer->getMeasurementCounts()[expectedBitString], 1024); allBitStrings.emplace(expectedBitString); } // Cover both cases (randomized Pauli worked) // We should have seen all 4 possible cases with that number of randomized // Pauli runs EXPECT_EQ(allBitStrings.size(), 4); } Loading