QNLP  v1.0
GateCache.hpp
Go to the documentation of this file.
1 
9 #ifndef QNLP_GATECACHE
10 #define QNLP_GATECACHE
11 
12 #include <unordered_map>
13 #include <unordered_set>
14 
15 #include <complex>
16 #include <cassert>
17 #include <utility>
18 #include <vector>
19 #include <iostream>
20 #include <functional>
21 
22 #include <cmath>
23 #include <limits>
24 #include "mat_ops.hpp"
25 
26 namespace QNLP{
27 
37  template <class fpType>
38  inline bool fpComp(fpType theta0, fpType theta1) {
39  return std::fabs(theta0 - theta1) < std::numeric_limits<fpType>::epsilon();
40  }
41 
46  struct GateMetaData {
47  std::string labelGate; //String label for gate; X,Y,Z,H,I, or others
48 
49  std::size_t sqrt_depth = 0; //Depth of sqrt calculations, for use with NCU
50  bool adjoint = false; //Is this an adjoint
51  double theta = 0.0; //Gate parameter, if any
52 
53  GateMetaData( std::string labelGate = "",
54  std::size_t sqrt_depth = 0,
55  bool adjoint = false,
56  double theta = 0.0) : labelGate(labelGate),
58  adjoint(adjoint),
59  theta(theta)
60  { }
61 
62  bool operator==(const GateMetaData &other) const {
63  return ( !labelGate.compare(other.labelGate) &&
64  fpComp<double>(theta, other.theta) &&
65  sqrt_depth == other.sqrt_depth ); /* labels and depth should be sufficient
66  && theta == other.third);*/
67  }
68 
69  friend std::ostream& operator<<(std::ostream& os, const GateMetaData& gmd){
70  os << gmd.labelGate << ',' << gmd.sqrt_depth << ',' << gmd.adjoint << "," << gmd.theta;
71  return os;
72  }
73  };
74 
80  std::size_t operator()(const GateMetaData& gmd) const {
81  return (
82  (std::hash<std::string>{}(gmd.labelGate)
83  ^ (std::hash<double>{}(gmd.theta) << 1)) >> 1)
84  ^ (std::hash<std::size_t>{}(gmd.sqrt_depth) << 1);
85  }
86  };
87 
94  template <class SimulatorType>
95  class GateCache {
96  private:
97  std::size_t cache_depth;
98 
99  public:
100  GateCache() : cache_depth(0) { };
101 
102  GateCache(SimulatorType& qSim) : GateCache() {
103  //initCache(qSim, 16);
104  //cache_depth = 16;
105  }
106 
107  GateCache(SimulatorType& qSim, std::size_t default_depth) : cache_depth(default_depth) {
108  initCache(qSim, cache_depth);
109  }
110 
112 
113  //Take the 2x2 matrix type from the template SimulatorType
114  using GateType = decltype(std::declval<SimulatorType>().getGateX());
115 
116  //Maintain a map for each gate label (X,Y,Z, etc.), and use vectors to store sqrt (indexed by 1/2^(i), and pairing matrix and adjoint)
117  std::unordered_map<std::string, std::vector< std::pair<GateType, GateType> > > gateCacheMap;
118 
119  void clearCache(){
120  gateCacheMap.clear();
121  cache_depth = 0;
122  }
123 
130  void initCache(SimulatorType& sim, std::size_t sqrt_depth){
131  // If we do not have a sufficient circuit depth, clear and rebuild up to given depth.
132  // Could ideally use existing values and rebuild from lowest depth, but consider this
133  // after we have a working implementation.
134 
135  if(cache_depth < sqrt_depth ){
136  gateCacheMap.clear();
137  cache_depth = 0;
138  }
139 
140  if (gateCacheMap.empty()){
141 
142  gateCacheMap["X"] = std::vector< std::pair<GateType, GateType> > { std::make_pair( sim.getGateX(), adjointMatrix( sim.getGateX() ) ) };
143  gateCacheMap["Y"] = std::vector< std::pair<GateType, GateType> > { std::make_pair( sim.getGateY(), adjointMatrix( sim.getGateY() ) ) };
144  gateCacheMap["Z"] = std::vector< std::pair<GateType, GateType> > { std::make_pair( sim.getGateZ(), adjointMatrix( sim.getGateZ() ) ) };
145  gateCacheMap["H"] = std::vector< std::pair<GateType, GateType> > { std::make_pair( sim.getGateH(), adjointMatrix( sim.getGateH() ) ) };
146 
147  for( std::size_t depth = 1; depth <= sqrt_depth; depth++ ){
148  for( auto& kv : gateCacheMap ){
149  kv.second.reserve(sqrt_depth + 1);
150  auto m = matrixSqrt<GateType>(kv.second[depth-1].first);
151  kv.second.emplace(kv.second.begin() + depth, std::make_pair( m, adjointMatrix( m ) ) );
152  }
153  }
154  cache_depth = sqrt_depth;
155  }
156  }
157 
165  void addToCache(SimulatorType& sim, const std::string gateLabel, const GateType& gate, std::size_t max_depth){
166  if(max_depth <= cache_depth && gateCacheMap.find(gateLabel) != gateCacheMap.end() ){
167  return;
168  }
169  else if(max_depth > cache_depth){
171  }
172 
173  std::vector< std::pair<GateType, GateType> > v;
174 
175  v.reserve(max_depth + 1);
176  v.push_back(std::make_pair( gate, adjointMatrix( gate ) ) );
177  for( std::size_t depth = 1; depth <= max_depth; depth++ ){
178  auto m = matrixSqrt<GateType>( v[depth-1].first );
179  v.emplace(v.begin() + depth, std::make_pair( m, adjointMatrix( m ) ) );
180  }
181  gateCacheMap.emplace(std::make_pair(gateLabel, v) );
182  }
183  };
184 };
185 #endif
std::size_t sqrt_depth
Definition: GateCache.hpp:49
Meta container object for gate caching.
Definition: GateCache.hpp:46
void initCache(SimulatorType &sim, std::size_t sqrt_depth)
Initialise the gate cache with PauliX,Y,Z and H up to a given sqrt depth.
Definition: GateCache.hpp:130
Class to cache intermediate matrix values used within other parts of the computation....
Definition: GateCache.hpp:95
Mat2x2Type adjointMatrix(const Mat2x2Type &U)
Function to calculate the adjoint of an input matrix.
Definition: mat_ops.hpp:54
Templated methods to manipulate small matrices.
GateCache(SimulatorType &qSim)
Definition: GateCache.hpp:102
bool operator==(const GateMetaData &other) const
Definition: GateCache.hpp:62
std::string labelGate
Definition: GateCache.hpp:47
std::size_t cache_depth
Definition: GateCache.hpp:97
GateMetaData(std::string labelGate="", std::size_t sqrt_depth=0, bool adjoint=false, double theta=0.0)
Definition: GateCache.hpp:53
void addToCache(SimulatorType &sim, const std::string gateLabel, const GateType &gate, std::size_t max_depth)
Adds new gate to the cache up to a given sqrt depth.
Definition: GateCache.hpp:165
decltype(std::declval< SimulatorType >().getGateX()) GateType
Definition: GateCache.hpp:114
std::unordered_map< std::string, std::vector< std::pair< GateType, GateType > > > gateCacheMap
Definition: GateCache.hpp:117
std::size_t operator()(const GateMetaData &gmd) const
Definition: GateCache.hpp:80
bool fpComp(fpType theta0, fpType theta1)
Comparison of floating point values within the given machine epsilon.
Definition: GateCache.hpp:38
Hashing function for GateMetaData objects, to allow storage in unordered_map. Taken from default docs...
Definition: GateCache.hpp:79
GateCache(SimulatorType &qSim, std::size_t default_depth)
Definition: GateCache.hpp:107
friend std::ostream & operator<<(std::ostream &os, const GateMetaData &gmd)
Definition: GateCache.hpp:69