Commit e4817b3c authored by Adams, Austin Joel's avatar Adams, Austin Joel
Browse files

Add some instructions for common ion trap native gates

Not sure if users would use these, but they are useful in
IRTransformations in the GTRI testbed backend.

Definitions are from the Methods section of the following paper:
https://www.nature.com/articles/nature18648

Signed-off-by: Adams, Austin Joel's avatarAustin Adams <aja@gatech.edu>
parent 17c30f48
......@@ -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