Commit 6cdf5f8c authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Added QRT support for XACC two-qubit gates



Signed-off-by: default avatarNguyen, Thien <nguyentm@ornl.gov>
parent a099a8b6
Loading
Loading
Loading
Loading
+57 −0
Original line number Diff line number Diff line
#include "qcor.hpp"

// Quantum Fourier Transform
__qpu__ void qft(qreg q) {
  // Local Declarations
  const auto nQubits = q.size();
  for (int qIdx = 0; qIdx < nQubits; ++qIdx) {
    H(q[qIdx]);
    for (int j = qIdx + 1; j < nQubits; ++j) {
      const double theta = M_PI/std::pow(2.0, j - qIdx);
      CPhase(q[j], q[qIdx], theta);
    }
  }

  // Swap qubits
  for (int qIdx = 0; qIdx < nQubits / 2; ++qIdx) {
    Swap(q[qIdx], q[nQubits - qIdx - 1]);
  }
}

// Inverse Quantum Fourier Transform
__qpu__ void iqft(qreg q) {
  // Local Declarations
  const auto nQubits = q.size();
  // Swap qubits
  const int startIdx = nQubits / 2 - 1;
  for (int qIdx = startIdx; qIdx >= 0; --qIdx) {
    Swap(q[qIdx], q[nQubits - qIdx - 1]);
  }
    
  for (int qIdx = nQubits - 1; qIdx >= 0; --qIdx) {
    for (int j = nQubits - 1; j > qIdx; --j) {
      const double theta = -M_PI/std::pow(2.0, j - qIdx);
      CPhase(q[j], q[qIdx], theta);
    }
    H(q[qIdx]);
  }
}

__qpu__ void f(qreg q) {
  const auto nQubits = q.size();
  // TODO: check if this is possible
  qft(q);
  iqft(q);
  for (int qIdx = 0; qIdx < nQubits / 2; ++qIdx) {
    Measure(q[qIdx]);
  }
}


int main(int argc, char **argv) {
  // Allocate 4 qubits
  auto q = qalloc(4);
  f(q);
  // dump the results
  q.print();
}
+28 −17
Original line number Diff line number Diff line
@@ -75,36 +75,47 @@ protected:
    ss << ");\n";
  }

  void addTwoQubitGate(const std::string name, xacc::Instruction &inst) {
    auto expr_src = inst.getBitExpression(0);
    auto expr_tgt = inst.getBitExpression(1);
    ss << "quantum::" + name + "(" << inst.getBufferNames()[0] << "["
       << (expr_src.empty() ? std::to_string(inst.bits()[0]) : expr_src)
       << "], " << inst.getBufferNames()[1] << "["
       << (expr_tgt.empty() ? std::to_string(inst.bits()[1]) : expr_tgt) << "]";
    // Handle parameterized gate:
    if (inst.isParameterized()) {
      ss << ", " << inst.getParameter(0).toString();
      for (int i = 1; i < inst.nParameters(); i++) {
        ss << ", " << inst.getParameter(i).toString();
      }
    }
    ss << ");\n";   
  }

public:
  auto get_new_src() { return ss.str(); }

  // One-qubit gates
  void visit(Hadamard &h) override { addOneQubitGate("h", h); }
  void visit(CNOT &cnot) override {
    auto expr_src = cnot.getBitExpression(0);
    auto expr_tgt = cnot.getBitExpression(1);
    ss << "quantum::cnot(" << cnot.getBufferNames()[0] << "["
       << (expr_src.empty() ? std::to_string(cnot.bits()[0]) : expr_src)
       << "], " << cnot.getBufferNames()[1] << "["
       << (expr_tgt.empty() ? std::to_string(cnot.bits()[1]) : expr_tgt)
       << "]);\n";
  }

  void visit(Rz &rz) override { addOneQubitGate("rz", rz); }
  void visit(Ry &ry) override { addOneQubitGate("ry", ry); }
  void visit(Rx &rx) override { addOneQubitGate("rx", rx); }
  void visit(X &x) override { addOneQubitGate("x", x); }
  void visit(Y &y) override { addOneQubitGate("y", y); }
  void visit(Z &z) override { addOneQubitGate("z", z); }
  void visit(CY &cy) override {}
  void visit(CZ &cz) override {}
  void visit(Swap &s) override {}
  void visit(CRZ &crz) override {}
  void visit(CH &ch) override {}
  void visit(S &s) override { addOneQubitGate("s", s); }
  void visit(Sdg &sdg) override { addOneQubitGate("sdg", sdg); }
  void visit(T &t) override { addOneQubitGate("t", t); }
  void visit(Tdg &tdg) override { addOneQubitGate("tdg", tdg); }
  void visit(CPhase &cphase) override {}
  
  // Two-qubit gates
  void visit(CNOT &cnot) override { addTwoQubitGate("cnot", cnot); }
  void visit(CY &cy) override { addTwoQubitGate("cy", cy); }
  void visit(CZ &cz) override { addTwoQubitGate("cz", cz); }
  void visit(Swap &s) override { addTwoQubitGate("swap", s); }
  void visit(CRZ &crz) override { addTwoQubitGate("crz", crz); }
  void visit(CH &ch) override { addTwoQubitGate("ch", ch); }
  void visit(CPhase &cphase) override { addTwoQubitGate("cphase", cphase); }
    
  void visit(Measure &measure) override { addOneQubitGate("mz", measure); }
  void visit(Identity &i) override { addOneQubitGate("i", i); }
  void visit(U &u) override { addOneQubitGate("u", u); }
