QCOR
qalloc.hpp
1 /*******************************************************************************
2  * Copyright (c) 2020 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 XACC_QALLOC_HPP_
14 #define XACC_QALLOC_HPP_
15 
16 #include <map>
17 #include <string>
18 #include <memory>
19 #include <vector>
20 
21 namespace xacc {
22 class AcceleratorBuffer;
23 class Observable;
24 namespace internal_compiler {
25 // We treat a qubit as a pair { QREG_VAR_NAME, QREG_IDX }
26 // for use with qcor QRT API we also need to keep track of the buffer
27 struct qubit;
28 struct AllocEventListener {
29  virtual void onAllocate(qubit* qubit) = 0;
30  virtual void onDealloc(qubit* qubit) = 0;
31 };
32 
33 extern AllocEventListener *getGlobalQubitManager();
34 extern void setGlobalQubitManager(AllocEventListener *);
35 
36 // This is the struct that will be embedded into the qubit
37 // to track the **true** lifetime of a qubit.
38 // It will notify the AllocEventListener once a qubit is deallocated
39 // (all copies go out of scope)
40 // Use case: scratch qubits created inside a quantum kernel.
41 struct AllocTracker {
42  qubit *m_qubit;
43  AllocEventListener *listener;
44  AllocTracker(qubit *q) : m_qubit(q), listener(getGlobalQubitManager()) {
45  listener->onAllocate(m_qubit);
46  }
47 
48  ~AllocTracker() { listener->onDealloc(m_qubit); }
49 };
50 
51 // Qubit allocator interface:
53  virtual qubit allocate() = 0;
54 };
55 
56 struct qubit {
57  std::string first;
58  std::size_t second;
59  xacc::AcceleratorBuffer *buffer;
60  xacc::AcceleratorBuffer *results() { return buffer; }
61 
62  // New allocation:
63  qubit(const std::string &reg_name, size_t idx,
64  xacc::AcceleratorBuffer *in_buffer = nullptr)
65  : first(reg_name), second(idx), buffer(in_buffer) {
66  tracker = std::make_shared<AllocTracker>(this);
67  }
68  qubit() = default;
69  // Having this tracker as a shared_ptr so that we can follow the qubit
70  // even if it is copied, e.g. via slicing.
71  // Default copy and copy assign should just copy this tracker across.
72  std::shared_ptr<AllocTracker> tracker;
73 };
74 
75 class qreg;
76 // Classical register associated with a qubit register to store single-shot
77 // measurement results. i.e. after Measure(q[0]) => q.creg[0] will contain the
78 // boolean (true/false) result of the measurement.
79 class cReg {
80 public:
81  cReg() = default;
82  cReg(std::shared_ptr<AcceleratorBuffer> in_buffer);
83  bool operator[](std::size_t i);
84 
85 private:
86  std::shared_ptr<AcceleratorBuffer> buffer;
87 };
88 
89 // A qreg is a vector of qubits
90 class qreg {
91 private:
92  std::vector<qubit> internal_qubits;
93  std::string random_string(std::size_t length);
94 
95 protected:
96  std::shared_ptr<AcceleratorBuffer> buffer;
97  bool been_named_and_stored = false;
98 
99 public:
100  struct Range {
101  std::size_t start;
102  std::size_t end;
103  std::size_t step = 1;
104  Range(std::vector<std::size_t> &s);
105  Range(std::initializer_list<std::size_t> &&s);
106  };
107 
108  qreg() = default;
109  qreg(const int n);
110  qreg(const qreg &other);
111  qreg(std::vector<qubit> &qubits);
112  qubit operator[](const std::size_t i);
113  qreg extract_range(const std::size_t& start, const std::size_t& end);
114  qreg extract_range(const Range &&range);
115  qreg extract_qubits(const std::initializer_list<std::size_t> &&qbits);
116  qreg head(const std::size_t n_qubits);
117  qubit head();
118  qubit tail();
119  qreg tail(const std::size_t n_qubits);
120  AcceleratorBuffer *results();
121  std::shared_ptr<AcceleratorBuffer> results_shared();
122  std::map<std::string, int> counts();
123  double exp_val_z();
124  void reset();
125  int size();
126  void addChild(qreg &q);
127  void setName(const char *name);
128  void setNameAndStore(const char *name);
129  std::string name();
130  void store();
131  void print();
132  double weighted_sum(Observable *obs);
133  void write_file(const std::string &file_name);
134  // friend std::ostream& operator<<(std::ostream& os, qreg& q);
135  // Public member var to simplify the single measurement syntax:
136  // i.e. we can access the single measurement results via the syntax:
137  // q.creg[i] vs. (*q.results())[i]
138  cReg creg;
139 };
140 // std::ostream& operator<<(std::ostream& os, qreg& q);
141 } // namespace internal_compiler
142 } // namespace xacc
143 
144 // Optionally provide an allocator:
145 // The idea is that during code-gen (syntax handling)
146 // we can add in a special auxillary/ancilla allocator
147 // which allocate qubits from a shared pool rather than
148 // create new qubits.
150 qalloc(const int n,
151  xacc::internal_compiler::QubitAllocator *allocator = nullptr);
152 
153 // __qpu__ indicates this functions is for the QCOR Clang Syntax Handler
154 // and annotated with quantum for the LLVM IR CodeGen
155 #define __qpu__ [[clang::syntax(qcor)]] __attribute__((annotate("quantum")))
156 
157 #endif
xacc::internal_compiler::QubitAllocator
Definition: qalloc.hpp:63
xacc::internal_compiler::qubit
Definition: qalloc.hpp:67
xacc::internal_compiler::AllocEventListener
Definition: qalloc.hpp:39
xacc::internal_compiler::AllocTracker
Definition: qalloc.hpp:52
xacc::internal_compiler::cReg
Definition: qalloc.hpp:90
xacc::internal_compiler::qreg
Definition: qalloc.hpp:101
xacc::internal_compiler::qreg::Range
Definition: qalloc.hpp:111