Commit 09cc54bc authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Handle clifford gates


Signed-off-by: Nguyen, Thien Minh's avatarThien Nguyen <nguyentm@ornl.gov>
parent c5e99b56
......@@ -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) {
......@@ -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] =
......@@ -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());
}
}
}
......@@ -125,27 +130,45 @@ createMirrorCircuit(std::shared_ptr<CompositeInstruction> in_circuit) {
return random_paulis;
}(n);
const auto new_paulis_as_layer = pauliListToLayer(new_paulis);
const auto current_net_paulis_as_layer = pauliListToLayer(net_paulis);
const auto new_net_paulis_reps =
qcor::utils::computeCircuitSymplecticRepresentations(
{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);
{
std::stringstream ss;
ss << "Net Pauli: ";
for (const auto &p : net_paulis) {
ss << p << " ";
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}));
}
}
xacc::info(ss.str());
}
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);
// 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());
}
const size_t qubit = gate->bits()[0];
const auto [theta1, theta2, theta3] = decomposeU3Angle(gate);
// Compute the pseudo_inverse gate:
......@@ -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());
}
}
}
}
......
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment