Intel® Quantum SDK
Forum related to Intel Quantum SDK, a full-stack software kit for programming and executing algorithms on simulated quantum hardware.

Predefined Indices

zgural
Beginner
1,307 Views

This question is related to my previous one:  I am finding it hard to define a quantum_kernel which uses a predefined array (possibly but not necessarily random) to determine the sequence of gates.  For example the following code to implement H(Q[1]) H(Q[3]) H(Q[0]) H(Q[5]) |Psi>   fails:

 

const std::vector<int> Indices = {5,0,3,1}; 

const int L = Indices.size();

quantum_kernel void SequenceOfGates(){

      for (int n=0; n<L; n++){

              int i = Indices[n];

              H(Q[i]) ; 

              }

      }

 

The error is 

ERROR: Quantum SDK - ValidateAndConditionQBBPass says: Invalid loops stuck around in 'SequenceOfGates()'
LLVM ERROR: Cannot process further. Exiting...

 

 

 

 

 

 

0 Kudos
5 Replies
gbaker
Employee
1,295 Views

Thanks for the question,

For the compiler to know at compile time, a constexpr container must be used (note that vector wasn't made constexpr until c++ 20)

Something like the following would work instead:

constexpr int L = 4;

constexpr std::array<int, L> Indices = {5,0,3,1};

quantum_kernel void SequenceOfGates(){

      for (int n=0; n<L; n++){

              int i = Indices[n];

              H(Q[i]) ;

      }

}

 

 

 

KevinR_Intel
Moderator
1,291 Views

I learned something about the C++ compiler behavior here!

Namely that even though we can see from the code that the vector will *always* have the same entries in it; that isn't a strictly enforced constraint from the compiler's perspective. The 'constexpr' attribute will tell the compiler what we intuitively understand and it will enforce the remaining constraints (i.e., if you try to modify Indices later in the code once it is marked constexpr, then I bet the compiler will refuse).

0 Kudos
zgural
Beginner
1,286 Views

Thanks, I will play around with constexpr.

However I also think the ability to dynamically generate indices will be important for any problem with a larger number of qubits.  As another example,  suppose one has a Hamiltonian written in terms of sums of Pauli strings.  You might use some (classical) code to generate these strings rather than doing it by hand;  for instance if H involves Majorana fermions and you have to use the Jordan Wigner  trick to generate the Pauli strings.   Next suppose you want to find the expectation value of H in some state by a repeated sequence of measurements.  If one of the Pauli strings is , say ...IIIYXIIIZII...,  you would not want to do a measure_all().  You would want to just want to measX, measY or measZ in the places where the Paulis are  X,Y,or Z but not the identity.   So you would need to create kernels to do these measurements for each Pauli string appearing in the Hamiltonian.   The following code does not work, but it seems to be the kind of thing you would want to be able to construct.  

quantum_kernel void measure_some(std::string P){
       // for example P = "IIXZIY"
       std::string X = "X";
       std::string Y = "Y";
       std::string Z = "Z";
      vector<int> X_locs;
      vector<int> Y_locs;
      vector<int> Z_locs;
     

       for (int id = 0; id < N; id++){
             std::string p = P.substr(id,1);
             if (p == X){
                       X_locs.push_back(id); }
              if (p == Y){
                       Y_locs.push_back(id); }
              if (p == Z){
                        Z_locs.push_back(id); }

      int Nx = X_locs.size();
      int Ny = Y_locs.size();
      int Nz = Z_locs.size();
     

      for (int idx = 0; idx < Nx; idx++){
              int j = X_locs[idx];
              MeasX(q[j],c[j]);  }
     

      for (int idy = 0; idy < Ny; idy++){
             int j = X_locs[idy];
             MeasY(q[j],c[j]); }
     

       for (int idz = 0; idz < Nz; idz++){
            int j = X_locs[idz];
            MeasZ(q[j],c[j]);  }

}

Then you would want to use this to make a a set of quantum instructions, one for each relevant Pauli string, which could be called in main() 

 

 

0 Kudos
Shavi
Employee
1,273 Views

Specifically for this use case, I believe the Hybrid Quantum Classical Library might be a good fit. This is actually a runtime solution similar to what Kevin suggested. The Hamiltonian can be constructed using the Pauli strings, and the library itself takes care of generating both the appropriate basis changes required as well as the minimal number of required measurements. We are constantly improving that library, so please be on the lookout for more features there as well (e.g. easier forms of Hamiltonian input).

https://github.com/IntelLabs/Hybrid-Quantum-Classical-Library

KevinR_Intel
Moderator
1,277 Views

I agree that we still need to implement a more elegant to do what you're (and likely others) are intending here. Off the top of my head, it would require some functionality of the Quantum Runtime that we need to implement and expose as an API.

0 Kudos
Reply