17 #ifndef QNLP_SIMULATOR_H 18 #define QNLP_SIMULATOR_H 35 #if defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER) 37 #include <experimental/any> 42 #ifdef VIRTUAL_INTERFACE 58 #define IS_SET(byte,bit) (((byte) & (1UL << (bit))) >> (bit)) 65 template <
class DerivedType>
66 #ifdef VIRTUAL_INTERFACE 67 class SimulatorGeneral :
virtual public ISimulator {
81 MPI_Initialized(&mpi_is_init);
84 char** argv_tmp =
new char*[argc_tmp];
85 MPI_Init(&argc_tmp, &argv_tmp);
101 #if defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER) 102 std::experimental::any
sim_ncu;
124 static_cast<DerivedType&>(*this).applyGateX(qubit_idx);
132 static_cast<DerivedType&>(*this).applyGateY(qubit_idx);
140 static_cast<DerivedType&>(*this).applyGateZ(qubit_idx);
148 static_cast<DerivedType&>(*this).applyGateI(qubit_idx);
156 static_cast<DerivedType&>(*this).applyGateH(qubit_idx);
164 static_cast<DerivedType&>(*this).applyGateSqrtX(qubit_idx);
173 static_cast<DerivedType&>(*this).applyGateRotX(qubit_idx, angle_rad);
182 static_cast<DerivedType&>(*this).applyGateRotY(qubit_idx, angle_rad);
191 static_cast<DerivedType&>(*this).applyGateRotZ(qubit_idx, angle_rad);
200 template<
class Mat2x2Type>
202 static_cast<DerivedType*>(
this)->applyGateU(U, qubit_idx);
210 return static_cast<DerivedType&>(*this).getGateX();
218 return static_cast<DerivedType&>(*this).getGateY();
225 return static_cast<DerivedType&>(*this).getGateZ();
232 return static_cast<DerivedType*>(
this)->getGateI();
239 return static_cast<DerivedType*>(
this)->getGateH();
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);
265 static_cast<DerivedType*>(
this)->applyGateCX(control,
target);
275 static_cast<DerivedType*>(
this)->applyGateCY(control,
target);
285 static_cast<DerivedType*>(
this)->applyGateCZ(control,
target);
295 static_cast<DerivedType*>(
this)->applyGateCH(control,
target);
305 static_cast<DerivedType*>(
this)->applyGateSwap(qubit_idx0,qubit_idx1);
315 static_cast<DerivedType*>(
this)->applyGateSqrtSwap(qubit_idx0,qubit_idx1);
325 static_cast<DerivedType*>(
this)->applyGatePhaseShift(angle, qubit_idx);
336 static_cast<DerivedType*>(
this)->applyGateCPhaseShift(angle, control,
target);
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);
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 );
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);
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);
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);
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);
405 return static_cast<DerivedType*>(
this)->getQubitRegister();
414 return static_cast<DerivedType*>(
this)->getNumQubits();
423 void applyQFT(std::size_t minIdx, std::size_t maxIdx){
441 void sumReg(std::size_t r0_minIdx, std::size_t r0_maxIdx, std::size_t r1_minIdx, std::size_t r1_maxIdx){
448 void subReg(std::size_t r0_minIdx, std::size_t r0_maxIdx, std::size_t r1_minIdx, std::size_t r1_maxIdx){
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);
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);
484 std::any_cast<
NCU<DerivedType>&>(
sim_ncu).applyNQubitControl(static_cast<DerivedType&>(*
this), ctrlIndices, auxIndices,
target, label, U, 0);
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){
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){
549 const std::vector<std::size_t> target_register,
550 std::size_t len_bin_pattern){
552 for(std::size_t i = 0; i < len_bin_pattern; i++){
553 if(
IS_SET(target_pattern,i)){
569 const std::vector<std::size_t>& bin_patterns,
570 const std::size_t len_bin_pattern){
585 const std::vector<std::size_t> reg_mem,
587 std::size_t len_bin_pattern){
610 const std::vector<std::size_t> reg_mem,
612 std::size_t len_bin_pattern){
630 return static_cast<DerivedType*>(
this)->applyMeasurement(
target, normalize);
643 for(
int j = target_qubits.size() - 1; j > -1; j--){
644 val |= (static_cast<DerivedType*>(
this)->applyMeasurement(target_qubits[j], normalize) << j);
672 static_cast<DerivedType*>(
this)->collapseToBasisZ(
target, collapseValue);
680 static_cast<DerivedType&>(*this).initRegister();
688 #if defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER) 702 template<
class Mat2x2Type>
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);
707 std::any_cast<
NCU<DerivedType>&>(
sim_ncu).getGateCache().addToCache(static_cast<DerivedType&>(*
this), gateLabel, U, 16);
718 static_cast<DerivedType*>(
this)->PrintStates(
x, qubits);
728 template<
class Mat2x2Type>
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);
739 std::complex<double> scale_factor(1.,0.);
741 V(0,0) *= scale_factor;
742 V(0,1) *= scale_factor;
743 V(1,0) *= scale_factor;
744 V(1,1) *= scale_factor;
756 template<
class Mat2x2Type>
758 Mat2x2Type Uadjoint(U);
759 std::complex<double>
tmp;
761 Uadjoint(0,1) = Uadjoint(1,0);
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));
777 unsigned int range2 = ((maxIdx - minIdx)%2 == 1) ? (maxIdx - minIdx)/2 +1 : (maxIdx - minIdx)/2;
778 for(
unsigned int idx = 0; idx < range2; idx++){
void applyGateRotY(std::size_t qubit_idx, double angle_rad)
Apply the given Rotation about Y-axis to the given qubit.
void applyGateCY(const std::size_t control, const std::size_t target)
Apply Controlled Pauli-Y on target qubit.
void applyIQFT(std::size_t minIdx, std::size_t maxIdx)
Apply the inverse Quantum Fourier transform (IQFT) to the given register index range.
void applyGateRotZ(std::size_t qubit_idx, double angle_rad)
Apply the given Rotation about Z-axis to the given qubit.
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.
void applyGateCSwap(std::size_t ctrl_qubit, std::size_t qubit_swap0, std::size_t qubit_swap1)
Controlled SWAP gate.
void groupQubits(const std::vector< std::size_t > reg_auxiliary, bool lsb=true)
Group all set qubits to MSB in register (ie |010100> -> |000011>)
Class definition for implementing the Hamming distance routine along with controlled Y rotations to e...
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....
void applyGateSwap(std::size_t qubit_idx0, std::size_t qubit_idx1)
Swap the qubits at the given indices.
void applyGateZ(std::size_t qubit_idx)
Apply the Pauli Z gate to the given qubit.
void encodeBinInToSuperpos_unique(SimulatorType &qSim, const std::vector< std::size_t > ®_memory, const std::vector< std::size_t > ®_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...
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,...
#define IS_SET(byte, bit)
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.
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.
CRTP defined class for simulator implementations.
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.
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....
void applyGateX(std::size_t qubit_idx)
Apply the Pauli X gate to the given qubit.
decltype(auto) getGateX()
Get the Pauli-X gate; returns templated type GateType.
std::size_t getNumQubits()
Get the number of Qubits.
void applyQFT(std::size_t minIdx, std::size_t maxIdx)
Apply the forward Quantum Fourier transform (QFT) to the given register index range.
void applyGateRotX(std::size_t qubit_idx, double angle_rad)
Apply the given Rotation about X-axis to the given qubit.
Class definition for performing quantum forward and inverse Fourier transforms.
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 ...
Class definition for applying n-qubit controlled unitary operations.
bool applyMeasurement(std::size_t target, bool normalize=true)
Apply measurement to a target qubit, randomly collapsing the qubit proportional to the amplitude and ...
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.
static void computeHammingDistanceRotY(SimulatorType &qSim, const std::vector< std::size_t > ®_memory, const std::vector< std::size_t > ®_auxiliary, std::size_t len_bin_pattern)
Computes Hamming Distance; adjusts each state's amplitude proportional to the Hamming distance betwee...
Class definition for bit-wise summation and subtraction of qubits.
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.
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.
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.
virtual ~SimulatorGeneral()
Destroy the Simulator General object.
Implements grouping of bits to LSB side of register.
void applyGateI(std::size_t qubit_idx)
Apply the Identity gate to the given qubit.
void applyGateY(std::size_t qubit_idx)
Apply the Pauli Y gate to the given qubit.
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...
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 ...
Class definition for defining and applying an Oracle.
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>
Class definition for applying Grover diffusion to a marked register.
void applyGatePhaseShift(double angle, std::size_t qubit_idx)
Apply phase shift to given Qubit; [[1 0] [0 exp(i*angle)]].
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...
void applyGateCCX(std::size_t ctrl_qubit0, std::size_t ctrl_qubit1, std::size_t target_qubit)
Controlled controlled NOT (CCNOT, CCX) gate.
static Mat2x2Type adjointMatrix(const Mat2x2Type &U)
Function to calculate the adjoint of an input matrix.
static void computeHammingDistanceOverwriteAux(SimulatorType &qSim, const std::vector< std::size_t > ®_memory, const std::vector< std::size_t > ®_auxiliary)
Computes Hamming Distance; Overwrites the pattern in reg_auxiliary to track bit differences from reg_...
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.
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...
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...
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.
decltype(auto) getQubitRegister()
Get the underlying qubit register object.
decltype(auto) getGateY()
Get the Pauli-Y gate; must be overloaded with appropriate return type.
void applyGateSqrtSwap(std::size_t qubit_idx0, std::size_t qubit_idx1)
Performs Sqrt SWAP gate between two given qubits (half way SWAP)
decltype(auto) getGateH()
Get the Hadamard gate; must be overloaded with appropriate return type.
void encodeBinToSuperpos_unique(const std::vector< std::size_t > ®_memory, const std::vector< std::size_t > ®_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....
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.
void applyGateCH(const std::size_t control, const std::size_t target)
Apply Controlled Hadamard on target qubit.
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>
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.
void applyGateSqrtX(std::size_t qubit_idx)
Apply the Sqrt{Pauli X} gate to the given qubit.
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 ...
void applyGateH(std::size_t qubit_idx)
Apply the Hadamard gate to the given qubit.
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.
void initCaches()
Initialise caches used in NCU operation.
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.
decltype(auto) getGateI()
Get the Identity; must be overloaded with appropriate return type.
void initRegister()
(Re)Initialise the underlying register of the encapsulated simulator to well-defined state (|0....
void applyGateCZ(const std::size_t control, const std::size_t target)
Apply Controlled Pauli-Z on target qubit.
decltype(auto) getGateZ()
Get the Pauli-Z gate; must be overloaded with appropriate return type.
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)
void applyGateCPhaseShift(double angle, std::size_t control, std::size_t target)
Perform controlled phase shift gate.
Definition of class to encode a binary string represented by an integer into a superposition of state...