QCOR
qrt_mapper.hpp
1 
2 #ifndef QCOR_QRT_MAPPER_HPP_
3 #define QCOR_QRT_MAPPER_HPP_
4 
5 #include <Instruction.hpp>
6 
7 #include "AllGateVisitor.hpp"
8 #include "Circuit.hpp"
9 #include "qrt.hpp"
10 
11 namespace qcor {
12 using namespace xacc::quantum;
13 
14 class qrt_mapper : public AllGateVisitor,
15  public xacc::InstructionVisitor<Circuit> {
16  protected:
17  std::stringstream ss;
18  // The kernel name of the CompositeInstruction
19  // that this mapper is visiting.
20  std::string kernelName;
21  void addOneQubitGate(const std::string name, xacc::Instruction &inst) {
22  if (!inst.getBitExpression(-1).empty()) {
23  // This is a qubit...
24  auto expr = inst.getBitExpression(-1);
25  ss << "quantum::" + name + "(" << expr;
26 
27  if (inst.isParameterized() && inst.name() != "Measure") {
28  ss << ", " << inst.getParameter(0).toString();
29  for (int i = 1; i < inst.nParameters(); i++) {
30  ss << ", " << inst.getParameter(i).toString() << "\n";
31  }
32  }
33  ss << ");\n";
34 
35  return;
36  }
37 
38  // This is a qreg[IDX]
39  auto expr = inst.getBitExpression(0);
40  ss << "quantum::" + name + "(" << inst.getBufferNames()[0] << "["
41  << (expr.empty() ? std::to_string(inst.bits()[0]) : expr) << "]";
42  if (inst.isParameterized() && inst.name() != "Measure") {
43  ss << ", " << inst.getParameter(0).toString();
44  for (int i = 1; i < inst.nParameters(); i++) {
45  ss << ", " << inst.getParameter(i).toString() << "\n";
46  }
47  }
48  ss << ");\n";
49  }
50 
51  void addTwoQubitGate(const std::string name, xacc::Instruction &inst) {
52  std::string expr_src, expr_tgt;
53  if (!inst.getBitExpression(-1).empty()) {
54  expr_src = inst.getBitExpression(-1) + ", ";
55  } else {
56  expr_src = inst.getBitExpression(0);
57  expr_src = inst.getBufferNames()[0] + "["
58  + (expr_src.empty() ? std::to_string(inst.bits()[0]) : expr_src)
59  + "], ";
60  }
61  if (!inst.getBitExpression(-2).empty()) {
62  expr_tgt = inst.getBitExpression(-2);
63  } else {
64  expr_tgt = inst.getBitExpression(1);
65  expr_tgt = inst.getBufferNames()[1] + "["
66  + (expr_tgt.empty() ? std::to_string(inst.bits()[1]) : expr_tgt)
67  + "]";
68  }
69 
70  ss << "quantum::" + name + "(" << expr_src << expr_tgt;
71  // Handle parameterized gate:
72  if (inst.isParameterized()) {
73  ss << ", " << inst.getParameter(0).toString();
74  for (int i = 1; i < inst.nParameters(); i++) {
75  ss << ", " << inst.getParameter(i).toString();
76  }
77  }
78  ss << ");\n";
79  }
80 
81  public:
82  // Ctor: cache the kernel name of the CompositeInstruction
83  qrt_mapper(const std::string &top_level_kernel_name)
84  : kernelName(top_level_kernel_name) {}
85  qrt_mapper() = default;
86 
87  // Workaround cross-boundary (dlopen) dynamic type-casting issue (Apple Clang)
88  // Construct the RTTI pointer offset map as fallback for dynamic_cast.
89  virtual std::unordered_map<std::string, ptrdiff_t> getVisitorRttiMap()
90  const override {
91  // Currently, looks like only xacc::InstructionVisitor<Circuit> is having
92  // this issue, but, technically, we can add all types here if needed to.
93  static const std::unordered_map<std::string, ptrdiff_t> result{
94  {typeid(Circuit).name(),
95  ComputePointerOffset<qrt_mapper,
96  xacc::InstructionVisitor<Circuit>>()}};
97  return result;
98  }
99 
100  auto get_new_src() { return ss.str(); }
101  // One-qubit gates
102  void visit(Hadamard &h) override { addOneQubitGate("h", h); }
103  void visit(Rz &rz) override { addOneQubitGate("rz", rz); }
104  void visit(Ry &ry) override { addOneQubitGate("ry", ry); }
105  void visit(Rx &rx) override { addOneQubitGate("rx", rx); }
106  void visit(X &x) override { addOneQubitGate("x", x); }
107  void visit(Y &y) override { addOneQubitGate("y", y); }
108  void visit(Z &z) override { addOneQubitGate("z", z); }
109  void visit(S &s) override { addOneQubitGate("s", s); }
110  void visit(Sdg &sdg) override { addOneQubitGate("sdg", sdg); }
111  void visit(T &t) override { addOneQubitGate("t", t); }
112  void visit(Tdg &tdg) override { addOneQubitGate("tdg", tdg); }
113 
114  // Two-qubit gates
115  void visit(CNOT &cnot) override { addTwoQubitGate("cnot", cnot); }
116  void visit(CY &cy) override { addTwoQubitGate("cy", cy); }
117  void visit(CZ &cz) override { addTwoQubitGate("cz", cz); }
118  void visit(Swap &s) override { addTwoQubitGate("swap", s); }
119  void visit(CRZ &crz) override { addTwoQubitGate("crz", crz); }
120  void visit(CH &ch) override { addTwoQubitGate("ch", ch); }
121  void visit(CPhase &cphase) override { addTwoQubitGate("cphase", cphase); }
122 
123  void visit(Measure &measure) override { addOneQubitGate("mz", measure); }
124  void visit(Identity &i) override { addOneQubitGate("i", i); }
125  void visit(U &u) override { addOneQubitGate("u3", u); }
126  void visit(U1 &u1) override { addOneQubitGate("u1", u1); }
127  void visit(Reset &r) override { addOneQubitGate("reset", r); }
128  void visit(Circuit &circ) override {
129  if (circ.name() == kernelName) {
130  return;
131  }
132  if (circ.name() == "exp_i_theta") {
133  ss << "quantum::exp(" << circ.getBufferNames()[0] << ", "
134  << circ.getArguments()[0]->name << ", " << circ.getArguments()[1]->name
135  << ");\n";
136  } else {
137  // Call a previously-defined QCOR kernel:
138  // In this context, we disable __execute flag around this hence
139  // this sub-kernel will not be submitted.
140  // i.e. only the outer-most kernel will be submitted.
141  // Open a new scope since we use a local var '__cached_execute_flag'
142  ss << "{\n";
143  // Cache the state of the __execute flag
144  ss << "const auto __cached_execute_flag = __execute;\n";
145  // Reset the flag:
146  ss << "__execute = false;\n";
147  for (const auto &arg : circ.getArguments()) {
148  if (arg->name == "__xacc__literal_") {
149  // double nameMEMORYLOC = ...
150  ss << arg->type << " " << arg->name << arg << " = ";
151  // can be int or double
152  if (arg->runtimeValue.keyExists<int>(
153  xacc::INTERNAL_ARGUMENT_VALUE_KEY)) {
154  ss << arg->runtimeValue.get<int>(xacc::INTERNAL_ARGUMENT_VALUE_KEY)
155  << ";\n";
156  } else {
157  ss << arg->runtimeValue.get<double>(
158  xacc::INTERNAL_ARGUMENT_VALUE_KEY)
159  << ";\n";
160  }
161  }
162  }
163  // Add the circuit invocation.
164  ss << circ.name() << "(" << circ.getBufferNames()[0];
165  for (const auto &arg : circ.getArguments()) {
166  if (arg->name.find("__xacc__literal_") != std::string::npos) {
167  ss << ", " << arg->name << arg;
168  } else {
169  ss << ", " << arg->name;
170  }
171  }
172  ss << ")"
173  << ";\n";
174  // Reinstate the __execute flag
175  ss << "__execute = __cached_execute_flag;\n";
176  ss << "}\n";
177  }
178  }
179  void visit(IfStmt &ifStmt) override {}
180 };
181 } // namespace qcor
182 #endif
qcor
Definition: qcor_syntax_handler.cpp:15
qcor::qrt_mapper
Definition: qrt_mapper.hpp:14