+36 −4
Original line number Diff line number Diff line
@@ -32,6 +32,17 @@ void one_qubit_inst(const std::string &name, const qubit &qidx,
  program->addInstruction(inst);
}

void two_qubit_inst(const std::string &name, const qubit &qidx1, const qubit &qidx2,
                    std::vector<double> parameters) {
  auto inst =
      provider->createInstruction(name, std::vector<std::size_t>{ qidx1.second, qidx2.second });
  inst->setBufferNames({ qidx1.first, qidx2.first });
  for (int i = 0; i < parameters.size(); i++) {
    inst->setParameter(i, parameters[i]);
  }
  program->addInstruction(inst);                    
}

void h(const qubit &qidx) { one_qubit_inst("H", qidx); }
void x(const qubit &qidx) { one_qubit_inst("X", qidx); }
void t(const qubit &qidx) { one_qubit_inst("T", qidx); }
@@ -51,10 +62,31 @@ void rz(const qubit &qidx, const double theta) {
void mz(const qubit &qidx) { one_qubit_inst("Measure", qidx); }

void cnot(const qubit &src_idx, const qubit &tgt_idx) {
  auto cx = provider->createInstruction(
      "CNOT", std::vector<std::size_t>{src_idx.second, tgt_idx.second});
  cx->setBufferNames({src_idx.first, tgt_idx.first});
  program->addInstruction(cx);
  two_qubit_inst("CNOT", src_idx, tgt_idx);
}

void cy(const qubit &src_idx, const qubit &tgt_idx) {
  two_qubit_inst("CY", src_idx, tgt_idx);
}

void cz(const qubit &src_idx, const qubit &tgt_idx) {
  two_qubit_inst("CZ", src_idx, tgt_idx);
}

void ch(const qubit &src_idx, const qubit &tgt_idx) {
  two_qubit_inst("CH", src_idx, tgt_idx);
}

void swap(const qubit &src_idx, const qubit &tgt_idx) {
  two_qubit_inst("Swap", src_idx, tgt_idx);
}

void cphase(const qubit &src_idx, const qubit &tgt_idx, const double theta) {
  two_qubit_inst("CPhase", src_idx, tgt_idx, { theta });
}

void crz(const qubit &src_idx, const qubit &tgt_idx, const double theta) {
  two_qubit_inst("CRZ", src_idx, tgt_idx, { theta });
}

void exp(qreg q, const double theta, xacc::Observable *H) {
+9 −0
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ void initialize(const std::string qpu_name, const std::string kernel_name);
void set_shots(int shots);
void one_qubit_inst(const std::string &name, const qubit &qidx,
                    std::vector<double> parameters = {});
void two_qubit_inst(const std::string &name, const qubit &qidx1, const qubit &qidx2, 
                    std::vector<double> parameters = {});

void h(const qubit &qidx);
void x(const qubit &qidx);
@@ -35,7 +37,14 @@ void rz(const qubit &qidx, const double theta);

void mz(const qubit &qidx);

// Two-qubit gates:
void cnot(const qubit &src_idx, const qubit &tgt_idx);
void cy(const qubit &src_idx, const qubit &tgt_idx);
void cz(const qubit &src_idx, const qubit &tgt_idx);
void ch(const qubit &src_idx, const qubit &tgt_idx);
void swap(const qubit &src_idx, const qubit &tgt_idx);
void cphase(const qubit &src_idx, const qubit &tgt_idx, const double theta);
void crz(const qubit &src_idx, const qubit &tgt_idx, const double theta);

void exp(qreg q, const double theta, xacc::Observable * H);
void exp(qreg q, const double theta, std::shared_ptr<xacc::Observable> H);