XACC
pulse_composite.hpp
1 /*******************************************************************************
2  * Copyright (c) 2019 UT-Battelle, LLC.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * and Eclipse Distribution License v1.0 which accompanies this
6  * distribution. The Eclipse Public License is available at
7  * http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
8  *License is available at https://eclipse.org/org/documents/edl-v10.php
9  *
10  * Contributors:
11  * Alexander J. McCaskey - initial API and implementation
12  *******************************************************************************/
13 #ifndef IBM_PULSE_COMPOSITE_INSTRUCTION_HPP_
14 #define IBM_PULSE_COMPOSITE_INSTRUCTION_HPP_
15 
16 #include "CompositeInstruction.hpp"
17 #include "pulse_instruction.hpp"
18 #include "InstructionIterator.hpp"
19 #include "Utils.hpp"
20 #include "expression_parsing_util.hpp"
21 #include "xacc_service.hpp"
22 
23 #include <limits>
24 #include <memory>
25 #include <stdexcept>
26 #include <unordered_set>
27 
28 namespace xacc {
29 namespace quantum {
30 
32  public std::enable_shared_from_this<PulseComposite> {
33 
34 private:
35  void validateInstructionIndex(const std::size_t idx) {
36  if (idx >= instructions.size()) {
37  xacc::XACCLogger::instance()->error(
38  "\nInvalid instruction index on CMD_DEF\n"
39  "CompositeInstruction:\nnInstructions() = " +
40  std::to_string(nInstructions()) + "\nidx = " + std::to_string(idx));
41  print_backtrace();
42  exit(0);
43  }
44  }
45 
46  void validateInstructionPtr(InstPtr inst) {
47  if (std::find(instructions.begin(), instructions.end(), inst) !=
48  std::end(instructions)) {
49  xacc::XACCLogger::instance()->error(
50  "\nInvalid instruction:\nThis instruction pointer already added to "
51  "CMD_DEF.");
52  print_backtrace();
53  exit(0);
54  }
55  }
56 
57  void errorCircuitParameter() const {
58  xacc::XACCLogger::instance()->error(
59  "CMD_DEF Instruction parameter API not implemented.");
60  print_backtrace();
61  exit(0);
62  }
63 
64 protected:
65  std::vector<InstPtr> instructions{};
66  std::vector<std::string> variables{};
67  std::vector<std::string> _requiredKeys{};
68 
69  std::vector<std::size_t> qbits;
70  std::string cmdDefName = "";
71 
72  std::shared_ptr<ExpressionParsingUtil> parsingUtil;
73 
74  std::complex<double> coefficient = 1.0;
75  std::string acc_signature = "";
76 
77 public:
78  PulseComposite(const std::string &name) : cmdDefName(name) {}
79  PulseComposite(const std::string &name, std::vector<std::string> &vars)
80  : cmdDefName(name), variables(vars) {}
81  PulseComposite(const std::string &name, std::vector<std::string> &&vars)
82  : cmdDefName(name), variables(vars) {}
83 
84  PulseComposite(const PulseComposite &other)
85  : cmdDefName(other.cmdDefName), variables(other.variables),
86  instructions(other.instructions), parsingUtil(other.parsingUtil) {}
87 
88  const std::string name() const override { return cmdDefName; }
89  const std::string description() const override { return ""; }
90  void setName(const std::string name) override { cmdDefName = name; }
91 
92  void mapBits(std::vector<std::size_t> bitMap) override {
93  for (auto &inst : instructions) {
94  inst->mapBits(bitMap);
95  }
96  }
97  void setBits(const std::vector<std::size_t> bits) override { qbits = bits; }
98  const std::vector<std::size_t> bits() override { return qbits; }
99 
100  const std::string toString() override {
101  std::string retStr = "";
102  std::stringstream vs;
103  vs << getVariables();
104  retStr += vs.str() + "\n";
105  for (auto i : instructions) {
106  if (i->isEnabled()) {
107  if (i->isComposite() &&
108  !std::dynamic_pointer_cast<CompositeInstruction>(i)
109  ->hasChildren()) {
110  retStr += i->name() + "()\n";
111  } else {
112  retStr += i->toString() + "\n";
113  }
114  }
115  }
116  return retStr;
117  }
118 
120  getParameter(const std::size_t idx) const override {
121  errorCircuitParameter();
122  return InstructionParameter(0);
123  }
124  void setParameter(const std::size_t idx, InstructionParameter &p) override {
125  errorCircuitParameter();
126  }
127  std::vector<InstructionParameter> getParameters() override {
128  errorCircuitParameter();
129  return {};
130  }
131  const int nParameters() override {
132  errorCircuitParameter();
133  return 0;
134  }
135 
136  const int nRequiredBits() const override { return 0; }
137 
138  void enable() override {
139  for (int i = 0; i < nInstructions(); i++) {
140  getInstruction(i)->enable();
141  }
142  }
143 
144  void disable() override {
145  for (int i = 0; i < nInstructions(); i++) {
146  getInstruction(i)->disable();
147  }
148  }
149 
150  const bool isAnalog() const override { return true; }
151 
152  void persist(std::ostream &outStream) override {}
153  void load(std::istream &inStream) override {}
154 
155  const int nInstructions() override { return instructions.size(); }
156 
157  const int nChildren() override { return instructions.size(); }
158 
159  InstPtr getInstruction(const std::size_t idx) override {
160  validateInstructionIndex(idx);
161  return instructions[idx];
162  }
163 
164  std::vector<InstPtr> getInstructions() override { return instructions; }
165  void removeInstruction(const std::size_t idx) override {
166  validateInstructionIndex(idx);
167  instructions.erase(instructions.begin() + idx);
168  }
169  void replaceInstruction(const std::size_t idx, InstPtr newInst) override {
170  validateInstructionIndex(idx);
171  // throwIfInvalidInstructionParameter(newInst);
172  instructions[idx] = newInst;
173  }
174  void insertInstruction(const std::size_t idx, InstPtr newInst) override {
175  validateInstructionIndex(idx);
176  // throwIfInvalidInstructionParameter(newInst);
177  instructions.insert(instructions.begin() + idx, newInst);
178  }
179 
180  void addInstruction(InstPtr instruction) override {
181  // throwIfInvalidInstructionParameter(instruction);
182  validateInstructionPtr(instruction);
183  instructions.push_back(instruction);
184  }
185  void addInstructions(std::vector<InstPtr> &insts) override {
186  for (auto &i : insts)
187  addInstruction(i);
188  }
189  void addInstructions(const std::vector<InstPtr> &insts) override {
190  for (auto &i : insts)
191  addInstruction(i);
192  }
193 
194  bool hasChildren() const override { return !instructions.empty(); }
195  bool expand(const HeterogeneousMap &runtimeOptions) override { return true; }
196 
197  const std::vector<std::string> requiredKeys() override {
198  return _requiredKeys;
199  }
200 
201  void addVariable(const std::string variableName) override {
202  variables.push_back(variableName);
203  }
204  void addVariables(const std::vector<std::string> &vars) override {
205  variables.insert(variables.end(), vars.begin(), vars.end());
206  }
207  const std::vector<std::string> getVariables() override {
208  // return this guys variables + all sub-node variables
209  std::vector<std::string> ret = variables;
210  for (auto &i : instructions) {
211  if (i->isComposite()) {
212  auto vars =
213  std::dynamic_pointer_cast<CompositeInstruction>(i)->getVariables();
214  ret.insert(ret.end(), vars.begin(), vars.end());
215  }
216  }
217  std::unordered_set<std::string> s(ret.begin(), ret.end());
218  ret.assign(s.begin(), s.end());
219  return ret;
220  }
221  void replaceVariable(const std::string variable,
222  const std::string newVariable) override {
223  std::replace_if(
224  variables.begin(), variables.end(),
225  [&](const std::string var) { return var == variable; }, newVariable);
226  }
227 
228  const std::size_t nVariables() override { return getVariables().size(); }
229 
230  const int depth() override { return 0; }
231  const std::string persistGraph() override { return ""; }
232  std::shared_ptr<Graph> toGraph() override { return nullptr; }
233 
234  void flatten() {}
235 
236  const std::size_t nLogicalBits() override {
237  // n logical should just be the number of
238  // unique qbit integers
239  std::set<std::size_t> bits;
240  InstructionIterator iter(shared_from_this());
241  while (iter.hasNext()) {
242  auto inst = iter.next();
243  if (!inst->isComposite()) {
244  for (auto &b : inst->bits()) {
245  bits.insert(b);
246  }
247  }
248  }
249  return bits.size();
250  }
251 
252  const std::size_t nPhysicalBits() override {
253  // n physical bits should be the largest bit
254  // plus 1
255  std::size_t maxBit = 0;
256  InstructionIterator iter(shared_from_this());
257  while (iter.hasNext()) {
258  auto inst = iter.next();
259  if (!inst->isComposite()) {
260  for (auto &b : inst->bits()) {
261  if (b > maxBit) {
262  maxBit = b;
263  }
264  }
265  }
266  }
267  return maxBit + 1;
268  }
269 
270  const std::set<std::size_t> uniqueBits() override {
271  std::set<std::size_t> uniqueBits;
272  InstructionIterator iter(shared_from_this());
273  while (iter.hasNext()) {
274  auto next = iter.next();
275  if (!next->isComposite()) {
276  for (auto &b : next->bits()) {
277  uniqueBits.insert(b);
278  }
279  }
280  }
281 
282  return uniqueBits;
283  }
284 
285  std::shared_ptr<CompositeInstruction> enabledView() override {
286  auto newF = std::make_shared<PulseComposite>(this->cmdDefName);
287  for (int i = 0; i < nInstructions(); i++) {
288  auto inst = getInstruction(i);
289  if (inst->isEnabled()) {
290  newF->addInstruction(inst);
291  }
292  }
293  return newF;
294  }
295 
296  void setCoefficient(const std::complex<double> c) override {
297  coefficient = c;
298  }
299  const std::complex<double> getCoefficient() override { return coefficient; }
300 
301  std::shared_ptr<CompositeInstruction>
302  operator()(const std::vector<double> &params) override {
303  if (!parsingUtil) {
304  parsingUtil = xacc::getService<ExpressionParsingUtil>("exprtk");
305  }
306  variables.erase( std::unique( variables.begin(), variables.end() ), variables.end() );
307  std::vector<InstPtr> flatten;
308  InstructionIterator iter(shared_from_this());
309  while (iter.hasNext()) {
310  auto inst = iter.next();
311  if (!inst->isComposite()) {
312  flatten.emplace_back(inst);
313  }
314  }
315 
316  auto evaluatedCircuit = std::make_shared<PulseComposite>("evaled_" + name());
317 
318  // Walk the IR Tree, handle functions and instructions differently
319  for (auto inst : flatten) {
320  // if (inst->isParameterized()) {
321  auto updatedInst =
322  std::dynamic_pointer_cast<PulseInstruction>(inst)->clone();
323 
324  // Really we only care about the phase...
325  // In future we might care about functional form params
326  for (int i = 0; i < inst->nParameters(); i++) {
327  if (inst->getParameter(i).isVariable()) {
328  InstructionParameter p = inst->getParameter(i);
329  double val;
330  if (parsingUtil->evaluate(p.toString(), variables, params, val)) {
331  updatedInst->setParameter(i, val);
332  } else {
333  updatedInst->setParameter(i, p);
334  }
335  } else {
336  auto a = inst->getParameter(i);
337  updatedInst->setParameter(i, a);
338  }
339  updatedInst->setBits(inst->bits());
340  }
341 
342 
343  evaluatedCircuit->addInstruction(updatedInst);
344  }
345 
346  // else {
347  // evaluatedCircuit->addInstruction(inst);
348  // }
349  return evaluatedCircuit;
350  }
351 
352  const std::string accelerator_signature() override { return acc_signature; }
353  void set_accelerator_signature(const std::string signature) override {
354  acc_signature = signature;
355  }
356 
357  DEFINE_VISITABLE()
358  std::shared_ptr<Instruction> clone() override {
359  return std::make_shared<PulseComposite>(*this);
360  }
361  virtual ~PulseComposite() {}
362 };
363 
364 } // namespace quantum
365 } // namespace xacc
366 #endif
const std::string name() const override
Definition: pulse_composite.hpp:88
const std::string description() const override
Definition: pulse_composite.hpp:89
std::shared_ptr< Instruction > next()
Definition: InstructionIterator.hpp:58
bool hasNext()
Definition: InstructionIterator.hpp:52
Definition: Accelerator.hpp:25
Definition: InstructionIterator.hpp:24
Definition: heterogeneous.hpp:45
Definition: pulse_instruction.hpp:22
Definition: CompositeInstruction.hpp:72
Definition: pulse_composite.hpp:31