Loading lib/mirror_rb/mirror_circuit_rb.cpp +63 −19 Original line number Diff line number Diff line Loading @@ -36,9 +36,8 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { std::vector<qcor::utils::PauliLabel> net_paulis(n, qcor::utils::PauliLabel::I); // Sympletic group for Pauli gates: const auto srep_dict = qcor::utils::computeGateSymplecticRepresentations({"I", "X", "Y", "Z"}); // Sympletic group const auto srep_dict = qcor::utils::computeGateSymplecticRepresentations(); const auto pauliListToLayer = [](const std::vector<qcor::utils::PauliLabel> &in_paulis) { Loading Loading @@ -83,12 +82,14 @@ 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(); 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 // TODO: convert all single-qubit rotation gates to U3 if (gate->name() == "U") { const auto u3_angles = decomposeU3Angle(gate); const auto [theta1_inv, theta2_inv, theta3_inv] = Loading @@ -97,6 +98,10 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { in_circuit->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()); } } } Loading Loading @@ -125,11 +130,33 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { return random_paulis; }(n); const auto new_paulis_as_layer = pauliListToLayer(new_paulis); const auto gateToLayerInfo = [](xacc::InstPtr gate, int nbQubits) { qcor::utils::CliffordGateLayer_t result; std::vector<int> operands; for (const auto &bit : gate->bits()) { operands.emplace_back(bit); } for (int i = 0; i < nbQubits; ++i) { if (!xacc::container::contains(operands, i)) { result.emplace_back(std::make_pair("I", std::vector<int>{i})); } } result.emplace_back(std::make_pair(gate->name(), operands)); return result; }; const auto current_net_paulis_as_layer = pauliListToLayer(net_paulis); 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 new_paulis_as_layer = pauliListToLayer(new_paulis); const auto new_net_paulis_reps = qcor::utils::computeCircuitSymplecticRepresentations( {new_paulis_as_layer, current_net_paulis_as_layer}, n, srep_dict); {new_paulis_as_layer, current_net_paulis_as_layer}, n, srep_dict); // Update the tracking net net_paulis = qcor::utils::find_pauli_labels(new_net_paulis_reps.second); Loading @@ -142,10 +169,6 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { xacc::info(ss.str()); } 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 size_t qubit = gate->bits()[0]; const auto [theta1, theta2, theta3] = decomposeU3Angle(gate); // Compute the pseudo_inverse gate: Loading @@ -155,6 +178,27 @@ 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())) { mirrorCircuit.emplace_back(gate->clone()); // we need to account for how the net pauli changes when it gets passed // through the clifford layers const auto new_net_paulis_reps = qcor::utils::computeCircuitSymplecticRepresentations( {gateToLayerInfo(gate, n), current_net_paulis_as_layer, gateToLayerInfo(gate, n)}, n, srep_dict); // Update the tracking net net_paulis = qcor::utils::find_pauli_labels(new_net_paulis_reps.second); { std::stringstream ss; ss << "Net Pauli: "; for (const auto &p : net_paulis) { ss << p << " "; } xacc::info(ss.str()); } } } } Loading lib/mirror_rb/tests/MirrorCircuitTester.cpp +43 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,49 @@ TEST(MirrorCircuitTester, checkMultipleU3) { EXPECT_EQ(allBitStrings.size(), 4); } TEST(MirrorCircuitTester, checkCliffordGates) { 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)); const double theta1 = random_angle(); const double phi1 = random_angle(); const double lambda1 = random_angle(); circuit->addInstruction(provider->createInstruction( "U", {0}, std::vector<xacc::InstructionParameter>{theta1, phi1, lambda1})); const double theta2 = random_angle(); const double phi2 = random_angle(); const double lambda2 = random_angle(); circuit->addInstruction(provider->createInstruction( "U", {1}, std::vector<xacc::InstructionParameter>{theta2, phi2, lambda2})); circuit->addInstruction(provider->createInstruction("CNOT", {0, 1})); circuit->addInstruction(provider->createInstruction("H", {0})); circuit->addInstruction(provider->createInstruction("H", {1})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( 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); } int main(int argc, char **argv) { xacc::Initialize(); ::testing::InitGoogleTest(&argc, argv); Loading Loading
lib/mirror_rb/mirror_circuit_rb.cpp +63 −19 Original line number Diff line number Diff line Loading @@ -36,9 +36,8 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { std::vector<qcor::utils::PauliLabel> net_paulis(n, qcor::utils::PauliLabel::I); // Sympletic group for Pauli gates: const auto srep_dict = qcor::utils::computeGateSymplecticRepresentations({"I", "X", "Y", "Z"}); // Sympletic group const auto srep_dict = qcor::utils::computeGateSymplecticRepresentations(); const auto pauliListToLayer = [](const std::vector<qcor::utils::PauliLabel> &in_paulis) { Loading Loading @@ -83,12 +82,14 @@ 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(); 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 // TODO: convert all single-qubit rotation gates to U3 if (gate->name() == "U") { const auto u3_angles = decomposeU3Angle(gate); const auto [theta1_inv, theta2_inv, theta3_inv] = Loading @@ -97,6 +98,10 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { in_circuit->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()); } } } Loading Loading @@ -125,11 +130,33 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { return random_paulis; }(n); const auto new_paulis_as_layer = pauliListToLayer(new_paulis); const auto gateToLayerInfo = [](xacc::InstPtr gate, int nbQubits) { qcor::utils::CliffordGateLayer_t result; std::vector<int> operands; for (const auto &bit : gate->bits()) { operands.emplace_back(bit); } for (int i = 0; i < nbQubits; ++i) { if (!xacc::container::contains(operands, i)) { result.emplace_back(std::make_pair("I", std::vector<int>{i})); } } result.emplace_back(std::make_pair(gate->name(), operands)); return result; }; const auto current_net_paulis_as_layer = pauliListToLayer(net_paulis); 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 new_paulis_as_layer = pauliListToLayer(new_paulis); const auto new_net_paulis_reps = qcor::utils::computeCircuitSymplecticRepresentations( {new_paulis_as_layer, current_net_paulis_as_layer}, n, srep_dict); {new_paulis_as_layer, current_net_paulis_as_layer}, n, srep_dict); // Update the tracking net net_paulis = qcor::utils::find_pauli_labels(new_net_paulis_reps.second); Loading @@ -142,10 +169,6 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) { xacc::info(ss.str()); } 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 size_t qubit = gate->bits()[0]; const auto [theta1, theta2, theta3] = decomposeU3Angle(gate); // Compute the pseudo_inverse gate: Loading @@ -155,6 +178,27 @@ 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())) { mirrorCircuit.emplace_back(gate->clone()); // we need to account for how the net pauli changes when it gets passed // through the clifford layers const auto new_net_paulis_reps = qcor::utils::computeCircuitSymplecticRepresentations( {gateToLayerInfo(gate, n), current_net_paulis_as_layer, gateToLayerInfo(gate, n)}, n, srep_dict); // Update the tracking net net_paulis = qcor::utils::find_pauli_labels(new_net_paulis_reps.second); { std::stringstream ss; ss << "Net Pauli: "; for (const auto &p : net_paulis) { ss << p << " "; } xacc::info(ss.str()); } } } } Loading
lib/mirror_rb/tests/MirrorCircuitTester.cpp +43 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,49 @@ TEST(MirrorCircuitTester, checkMultipleU3) { EXPECT_EQ(allBitStrings.size(), 4); } TEST(MirrorCircuitTester, checkCliffordGates) { 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)); const double theta1 = random_angle(); const double phi1 = random_angle(); const double lambda1 = random_angle(); circuit->addInstruction(provider->createInstruction( "U", {0}, std::vector<xacc::InstructionParameter>{theta1, phi1, lambda1})); const double theta2 = random_angle(); const double phi2 = random_angle(); const double lambda2 = random_angle(); circuit->addInstruction(provider->createInstruction( "U", {1}, std::vector<xacc::InstructionParameter>{theta2, phi2, lambda2})); circuit->addInstruction(provider->createInstruction("CNOT", {0, 1})); circuit->addInstruction(provider->createInstruction("H", {0})); circuit->addInstruction(provider->createInstruction("H", {1})); auto [mirror_cir, expected_result] = qcor::createMirrorCircuit( 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); } int main(int argc, char **argv) { xacc::Initialize(); ::testing::InitGoogleTest(&argc, argv); Loading