Unverified Commit 9c7d2f14 authored by Mccaskey, Alex's avatar Mccaskey, Alex Committed by GitHub
Browse files

Merge pull request #485 from ausbin/feature/iontrap-gates

Add some instructions for common ion trap native gates
parents bb89f50b e4817b3c
Pipeline #164193 passed with stage
in 14 minutes and 40 seconds
......@@ -54,6 +54,8 @@ public:
auto xy = std::make_shared<xacc::quantum::XY>();
auto u = std::make_shared<xacc::quantum::U>();
auto u1 = std::make_shared<xacc::quantum::U1>();
auto rphi = std::make_shared<xacc::quantum::Rphi>();
auto xx = std::make_shared<xacc::quantum::XX>();
auto anneal = std::make_shared<xacc::quantum::AnnealingInstruction>();
......@@ -92,6 +94,8 @@ public:
context.RegisterService<xacc::Instruction>(xy);
context.RegisterService<xacc::Instruction>(u);
context.RegisterService<xacc::Instruction>(u1);
context.RegisterService<xacc::Instruction>(rphi);
context.RegisterService<xacc::Instruction>(xx);
context.RegisterService<xacc::Instruction>(ifstmt);
context.RegisterService<xacc::Instruction>(anneal);
......
......@@ -301,6 +301,49 @@ public:
DEFINE_VISITABLE()
};
// The R_phi(theta) rotation from the Methods section of
// https://www.nature.com/articles/nature18648
class Rphi: public Gate {
public:
Rphi()
: Gate("Rphi",
std::vector<InstructionParameter>{InstructionParameter(0.0),
InstructionParameter(0.0)}) {}
Rphi(std::size_t qbit, std::vector<xacc::InstructionParameter> params)
: Gate("Rphi", std::vector<std::size_t>{qbit}, params) {}
Rphi(std::size_t qbit, double phi, double theta)
: Gate("Rphi", std::vector<std::size_t>{qbit},
std::vector<InstructionParameter>{InstructionParameter(phi),
InstructionParameter(theta)}) {}
const int nRequiredBits() const override { return 1; }
DEFINE_CLONE(Rphi)
DEFINE_VISITABLE()
};
// The XX(alpha) entangling gate from the Methods section of
// https://www.nature.com/articles/nature18648
// (We call the parameter alpha instead of chi_ij)
class XX : public Gate {
public:
XX() : Gate("XX", std::vector<InstructionParameter>{0.0}) {}
XX(std::size_t leftQubit, std::size_t rightQubit)
: Gate("XX", std::vector<std::size_t>{leftQubit, rightQubit},
std::vector<InstructionParameter>{0.0, 0.0}) {}
XX(std::size_t leftQubit, std::size_t rightQubit, double alpha)
: Gate("XX", std::vector<std::size_t>{leftQubit, rightQubit},
std::vector<InstructionParameter>{alpha}) {}
XX(std::vector<std::size_t> qbits)
: Gate("XX", qbits, std::vector<InstructionParameter>{0.0}) {}
XX(std::vector<std::size_t> qbits, double alpha)
: Gate("XX", qbits, std::vector<InstructionParameter>{alpha}) {}
const int nRequiredBits() const override { return 2; }
DEFINE_CLONE(XX)
DEFINE_VISITABLE()
};
class X : public Gate {
public:
X() : Gate("X") {}
......
......@@ -46,6 +46,8 @@ class AllGateVisitor : public BaseInstructionVisitor,
public InstructionVisitor<Tdg>,
public InstructionVisitor<U>,
public InstructionVisitor<U1>,
public InstructionVisitor<Rphi>,
public InstructionVisitor<XX>,
public InstructionVisitor<IfStmt>,
public InstructionVisitor<XY>,
public InstructionVisitor<Reset>,
......@@ -116,9 +118,81 @@ public:
void visit(S &s) override {}
void visit(CPhase &cp) override {}
void visit(Measure &cp) override {}
void visit(Identity &cp) override {}
void visit(U &cp) override {}
void visit(Measure &m) override {}
void visit(Identity &i) override {}
void visit(U &u) override {}
void visit(Rphi &r) override {
double phi = InstructionParameterToDouble(r.getParameter(0));
double theta = InstructionParameterToDouble(r.getParameter(1));
// Trick to rotate around azimuthal angle phi by theta
Rz rz1(r.bits()[0], phi);
Rx rx(r.bits()[0], theta);
Rz rz2(r.bits()[0], -phi);
visit(rz1);
visit(rx);
visit(rz2);
}
void visit(XX &xx) override {
double alpha = InstructionParameterToDouble(xx.getParameter(0));
std::size_t left = xx.bits()[0];
std::size_t right = xx.bits()[1];
// Suppose CRx(α) = |0><0|⊗ I + |1><1|⊗ Rx(α), where Rx(α) is
// defined in Section 4.2 of Mike & Ike. Then based on the
// Controlled-X decomposition from [1] and Controlled-sqrt(X)
// decomposition shown in the Methods section of [2], we can
// generalize and see that a controlled-Rx can be decomposed in
// terms of XX like this:
//
// CRx(α) = (Rz(-α/2)Ry(-π/2)Rx(α/2)⊗ Rx(α/2)) XX(-α/4) (Ry(π/2)⊗ I)
//
// Then, if we rearrange this equation, we can instead decompose XX
// in terms of CRx:
//
// XX(α) = (Rx(2α)Ry(π/2)Rz(-2α)⊗ Rx(2α)) CRx(-4α) (Ry(-π/2)⊗ I))
//
// However, CRx is not in XACC IR. So given that Rx is a special
// unitary and Rx(θ) = Rz(-π/2)Ry(θ)Rz(π/2), we can use Lemma 4.3 of [3]
// to decompose CRx into CNOTs, Ry, and Rz as follows:
//
// CRx(θ) = (I⊗ Rz(-π/2)Ry(θ/2)) CNOT (I⊗ Ry(-θ/2)) CNOT (I⊗ Rz(π/2))
//
// Then we substitute this into the earlier definition to find the
// decomposition we use below:
//
// XX(α) = (Rx(2α)Ry(π/2)Rz(-2α)⊗ Rx(2α)Rz(-π/2)Ry(-2*α)) CNOT (I⊗ Ry(2α)) CNOT (Ry(-π/2)⊗ Rz(π/2))
//
// [1]: https://doi.org/10.1088/1367-2630/aa5e47
// [2]: https://www.nature.com/articles/s41586-019-1427-5
// [3]: https://arxiv.org/abs/quant-ph/9503016
Ry left1(left, -M_PI/2.0);
Rz right1(right, M_PI/2.0);
CNOT cx1(left, right);
Ry right2(right, 2*alpha);
CNOT cx2(left, right);
Rz left2(left, -2.0*alpha);
Ry left3(left, M_PI/2.0);
Rx left4(left, 2.0*alpha);
Ry right3(right, -2.0*alpha);
Rz right4(right, -M_PI/2.0);
Rx right5(right, 2.0*alpha);
visit(left1);
visit(right1);
visit(cx1);
visit(right2);
visit(cx2);
visit(left2);
visit(left3);
visit(left4);
visit(right3);
visit(right4);
visit(right5);
}
void visit(Sdg &sdg) override {}
void visit(T &t) override {}
......
......@@ -70,9 +70,18 @@ public:
void visit(Sdg &sdg) override {addSingleQubitGate(sdg);}
void visit(T &t) override {addSingleQubitGate(t);}
void visit(Tdg &tdg) override {addSingleQubitGate(tdg);}
void visit(Rphi &rphi) override { addSingleQubitGate(rphi); }
void visit(U1 &u1) override { addSingleQubitGate(u1); }
void visit(CRZ &crz) override { addTwoQubitGate(crz); }
void visit(CH &ch) override { addTwoQubitGate(ch); }
void visit(CY &cy) override { addTwoQubitGate(cy); }
void visit(fSim &fsim) override { addTwoQubitGate(fsim); }
void visit(iSwap &iswap) override { addTwoQubitGate(iswap); }
void visit(RZZ &rzz) override { addTwoQubitGate(rzz); }
void visit(XX &xx) override { addTwoQubitGate(xx); }
void visit(XY &xy) override { addTwoQubitGate(xy); }
void visit(CRZ &crz) override {addTwoQubitGate(crz);}
void visit(CH &ch) override {addTwoQubitGate(ch);}
// Base gate visitor, i.e. none of the concrete gates can match.
// We need to assert here because we cannot generate a graph when there are unknown gates.
// e.g. there is an 1-1 mapping between node Id (in the graph) and instruction counter (in the circuit),
......
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