QNLP  v1.0
Simulator.hpp
Go to the documentation of this file.
1 //##############################################################################
15 //##############################################################################
16 
17 #ifndef QNLP_SIMULATOR_H
18 #define QNLP_SIMULATOR_H
19 #include <cstddef>
20 #include <utility> //std::declval
21 #include <vector>
22 #include <iostream>
23 
24 // Include all additional modules to be used within simulator
25 #include "GateWriter.hpp"
26 #include "ncu.hpp"
27 #include "oracle.hpp"
28 #include "diffusion.hpp"
29 #include "qft.hpp"
30 #include "arithmetic.hpp"
31 #include "bin_into_superpos.hpp"
32 #include "hamming.hpp"
33 #include "bit_group.hpp"
34 
35 #if defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER)
36 //pybind11 fails to compile with icpc using cpp17 support, so fallback to 14 if necessary
37 #include <experimental/any>
38 #else
39 #include <any>
40 #endif
41 
42 #ifdef VIRTUAL_INTERFACE
43 #include "ISimulator.hpp"
44 #endif
45 
46 #ifdef ENABLE_MPI
47 #include "mpi.h"
48 #endif
49 
50 namespace QNLP{
51 
52  /*
53  * @brief Returns the boolean True if the bit at index 'bit' in 'byte' is set to 1, else returns False
54  *
55  * @param byte An integer whose bit at index 'bit' is being tested if it is set
56  * @param bit The index into the integer 'byte' being tested if it is set
57  */
58  #define IS_SET(byte,bit) (((byte) & (1UL << (bit))) >> (bit))
59 
65  template <class DerivedType>
66  #ifdef VIRTUAL_INTERFACE
67  class SimulatorGeneral : virtual public ISimulator {
68  #else
70  #endif
71 
72  private:
78  //If we are building MPI support, ensure that it is init'd here before subclasses.
79  #ifdef ENABLE_MPI
80  int mpi_is_init;
81  MPI_Initialized(&mpi_is_init);
82  if (! mpi_is_init){
83  int argc_tmp = 0;
84  char** argv_tmp = new char*[argc_tmp];
85  MPI_Init(&argc_tmp, &argv_tmp);
86  delete argv_tmp;
87  }
88  #endif
89 
90  sim_ncu = NCU<DerivedType>(static_cast<DerivedType&>(*this));
91  };
92 
93  friend DerivedType;
94 
95  protected:
96  #ifdef GATE_LOGGING
97  GateWriter writer;
98  #endif
99 
100 
101  #if defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER)
102  std::experimental::any sim_ncu;
103  #else
104  std::any sim_ncu;
105  #endif
106 
107  public:
108  //using Mat2x2Type = decltype(std::declval<DerivedType>().getGateX());
113  virtual ~SimulatorGeneral(){ }
114  //##############################################################################
115  // Single qubit gates
116  //##############################################################################
117 
123  void applyGateX(std::size_t qubit_idx){
124  static_cast<DerivedType&>(*this).applyGateX(qubit_idx);
125  };
131  void applyGateY(std::size_t qubit_idx){
132  static_cast<DerivedType&>(*this).applyGateY(qubit_idx);
133  }
139  void applyGateZ(std::size_t qubit_idx){
140  static_cast<DerivedType&>(*this).applyGateZ(qubit_idx);
141  }
147  void applyGateI(std::size_t qubit_idx){
148  static_cast<DerivedType&>(*this).applyGateI(qubit_idx);
149  }
155  void applyGateH(std::size_t qubit_idx){
156  static_cast<DerivedType&>(*this).applyGateH(qubit_idx);
157  }
163  void applyGateSqrtX(std::size_t qubit_idx){
164  static_cast<DerivedType&>(*this).applyGateSqrtX(qubit_idx);
165  }
172  void applyGateRotX(std::size_t qubit_idx, double angle_rad){
173  static_cast<DerivedType&>(*this).applyGateRotX(qubit_idx, angle_rad);
174  }
181  void applyGateRotY(std::size_t qubit_idx, double angle_rad){
182  static_cast<DerivedType&>(*this).applyGateRotY(qubit_idx, angle_rad);
183  }
190  void applyGateRotZ(std::size_t qubit_idx, double angle_rad){
191  static_cast<DerivedType&>(*this).applyGateRotZ(qubit_idx, angle_rad);
192  }
193 
200  template<class Mat2x2Type>
201  void applyGateU(const Mat2x2Type &U, std::size_t qubit_idx){
202  static_cast<DerivedType*>(this)->applyGateU(U, qubit_idx);
203  }
204 
209  decltype(auto) getGateX() {
210  return static_cast<DerivedType&>(*this).getGateX();
211  }
212 
217  decltype(auto) getGateY(){
218  return static_cast<DerivedType&>(*this).getGateY();
219  }
224  decltype(auto) getGateZ(){
225  return static_cast<DerivedType&>(*this).getGateZ();
226  }
231  decltype(auto) getGateI(){
232  return static_cast<DerivedType*>(this)->getGateI();
233  }
238  decltype(auto) getGateH(){
239  return static_cast<DerivedType*>(this)->getGateH();
240  }
241 
242  //##############################################################################
243  // 2 qubit gates
244  //##############################################################################
245 
253  template<class Mat2x2Type>
254  void applyGateCU(const Mat2x2Type &U, const std::size_t control, const std::size_t target, std::string label="CU"){
255  static_cast<DerivedType*>(this)->applyGateCU(U, control, target, label);
256  }
257 
264  void applyGateCX(const std::size_t control, const std::size_t target){
265  static_cast<DerivedType*>(this)->applyGateCX(control, target);
266  }
267 
274  void applyGateCY(const std::size_t control, const std::size_t target){
275  static_cast<DerivedType*>(this)->applyGateCY(control, target);
276  }
277 
284  void applyGateCZ(const std::size_t control, const std::size_t target){
285  static_cast<DerivedType*>(this)->applyGateCZ(control, target);
286  }
287 
294  void applyGateCH(const std::size_t control, const std::size_t target){
295  static_cast<DerivedType*>(this)->applyGateCH(control, target);
296  }
297 
304  void applyGateSwap(std::size_t qubit_idx0, std::size_t qubit_idx1){
305  static_cast<DerivedType*>(this)->applyGateSwap(qubit_idx0,qubit_idx1);
306  }
307 
314  void applyGateSqrtSwap(std::size_t qubit_idx0, std::size_t qubit_idx1){
315  static_cast<DerivedType*>(this)->applyGateSqrtSwap(qubit_idx0,qubit_idx1);
316  }
317 
324  void applyGatePhaseShift(double angle, std::size_t qubit_idx){
325  static_cast<DerivedType*>(this)->applyGatePhaseShift(angle, qubit_idx);
326  }
327 
335  void applyGateCPhaseShift(double angle, std::size_t control, std::size_t target){
336  static_cast<DerivedType*>(this)->applyGateCPhaseShift(angle, control, target);
337  }
338 
346  void applyGateCCX(std::size_t ctrl_qubit0, std::size_t ctrl_qubit1, std::size_t target_qubit){
347  static_cast<DerivedType*>(this)->applyGateCCX(ctrl_qubit0, ctrl_qubit1, target_qubit);
348  }
349 
357  void applyGateCSwap(std::size_t ctrl_qubit, std::size_t qubit_swap0, std::size_t qubit_swap1){
358  assert( static_cast<DerivedType*>(this)->getNumQubits() > 2 );
359  //The requested qubit indices must be available to use within the register range
360  assert( (ctrl_qubit < getNumQubits() ) && (qubit_swap0 < getNumQubits() ) && (qubit_swap1 < getNumQubits()) );
361  //The qubits must be different from one another
362  assert( ctrl_qubit != qubit_swap0 && ctrl_qubit != qubit_swap1 && qubit_swap0 != qubit_swap1 );
363  static_cast<DerivedType*>(this)->applyGateCSwap(ctrl_qubit, qubit_swap0, qubit_swap1);
364  }
365 
373  void applyGateCRotX(std::size_t ctrl_qubit, std::size_t qubit_idx, double angle_rad){
374  static_cast<DerivedType&>(*this).applyGateCRotX(ctrl_qubit, qubit_idx, angle_rad);
375  }
376 
384  void applyGateCRotY(std::size_t ctrl_qubit, std::size_t qubit_idx, double angle_rad){
385  static_cast<DerivedType&>(*this).applyGateCRotY(ctrl_qubit, qubit_idx, angle_rad);
386  }
387 
395  void applyGateCRotZ(std::size_t ctrl_qubit, std::size_t qubit_idx, double angle_rad){
396  static_cast<DerivedType&>(*this).applyGateCRotZ(ctrl_qubit, qubit_idx, angle_rad);
397  }
398 
404  decltype(auto) getQubitRegister(){
405  return static_cast<DerivedType*>(this)->getQubitRegister();
406  }
407 
413  std::size_t getNumQubits(){
414  return static_cast<DerivedType*>(this)->getNumQubits();
415  }
416 
423  void applyQFT(std::size_t minIdx, std::size_t maxIdx){
424  QFT<decltype(static_cast<DerivedType&>(*this))>::applyQFT(static_cast<DerivedType&>(*this), minIdx, maxIdx);
425  }
426 
433  void applyIQFT(std::size_t minIdx, std::size_t maxIdx){
434  QFT<decltype(static_cast<DerivedType&>(*this))>::applyIQFT(static_cast<DerivedType&>(*this), minIdx, maxIdx);
435  }
436 
437 
441  void sumReg(std::size_t r0_minIdx, std::size_t r0_maxIdx, std::size_t r1_minIdx, std::size_t r1_maxIdx){
442  Arithmetic<decltype(static_cast<DerivedType&>(*this))>::sum_reg(static_cast<DerivedType&>(*this), r0_minIdx, r0_maxIdx, r1_minIdx, r1_maxIdx);
443  }
444 
448  void subReg(std::size_t r0_minIdx, std::size_t r0_maxIdx, std::size_t r1_minIdx, std::size_t r1_maxIdx){
449  Arithmetic<decltype(static_cast<DerivedType&>(*this))>::sub_reg(static_cast<DerivedType&>(*this), r0_minIdx, r0_maxIdx, r1_minIdx, r1_maxIdx);
450  }
451 
461  template<class Mat2x2Type>
462  void applyGateNCU(const Mat2x2Type& U, const std::vector<std::size_t>& ctrlIndices, std::size_t target, std::string label){
463  #if defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER)
464  std::experimental::any_cast<NCU<DerivedType>&>(sim_ncu).applyNQubitControl(static_cast<DerivedType&>(*this), ctrlIndices, {}, target, label, U, 0);
465  #else
466  std::any_cast<NCU<DerivedType>&>(sim_ncu).applyNQubitControl(static_cast<DerivedType&>(*this), ctrlIndices, {}, target, label, U, 0);
467  #endif
468  }
469 
479  template<class Mat2x2Type>
480  void applyGateNCU(const Mat2x2Type& U, const std::vector<std::size_t>& ctrlIndices, const std::vector<std::size_t>& auxIndices, std::size_t target, std::string label){
481  #if defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER)
482  std::experimental::any_cast<NCU<DerivedType>&>(sim_ncu).applyNQubitControl(static_cast<DerivedType&>(*this), ctrlIndices, auxIndices, target, label, U, 0);
483  #else
484  std::any_cast<NCU<DerivedType>&>(sim_ncu).applyNQubitControl(static_cast<DerivedType&>(*this), ctrlIndices, auxIndices, target, label, U, 0);
485  #endif
486  }
487 
497  template<class Mat2x2Type>
498  void applyOracleU(std::size_t bit_pattern, const std::vector<std::size_t>& ctrlIndices, std::size_t target, const Mat2x2Type& U , std::string gateLabel){
499  Oracle<DerivedType>::bitStringNCU(static_cast<DerivedType&>(*this), bit_pattern, ctrlIndices, target, U, gateLabel);
500  }
501 
512  template<class Mat2x2Type>
513  void applyOracleU(std::size_t bit_pattern, const std::vector<std::size_t>& ctrlIndices, const std::vector<std::size_t>& auxIndices, std::size_t target, const Mat2x2Type& U , std::string gateLabel){
514  Oracle<DerivedType>::bitStringNCU(static_cast<DerivedType&>(*this), bit_pattern, ctrlIndices, auxIndices, target, U, gateLabel);
515  }
516 
524  void applyOraclePhase(std::size_t bit_pattern, const std::vector<std::size_t>& ctrlIndices, std::size_t target){
525  //applyOracleU<decltype(static_cast<DerivedType*>(this)->getGateZ())>(bit_pattern, ctrlIndices, target, static_cast<DerivedType*>(this)->getGateZ());
526  Oracle<DerivedType> oracle;
527  oracle.bitStringPhaseOracle(static_cast<DerivedType&>(*this), bit_pattern, ctrlIndices, target );
528  }
529 
536  void applyDiffusion(const std::vector<std::size_t>& ctrlIndices, std::size_t target){
537  Diffusion<DerivedType> diffusion;
538  diffusion.applyOpDiffusion(static_cast<DerivedType&>(*this), ctrlIndices, target);
539  }
540 
548  void encodeToRegister(std::size_t target_pattern,
549  const std::vector<std::size_t> target_register,
550  std::size_t len_bin_pattern){
551 
552  for(std::size_t i = 0; i < len_bin_pattern; i++){
553  if(IS_SET(target_pattern,i)){
554  applyGateX(target_register[i]);
555  }
556  }
557  }
558 
567  void encodeBinToSuperpos_unique(const std::vector<std::size_t>& reg_memory,
568  const std::vector<std::size_t>& reg_auxiliary,
569  const std::vector<std::size_t>& bin_patterns,
570  const std::size_t len_bin_pattern){
571 
572  EncodeBinIntoSuperpos<DerivedType> encoder(bin_patterns.size(), len_bin_pattern);
573  encoder.encodeBinInToSuperpos_unique(static_cast<DerivedType&>(*this), reg_memory, reg_auxiliary, bin_patterns);
574  }
575 
585  const std::vector<std::size_t> reg_mem,
586  const std::vector<std::size_t> reg_auxiliary,
587  std::size_t len_bin_pattern){
588 
589  assert(len_bin_pattern < reg_auxiliary.size()-1);
590 
591  // Encode test pattern to auxiliary register
592  encodeToRegister(test_pattern, reg_auxiliary, len_bin_pattern);
593 
594  HammingDistance<DerivedType> hamming_operator(len_bin_pattern);
595  hamming_operator.computeHammingDistanceRotY(static_cast<DerivedType&>(*this), reg_mem, reg_auxiliary, len_bin_pattern);
596 
597  // Un-encode test pattern from auxiliary register
598  encodeToRegister(test_pattern, reg_auxiliary, len_bin_pattern);
599  }
600 
601 
610  const std::vector<std::size_t> reg_mem,
611  const std::vector<std::size_t> reg_auxiliary,
612  std::size_t len_bin_pattern){
613 
614  assert(reg_mem.size() < reg_auxiliary.size()-1);
615 
616  // Encode test pattern to auxiliary register
617  encodeToRegister(test_pattern, reg_auxiliary, len_bin_pattern);
618 
619  HammingDistance<DerivedType>::computeHammingDistanceOverwriteAux(static_cast<DerivedType&>(*this), reg_mem, reg_auxiliary);
620  }
621 
629  bool applyMeasurement(std::size_t target, bool normalize=true){
630  return static_cast<DerivedType*>(this)->applyMeasurement(target, normalize);
631  }
632 
640  std::size_t applyMeasurementToRegister(std::vector<std::size_t> target_qubits, bool normalize=true){
641  // Store current state of training register in it's integer format
642  std::size_t val = 0;
643  for(int j = target_qubits.size() - 1; j > -1; j--){
644  val |= (static_cast<DerivedType*>(this)->applyMeasurement(target_qubits[j], normalize) << j);
645  }
646  return val;
647  }
648 
656  void groupQubits(const std::vector<std::size_t> reg_auxiliary, bool lsb=true){
657  assert( reg_auxiliary.size() >= 2);
658 
659  const std::vector<std::size_t> reg_ctrl ( reg_auxiliary.end()-2, reg_auxiliary.end() );
660  const std::vector<std::size_t> sub_reg (reg_auxiliary.begin(), reg_auxiliary.end()-2 ) ;
661 
662  BitGroup<DerivedType>::bit_group(static_cast<DerivedType&>(*this), sub_reg, reg_ctrl, lsb);
663  }
664 
671  void collapseToBasisZ(std::size_t target, bool collapseValue){
672  static_cast<DerivedType*>(this)->collapseToBasisZ(target, collapseValue);
673  }
674 
679  void initRegister(){
680  static_cast<DerivedType&>(*this).initRegister();
681  }
682 
687  void initCaches(){
688  #if defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER)
689  std::experimental::any_cast<NCU<DerivedType>&>(sim_ncu).initialiseMaps(static_cast<DerivedType&>(*this), 16);
690  #else
691  std::any_cast<NCU<DerivedType>&>(sim_ncu).initialiseMaps(static_cast<DerivedType&>(*this), 16);
692  #endif
693  }
694 
702  template<class Mat2x2Type>
703  void addUToCache(std::string gateLabel, const Mat2x2Type& U){
704  #if defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER)
705  std::experimental::any_cast<NCU<DerivedType>&>(sim_ncu).getGateCache().addToCache(static_cast<DerivedType&>(*this), gateLabel, U, 16);
706  #else
707  std::any_cast<NCU<DerivedType>&>(sim_ncu).getGateCache().addToCache(static_cast<DerivedType&>(*this), gateLabel, U, 16);
708  #endif
709  }
710 
717  void PrintStates(std::string x, std::vector<std::size_t> qubits = {}){
718  static_cast<DerivedType*>(this)->PrintStates(x, qubits);
719  }
720 
728  template<class Mat2x2Type>
729  Mat2x2Type matrixSqrt(const Mat2x2Type& U){
730  Mat2x2Type V(U);
731  std::complex<double> delta = U(0,0)*U(1,1) - U(0,1)*U(1,0);
732  std::complex<double> tau = U(0,0) + U(1,1);
733  std::complex<double> s = sqrt(delta);
734  std::complex<double> t = sqrt(tau + 2.0*s);
735 
736  //must be a way to vectorise these; TinyMatrix have a scale/shift option?
737  V(0,0) += s;
738  V(1,1) += s;
739  std::complex<double> scale_factor(1.,0.);
740  scale_factor/=t;
741  V(0,0) *= scale_factor; //(std::complex<double>(1.,0.)/t);
742  V(0,1) *= scale_factor; //(1/t);
743  V(1,0) *= scale_factor; //(1/t);
744  V(1,1) *= scale_factor; //(1/t);
745 
746  return V;
747  }
748 
756  template<class Mat2x2Type>
757  static Mat2x2Type adjointMatrix(const Mat2x2Type& U){
758  Mat2x2Type Uadjoint(U);
759  std::complex<double> tmp;
760  tmp = Uadjoint(0,1);
761  Uadjoint(0,1) = Uadjoint(1,0);
762  Uadjoint(1,0) = tmp;
763  Uadjoint(0,0) = std::conj(Uadjoint(0,0));
764  Uadjoint(0,1) = std::conj(Uadjoint(0,1));
765  Uadjoint(1,0) = std::conj(Uadjoint(1,0));
766  Uadjoint(1,1) = std::conj(Uadjoint(1,1));
767  return Uadjoint;
768  }
769 
776  void InvertRegister(const unsigned int minIdx, const unsigned int maxIdx){
777  unsigned int range2 = ((maxIdx - minIdx)%2 == 1) ? (maxIdx - minIdx)/2 +1 : (maxIdx - minIdx)/2;
778  for(unsigned int idx = 0; idx < range2; idx++){
779  applyGateSwap(minIdx+idx, maxIdx-idx);
780  }
781  }
782 
783  #ifdef GATE_LOGGING
784 
789  GateWriter& getGateWriter(){
790  return writer;
791  }
792  #endif
793  };
794 }
795 #endif
void applyGateRotY(std::size_t qubit_idx, double angle_rad)
Apply the given Rotation about Y-axis to the given qubit.
Definition: Simulator.hpp:181
void applyGateCY(const std::size_t control, const std::size_t target)
Apply Controlled Pauli-Y on target qubit.
Definition: Simulator.hpp:274
void applyIQFT(std::size_t minIdx, std::size_t maxIdx)
Apply the inverse Quantum Fourier transform (IQFT) to the given register index range.
Definition: Simulator.hpp:433
void applyGateRotZ(std::size_t qubit_idx, double angle_rad)
Apply the given Rotation about Z-axis to the given qubit.
Definition: Simulator.hpp:190
Functions to compute the Hamming distance between a test pattern and the states in memory using y rot...
SimulatorGeneral()
Construct a new Simulator General object.
Definition: Simulator.hpp:77
void applyGateCSwap(std::size_t ctrl_qubit, std::size_t qubit_swap0, std::size_t qubit_swap1)
Controlled SWAP gate.
Definition: Simulator.hpp:357
void groupQubits(const std::vector< std::size_t > reg_auxiliary, bool lsb=true)
Group all set qubits to MSB in register (ie |010100> -> |000011>)
Definition: Simulator.hpp:656
Class definition for implementing the Hamming distance routine along with controlled Y rotations to e...
Definition: hamming.hpp:26
static void bit_group(SimulatorType &qSim, const std::vector< std::size_t > &qreg_idx, const std::vector< std::size_t > &qaux_idx, bool lsb=true)
Swaps all qubits in register indices given by qreg_idx to their right-most positions....
Definition: bit_group.hpp:114
void applyGateSwap(std::size_t qubit_idx0, std::size_t qubit_idx1)
Swap the qubits at the given indices.
Definition: Simulator.hpp:304
void applyGateZ(std::size_t qubit_idx)
Apply the Pauli Z gate to the given qubit.
Definition: Simulator.hpp:139
void encodeBinInToSuperpos_unique(SimulatorType &qSim, const std::vector< std::size_t > &reg_memory, const std::vector< std::size_t > &reg_auxiliary, const std::vector< std::size_t > &bin_patterns)
Encodes each element of inputted vector as a binary string in a superpostiion of states....
std::size_t applyMeasurementToRegister(std::vector< std::size_t > target_qubits, bool normalize=true)
Apply measurement to a set of target qubits, randomly collapsing the qubits proportional to the ampli...
Definition: Simulator.hpp:640
void PrintStates(std::string x, std::vector< std::size_t > qubits={})
Prints the string x and then for each state of the specified qubits in the superposition,...
Definition: Simulator.hpp:717
#define IS_SET(byte, bit)
Definition: Simulator.hpp:58
void applyGateCRotY(std::size_t ctrl_qubit, std::size_t qubit_idx, double angle_rad)
Apply the given Controlled Rotation about Y-axis to the given qubit.
Definition: Simulator.hpp:384
void applyGateNCU(const Mat2x2Type &U, const std::vector< std::size_t > &ctrlIndices, std::size_t target, std::string label)
Apply n-control unitary gate to the given qubit target.
Definition: Simulator.hpp:462
CRTP defined class for simulator implementations.
Definition: Simulator.hpp:69
void InvertRegister(const unsigned int minIdx, const unsigned int maxIdx)
Invert the register about the given indides: 0,1,2...n-1,n -> n,n-1,...,1,0.
Definition: Simulator.hpp:776
void encodeToRegister(std::size_t target_pattern, const std::vector< std::size_t > target_register, std::size_t len_bin_pattern)
Encodes a defined binary pattern into a defined target register (initially in state |00....
Definition: Simulator.hpp:548
void applyGateX(std::size_t qubit_idx)
Apply the Pauli X gate to the given qubit.
Definition: Simulator.hpp:123
decltype(auto) getGateX()
Get the Pauli-X gate; returns templated type GateType.
Definition: Simulator.hpp:209
std::size_t getNumQubits()
Get the number of Qubits.
Definition: Simulator.hpp:413
void applyQFT(std::size_t minIdx, std::size_t maxIdx)
Apply the forward Quantum Fourier transform (QFT) to the given register index range.
Definition: Simulator.hpp:423
void applyGateRotX(std::size_t qubit_idx, double angle_rad)
Apply the given Rotation about X-axis to the given qubit.
Definition: Simulator.hpp:172
Class definition for performing quantum forward and inverse Fourier transforms.
Definition: qft.hpp:23
void applyHammingDistanceOverwrite(std::size_t test_pattern, const std::vector< std::size_t > reg_mem, const std::vector< std::size_t > reg_auxiliary, std::size_t len_bin_pattern)
Computes the relative Hamming distance between the test pattern and the pattern stored in each state ...
Definition: Simulator.hpp:609
Class definition for applying n-qubit controlled unitary operations.
Definition: ncu.hpp:29
bool applyMeasurement(std::size_t target, bool normalize=true)
Apply measurement to a target qubit, randomly collapsing the qubit proportional to the amplitude and ...
Definition: Simulator.hpp:629
void applyOraclePhase(std::size_t bit_pattern, const std::vector< std::size_t > &ctrlIndices, std::size_t target)
Apply oracle to match given binary index with linearly adjacent controls.
Definition: Simulator.hpp:524
static void computeHammingDistanceRotY(SimulatorType &qSim, const std::vector< std::size_t > &reg_memory, const std::vector< std::size_t > &reg_auxiliary, std::size_t len_bin_pattern)
Computes Hamming Distance; adjusts each state's amplitude proportional to the Hamming distance betwee...
Definition: hamming.hpp:64
Class definition for bit-wise summation and subtraction of qubits.
Definition: arithmetic.hpp:22
Implements the forward and inverse quantum Fourier transform.
void applyGateCX(const std::size_t control, const std::size_t target)
Apply Controlled Pauli-X (CNOT) on target qubit.
Definition: Simulator.hpp:264
Functions for applying n-qubit controlled U (unitary) gates.
void applyDiffusion(const std::vector< std::size_t > &ctrlIndices, std::size_t target)
Apply diffusion operator on marked state.
Definition: Simulator.hpp:536
Define thee abstract interface class for implementing the QNLP-quantum simulator connector.
void applyOracleU(std::size_t bit_pattern, const std::vector< std::size_t > &ctrlIndices, const std::vector< std::size_t > &auxIndices, std::size_t target, const Mat2x2Type &U, std::string gateLabel)
Apply oracle to match given binary index with non adjacent controls.
Definition: Simulator.hpp:513
virtual ~SimulatorGeneral()
Destroy the Simulator General object.
Definition: Simulator.hpp:113
Implements grouping of bits to LSB side of register.
void applyGateI(std::size_t qubit_idx)
Apply the Identity gate to the given qubit.
Definition: Simulator.hpp:147
void applyGateY(std::size_t qubit_idx)
Apply the Pauli Y gate to the given qubit.
Definition: Simulator.hpp:131
void collapseToBasisZ(std::size_t target, bool collapseValue)
Apply measurement to a target qubit with respect to the Z-basis, collapsing to a specified value (0 o...
Definition: Simulator.hpp:671
void applyHammingDistanceRotY(std::size_t test_pattern, const std::vector< std::size_t > reg_mem, const std::vector< std::size_t > reg_auxiliary, std::size_t len_bin_pattern)
Computes the relative Hamming distance between the test pattern and the pattern stored in each state ...
Definition: Simulator.hpp:584
Class definition for defining and applying an Oracle.
Definition: oracle.hpp:26
void sumReg(std::size_t r0_minIdx, std::size_t r0_maxIdx, std::size_t r1_minIdx, std::size_t r1_maxIdx)
Applies |r1>|r2> -> |r1>|r1+r2>
Definition: Simulator.hpp:441
Class definition for applying Grover diffusion to a marked register.
Definition: diffusion.hpp:27
void applyGatePhaseShift(double angle, std::size_t qubit_idx)
Apply phase shift to given Qubit; [[1 0] [0 exp(i*angle)]].
Definition: Simulator.hpp:324
static void bitStringPhaseOracle(SimulatorType &s, std::size_t bitstring, const std::vector< std::size_t > &ctrlIndices, std::size_t target)
Takes bitstring as the binary pattern and indices as the qubits to operate upon. Applies the appropri...
Definition: oracle.hpp:126
void applyGateCCX(std::size_t ctrl_qubit0, std::size_t ctrl_qubit1, std::size_t target_qubit)
Controlled controlled NOT (CCNOT, CCX) gate.
Definition: Simulator.hpp:346
static Mat2x2Type adjointMatrix(const Mat2x2Type &U)
Function to calculate the adjoint of an input matrix.
Definition: Simulator.hpp:757
static void computeHammingDistanceOverwriteAux(SimulatorType &qSim, const std::vector< std::size_t > &reg_memory, const std::vector< std::size_t > &reg_auxiliary)
Computes Hamming Distance; Overwrites the pattern in reg_auxiliary to track bit differences from reg_...
Definition: hamming.hpp:102
Functions for applying black-box like functions to select appropriate qubits matching given patterns.
void applyGateU(const Mat2x2Type &U, std::size_t qubit_idx)
Apply arbitrary user-defined unitary gate to qubit at qubit_idx.
Definition: Simulator.hpp:201
static void bitStringNCU(SimulatorType &s, std::size_t bitstring, const std::vector< std::size_t > &ctrl_indices, const std::size_t target, const Mat2x2Type &U, std::string gateLabel)
Takes bitstring as the binary pattern and indices as the qubits to operate upon. Applies the appropri...
Definition: oracle.hpp:54
Defines class with operator which applies the Grover diffusion to a marked register....
void applyOpDiffusion(SimulatorType &sim, const std::vector< std::size_t > &ctrlIndices, const std::size_t target)
Application of the Grover diffusion operator to already marked register. Follows the Q = -A S_0 A str...
Definition: diffusion.hpp:49
void applyOracleU(std::size_t bit_pattern, const std::vector< std::size_t > &ctrlIndices, std::size_t target, const Mat2x2Type &U, std::string gateLabel)
Apply oracle to match given binary index with non adjacent controls.
Definition: Simulator.hpp:498
decltype(auto) getQubitRegister()
Get the underlying qubit register object.
Definition: Simulator.hpp:404
decltype(auto) getGateY()
Get the Pauli-Y gate; must be overloaded with appropriate return type.
Definition: Simulator.hpp:217
void applyGateSqrtSwap(std::size_t qubit_idx0, std::size_t qubit_idx1)
Performs Sqrt SWAP gate between two given qubits (half way SWAP)
Definition: Simulator.hpp:314
decltype(auto) getGateH()
Get the Hadamard gate; must be overloaded with appropriate return type.
Definition: Simulator.hpp:238
void encodeBinToSuperpos_unique(const std::vector< std::size_t > &reg_memory, const std::vector< std::size_t > &reg_auxiliary, const std::vector< std::size_t > &bin_patterns, const std::size_t len_bin_pattern)
Encode inputted binary strings to the memory register specified as a superposition of states....
Definition: Simulator.hpp:567
void applyGateNCU(const Mat2x2Type &U, const std::vector< std::size_t > &ctrlIndices, const std::vector< std::size_t > &auxIndices, std::size_t target, std::string label)
Apply n-control sigma_x gate to the given qubit target, using auxiliary qubits for 5CX optimisation.
Definition: Simulator.hpp:480
void applyGateCH(const std::size_t control, const std::size_t target)
Apply Controlled Hadamard on target qubit.
Definition: Simulator.hpp:294
void subReg(std::size_t r0_minIdx, std::size_t r0_maxIdx, std::size_t r1_minIdx, std::size_t r1_maxIdx)
Applies |r1>|r2> -> |r1>|r1-r2>
Definition: Simulator.hpp:448
void applyGateCRotX(std::size_t ctrl_qubit, std::size_t qubit_idx, double angle_rad)
Apply the given Controlled Rotation about X-axis to the given qubit.
Definition: Simulator.hpp:373
void applyGateSqrtX(std::size_t qubit_idx)
Apply the Sqrt{Pauli X} gate to the given qubit.
Definition: Simulator.hpp:163
void addUToCache(std::string gateLabel, const Mat2x2Type &U)
Adds a matrix to the cache, assigning it to a defined label. This is used in the caching for the NCU ...
Definition: Simulator.hpp:703
void applyGateH(std::size_t qubit_idx)
Apply the Hadamard gate to the given qubit.
Definition: Simulator.hpp:155
void applyGateCU(const Mat2x2Type &U, const std::size_t control, const std::size_t target, std::string label="CU")
Apply the given controlled unitary gate on target qubit.
Definition: Simulator.hpp:254
void initCaches()
Initialise caches used in NCU operation.
Definition: Simulator.hpp:687
void applyGateCRotZ(std::size_t ctrl_qubit, std::size_t qubit_idx, double angle_rad)
Apply the given Controlled Rotation about Z-axis to the given qubit.
Definition: Simulator.hpp:395
decltype(auto) getGateI()
Get the Identity; must be overloaded with appropriate return type.
Definition: Simulator.hpp:231
void initRegister()
(Re)Initialise the underlying register of the encapsulated simulator to well-defined state (|0....
Definition: Simulator.hpp:679
void applyGateCZ(const std::size_t control, const std::size_t target)
Apply Controlled Pauli-Z on target qubit.
Definition: Simulator.hpp:284
decltype(auto) getGateZ()
Get the Pauli-Z gate; must be overloaded with appropriate return type.
Definition: Simulator.hpp:224
Defines class which introduces routines for encoding binary numbers represented as unsigned integers ...
Mat2x2Type matrixSqrt(const Mat2x2Type &U)
Calculates the unitary matrix square root (U == VV, where V is returned)
Definition: Simulator.hpp:729
void applyGateCPhaseShift(double angle, std::size_t control, std::size_t target)
Perform controlled phase shift gate.
Definition: Simulator.hpp:335
Definition of class to encode a binary string represented by an integer into a superposition of state...