https://github.com/epiqc/ScaffCC
Revision 9d2cca71cf54ddfebda26e247d82ae7b71d9e03c authored by Pranav Gokhale on 30 June 2018, 18:56:21 UTC, committed by Pranav Gokhale on 30 June 2018, 18:56:21 UTC
1 parent 720b0db
Raw File
Tip revision: 9d2cca71cf54ddfebda26e247d82ae7b71d9e03c authored by Pranav Gokhale on 30 June 2018, 18:56:21 UTC
Fix OpenQASM output formatting of Rx and Ry
Tip revision: 9d2cca7
shors.n512.scaffold
//--- Scaffold Code for Shor’s Algorithm ---//
//Input x -> H -> f(x) -> iQFT
//f(x) = a^x mod N

// Optimized implementation as described in 		 	 	 		
// http://arxiv.org/pdf/1207.0511v5.pdf			
// Quantum Information and Computation, Vol. 14, No. 7&8 (2014) 0649–0682

#include <math.h>
#include <stdlib.h>
#define _n 512  //number of bits in N
#include "look_up_tables.h"

#define pi 3.141592

#define _N 10941738641570527421809707322040357612003732945449205990913842131476349984288934784717997257891267332497625752899781833797076537244027146743531593354333897 //number to be factorized

//char Nbits [] = "11010000111010100001101010111010100101111000110111110000000001100101101100100000000010011111011101011100100001000110111100101000101100000100111011010101000101000011101100100011011110110011111111000010010000100111001000100100010110101101111010000011011111101111111000000010011100011110000110100010100001010100111000001100100000011011101010011111011100001010100000111010110110000110110101000111101100001110101011001101000001100010101111000001010110111100011000011010100110011101110010000011000100100100111011001001"

//char Nbits [] = {1,1,0,1,0,0,0,0,1,1,1,0,1,0,1,0,0,0,0,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,0,1,0,0,0,0,1,0,0,0,1,1,0,1,1,1,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,0,0,0,1,0,0,1,1,1,0,1,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,1,1,1,0,1,1,0,0,1,0,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,1,1,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,1,1,0,1,0,1,1,0,1,1,1,1,0,1,0,0,0,0,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,0,0,1,0,1,0,0,0,0,1,0,1,0,1,0,0,1,1,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,1,0,1,0,0,1,1,1,1,1,0,1,1,1,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,1,1,0,1,1,0,1,0,1,0,0,0,1,1,1,1,0,1,1,0,0,0,0,1,1,1,0,1,0,1,0,1,1,0,0,1,1,0,1,0,0,0,0,0,1,1,0,0,0,1,0,1,0,1,1,1,1,0,0,0,0,0,1,0,1,0,1,1,0,1,1,1,1,0,0,0,1,1,0,0,0,0,1,1,0,1,0,1,0,0,1,1,0,0,1,1,1,0,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,0,0,1};


//_dc = _N - (1<<_n)
//char dcbits[] = {101111000101011110010101000101011010000111001000001111111110011010010011011111111101100000100010100011011110111001000011010111010011111011000100101010111010111100010011011100100001001100000000111101101111011000110111011011101001010010000101111100100000010000000111111101100011100001111001011101011110101011000111110011011111100100010101100000100011110101011111000101001001111001001010111000010011110001010100110010111110011101010000111110101001000011100111100101011001100010001101111100111011011011000100110111};
//FIXME: negative this


#define _a 2    //randomly chosen s.t. gcd(a,N) = 1

// pre-computed constants for the GMQDIV2 circuit
// we use the fact that this divider is only ever used
// to divide by _N
#define _l _n //1+floor(log2(_N))
#define _mdash floor(((1<<(_n+1))-1)/_N) - (1<<_N) //FIXME: definition not clear from paper

//AQFT parameters
#define _n_upper 2*_n
#define log_2(x) log(x)/log(2)
#define AQFTk (int)(3+log_2(_n_upper)) //value of k for approximate QFT // k>=2+log2(n)


module swap (qbit a, qbit b) {
	CNOT(a, b);
	CNOT(b, a);
	CNOT(a, b);
}

module cRz (qbit ctrl, qbit target, double angle) {

	Rz (target, angle/2);
	CNOT (target, ctrl);
	Rz (target, -1*angle/2);
	CNOT (target, ctrl);
}

module ccRz (qbit ctrl1, qbit ctrl2, qbit target, double angle)
{
  // doubly - controlled Rz circuit with angle
  // decompose in terms of V = sqrt(U)
  cRz (ctrl2, target, angle/2);
  CNOT (ctrl2, ctrl1);
  cRz (ctrl1, target, -angle/2);
  CNOT (ctrl2, ctrl1);
  cRz (ctrl1, target, angle/2);
}


module QFT(qbit x[]) {
  int i, j;
  double angle = 0.0;
  for (i=0; i<_n; i++){
    H(x[i]);
    for (j=i+1; j<_n; j++) {
      angle = angle_R[j];
      cRz(x[j], x[i], angle);
    }
  }
  // TODO: swaps for reordering
}

// inverse QFT
module iQFT (qbit x[]){
  int i, j;
  double angle = 0.0;
  for (i=_n-1; i>=0; i--){
    for (j=_n-1; j>i; j--) {
      angle = -angle_R[j];
      cRz(x[j], x[i], angle);
    }
    H(x[i]);
  }
  // TODO: swaps for reordering    
}



// QFT with input broken into two equal parts, each size n
module QFT_2 (qbit x0[], qbit x1[]) {
  int i, j;
  double angle = 0.0;
  
  // the first register
  for (i=0; i<_n; i++){
    H(x0[i]);
    for (j=i+1; j<_n; j++) {
      angle = angle_R[j];
      cRz(x0[j], x0[i], angle);
    }
    for (j=0; j<_n; j++) {
      angle = angle_R[j+_n];
      cRz(x1[j], x0[i], angle);
    }
  }

  // the second register
  for (i=0; i<_n; i++){
    H(x1[i]);
    for (j=i+1; j<_n; j++) {
      angle = angle_R[j+_n];
      cRz(x1[j], x1[i], angle);
    }
  }

  // TODO: swaps for reordering
}

// inverse QFT with input broken into two equal parts, each size n
module iQFT_2 (qbit x0[], qbit x1[]){
  int i, j;
  double angle = 0.0;
  
  // the second register
  for (i=_n-1; i>=0; i--){
    for (j=_n-1; j>i; j--) {
      angle = -angle_R[j+_n];
      cRz(x1[j], x1[i], angle);
    }
    H(x1[i]);
  }
  
  // the first register
  for (i=_n-1; i>=0; i--){
    for (j=_n-1; j>=0; j--) {
      angle = -angle_R[j+_n];
      cRz(x1[j], x0[i], angle);
    }
    for (j=_n-1; j>i; j--) {
      angle = -angle_R[j];
      cRz(x0[j], x0[i], angle);
    }
    H(x0[i]);
  }
  
  // TODO: swaps for reordering    
}



// add constant _N to qubit register which is broken down into 2 registers of length _n
module QADD_2 (qbit R0[], qbit R2[])
{
  int j = 0;
  double angle = 0.0;

  for(j=0; j<_n; j++){
    angle = angle_A_N[j]; 
    Rz(R0[j],angle);
  }
  for(j=0; j<_n; j++){
    angle = angle_A_N[j+_n]; 
    Rz(R2[j],angle);
  }
}

// add constant _N to qubit register which is broken down into 2 registers of length _n
module iQADD_2 (qbit R0[], qbit R2[])
{
  int j = 0;
  double angle = 0.0;

  for(j=_n-1; j>=0; j--){
    angle = -angle_A_N[j+_n]; 
    Rz(R2[j],angle);
  }
  for(j=_n-1; j>=0; j--){
    angle = -angle_A_N[j]; 
    Rz(R0[j],angle);
  }
}

module CQADD_1 (qbit ctrl, qbit target[])
{
  int j = 0;
  double angle = 0.0;
  
  for(j=0; j<_n; j++){
    angle = angle_A_1[j]; //compute angle of rotation
    cRz(ctrl,target[j],angle);
  }
}

module iCQADD_1 (qbit ctrl, qbit target[])
{
  int j = 0;
  double angle = 0.0;
  
  for(j=_n-1; j>=0; j--){
    angle = -angle_A_1[j]; //compute angle of rotation
    cRz(ctrl,target[j],angle);
  }
}


module CQADD_dc (qbit ctrl, qbit target[])
{
  int j = 0;
  double angle = 0.0;
  
  for(j=0; j<_n; j++){
    angle = angle_A_dc[j]; //compute angle of rotation
    cRz(ctrl,target[j],angle);
  }
}

module iCQADD_dc (qbit ctrl, qbit target[])
{
  int j = 0;
  double angle = 0.0;
  
  for(j=_n-1; j>=0; j--){
    angle = -angle_A_dc[j]; //compute angle of rotation
    cRz(ctrl,target[j],angle);
  }
}



// add two n-qubit registers (Fig.7 in paper)
// qbit a[n]
// qbit b[n]
// (left is lsb)
module QADDn( qbit a[],     // n bits
              qbit b[]     // n bits
            )
{
  int i = 0;
  int j = 0;
  double angle = 0.0;

  // is this going to be parallelized?

  // lower bits
  for (i=_n-1; i>=0; i--) {
    for (j=i; j<_n; j++) {
      angle = angle_R [j-i+1]; 
      cRz (a[i], b[j], angle);
    }
  }
}

module iQADDn( qbit a[],     // n bits
               qbit b[]      // n bits
              )
{
  int i = 0;
  int j = 0;
  double angle = 0.0;

  // is this going to be parallelized?

  // lower bits
  for (i=0; i<_n; i++) {
    for (j=_n-1; j>=i; j--) {
      angle = -angle_R [j-i+1]; 
      cRz (a[i], b[j], angle);
    }
  }
}


// multiplier-accumulator (refer to Fig.11b and Fig.12 in paper)
// parallel version with 8n depth
// Is this parallelized? 
module QMAC_a(qbit ctrl, 
              qbit x[],               // size n
              // b is divided into two registers of size n
              qbit R10[], // size n
              qbit R20[] // size n
              )
{
  double angle = 0.0;
  int i=0; 
  int j=0;
  int l=0;

  // V section
  for (l=0; l<_n; l++){
    for (i=0; i<_n; i++){
      j = (l-i)%_n;
      angle = angle_V_a[l][j];
      cRz(x[j], R10[l], angle);
    }
  }
  for (l=0; l<_n; l++){
    for (i=0; i<_n; i++){
      j = (l+_n-i)%_n;
      angle = angle_V_a[l+_n][j];
      cRz(x[j], R20[l], angle);
    }
  }


  //CNOTs
  for(i=0; i<_n; i++)
    CNOT(x[i], ctrl);


  // V_dagger section
  for(l=0; l<_n; l++){
    for(i=0; i<_n; i++){
      j = (l-i)%_n; 
      angle = -angle_V_a[l][j];
      cRz(x[j], R10[l], angle);
    }
  }
  for(l=0; l<_n; l++){
    for(i=0; i<_n; i++){
      j = (l+_n-i)%_n; 
      angle = -angle_V_a[l+_n][j];
      cRz(x[j], R20[l], angle);
    }
  }


  //CNOTs
  for(i=0; i<_n; i++)
    CNOT(x[i], ctrl);


  // W section
  for(l=0; l<_n; l++) {
    angle = angle_W_a[l];
    cRz(ctrl, R10[l], angle);
  }
  for(l=0; l<_n; l++) {
    angle = angle_W_a[l+_n];
    cRz(ctrl, R20[l], angle);
  }
  
}


module iQMAC_a(qbit ctrl, 
              qbit x[],               // size n
              // b is divided into two registers of size n
              // which are again divided into two of size t and n-t
              qbit R10[], // size n
              qbit R20[] // size n
              )
{
  double angle = 0.0;
  int i=0; 
  int j=0;
  int l=0;

  // More parallel version of above with O(n) depth
  // Is this parallelized? 
  
  // W section
  for(l=_n-1; l>=0; l--) {
    angle = -angle_W_a[l+_n];
    cRz(ctrl, R20[l], angle);
  }
  for(l=_n-1; l>=0; l--) {
    angle = -angle_W_a[l];
    cRz(ctrl, R10[l], angle);
  }


  //CNOTs
  for(i=_n-1; i>=0; i--)
    CNOT(x[i], ctrl);


  // V_dagger section
  for(l=_n-1; l>=0; l--){
    for(i=_n-1; i>=0; i--){
      j = (l+_n-i)%_n;
      angle = angle_V_a[l+_n][j];
      cRz(x[j], R20[l], angle);
    }
  }
  for(l=_n-1; l>=0; l--){
    for(i=_n-1; i>=0; i--){
      j = (l-i)%_n;
      angle = angle_V_a[l][j];
      cRz(x[j], R10[l], angle);
    }
  }


  //CNOTs
  for(i=_n-1; i>=0; i--)
    CNOT(x[i], ctrl);


  // V section
  for (l=_n-1; l>=0; l--){
    for (i=_n-1; i>=0; i--){
      j = (l+_n-i)%_n;
      angle = -angle_V_a[l+_n][j];
      cRz(x[j], R20[l], angle);
    }
  }
  for (l=_n-1; l>=0; l--){
    for (i=_n-1; i>=0; i--){
      j = (l-i)%_n;
      angle = -angle_V_a[l][j];
      cRz(x[j], R10[l], angle);
    }
  }

}



// multiplier-accumulator (refer to Fig.11b and Fig.12 in paper)
// parallel version with 8n depth
// Is this parallelized? 
module QMAC_N(qbit ctrl, 
              qbit x[],               // size n
              // b is divided into two registers of size n
              qbit R10[], // size n
              qbit R20[] // size n
              )
{
  double angle = 0.0;
  int i=0; 
  int j=0;
  int l=0;

  // V section
  for (l=0; l<_n; l++){
    for (i=0; i<_n; i++){
      j = (l-i)%_n;
      angle = angle_V_N[l][j];
      cRz(x[j], R10[l], angle);
    }
  }
  for (l=0; l<_n; l++){
    for (i=0; i<_n; i++){
      j = (l+_n-i)%_n;
      angle = angle_V_N[l+_n][j];
      cRz(x[j], R20[l], angle);
    }
  }


  //CNOTs
  for(i=0; i<_n; i++)
    CNOT(x[i], ctrl);


  // V_dagger section
  for(l=0; l<_n; l++){
    for(i=0; i<_n; i++){
      j = (l-i)%_n; 
      angle = -angle_V_N[l][j];
      cRz(x[j], R10[l], angle);
    }
  }
  for(l=0; l<_n; l++){
    for(i=0; i<_n; i++){
      j = (l+_n-i)%_n; 
      angle = -angle_V_N[l+_n][j];
      cRz(x[j], R20[l], angle);
    }
  }


  //CNOTs
  for(i=0; i<_n; i++)
    CNOT(x[i], ctrl);


  // W section
  for(l=0; l<_n; l++) {
    angle = angle_W_N[l];
    cRz(ctrl, R10[l], angle);
  }
  for(l=0; l<_n; l++) {
    angle = angle_W_N[l+_n];
    cRz(ctrl, R20[l], angle);
  }
  
}


module iQMAC_N(qbit ctrl, 
              qbit x[],               // size n
              // b is divided into two registers of size n
              // which are again divided into two of size t and n-t
              qbit R10[], // size n
              qbit R20[] // size n
              )
{
  double angle = 0.0;
  int i=0; 
  int j=0;
  int l=0;

  // More parallel version of above with O(n) depth
  // Is this parallelized? 
  
  // W section
  for(l=_n-1; l>=0; l--) {
    angle = -angle_W_N[l+_n];
    cRz(ctrl, R20[l], angle);
  }
  for(l=_n-1; l>=0; l--) {
    angle = -angle_W_N[l];
    cRz(ctrl, R10[l], angle);
  }


  //CNOTs
  for(i=_n-1; i>=0; i--)
    CNOT(x[i], ctrl);


  // V_dagger section
  for(l=_n-1; l>=0; l--){
    for(i=_n-1; i>=0; i--){
      j = (l+_n-i)%_n;
      angle = angle_V_N[l+_n][j];
      cRz(x[j], R20[l], angle);
    }
  }
  for(l=_n-1; l>=0; l--){
    for(i=_n-1; i>=0; i--){
      j = (l-i)%_n;
      angle = angle_V_N[l][j];
      cRz(x[j], R10[l], angle);
    }
  }


  //CNOTs
  for(i=_n-1; i>=0; i--)
    CNOT(x[i], ctrl);


  // V section
  for (l=_n-1; l>=0; l--){
    for (i=_n-1; i>=0; i--){
      j = (l+_n-i)%_n;
      angle = -angle_V_N[l+_n][j];
      cRz(x[j], R20[l], angle);
    }
  }
  for (l=_n-1; l>=0; l--){
    for (i=_n-1; i>=0; i--){
      j = (l-i)%_n;
      angle = -angle_V_N[l][j];
      cRz(x[j], R10[l], angle);
    }
  }

}



// Granlund-Montgomery division by constant circuit, giving n-bit quotient and n-bit remainder
// Circuit Depth = 244n timesteps
// Circuit Width = 7n+1 qubits
// Figures 13 & 14 & 18
// In this case, divisor d = _N always.
module GMQDIV2( 
               // dividend z at the start of computation (2*_n qubits)
               qbit Reg00[_n],   // lower bits: l bits
               qbit Reg10[_n]   // lower bits: l bits
               )
{
  // quotient q at the end of computation (n qubits)
  qbit Reg2[_n];    // n bits   

  // ancilla qubits  
  qbit Reg3[_n];   // ancilla -- q1
  qbit Reg4[_n];   // ancilla -- n2, n2+n1, n2, 0, n1, 0
  qbit Reg51[_n];
  qbit Reg6[_n]; // ancilla -- LOW(m'(n2+n1)+nadj)
  qbit Aqbit[1];// ancilla - sign(n1)
  qbit anc[1];

  // loop variable
  int i;
  
  // -------------------- Compute (fig. 13) ------------------------/

  // SLL(HIGH(z),n-l) --> Reg0[0 .. l-1] |  Reg5[0 .. n-l-1]
  // Reg4[0 .. n-1]
  QADDn(Reg00, Reg4);

  // SLL(LOW(z),n-l) --> Reg1[0 .. l-1] | Reg5[0 .. n-l-1]
  // Reg6[0 .. n-1]
  QADDn(Reg10, Reg6);

  // SRL(LOW(z), l) --> Reg1[l .. n-1] | Reg5[n-l .. n-1]
  // Reg4[0 .. n-1]
  QADDn(Reg51, Reg4);
  
  iQFT(Reg6);
  
  // CNOT(target, control)
  CNOT(Aqbit[0], Reg6[_n-1]);

  CQADD_1(Aqbit[0], Reg4);

  QFT(Reg6);

  CQADD_dc(Aqbit[0], Reg6);

  iQFT(Reg6);
   
  // Reg6[n]|Reg51[l]
  QFT_2(Reg6, Reg51); 

  iQFT(Reg4);
  
  //FIXME: code me (algorithm does not show control signal)
  //QMAC_mdash();

  iQFT_2(Reg6, Reg51);

  for (i=0; i<_n ; i++) {
    CNOT(Reg2[_n-_n+i], Reg51[i]);
  }

  QFT(Reg2);

  QADDn(Reg2, Reg4);

  iCQADD_1(Aqbit[0], Reg2);

  iQFT(Reg2);

  QFT_2(Reg10, Reg00);

  for (i=0; i<_n; i++)
    CNOT(Reg3[i], Reg2[i]);

  // FIXME: code me
  //QMAC(, -_N);

  iQADD_2(Reg10, Reg00);

  QFT(Reg2);

  iQFT_2(Reg10, Reg00);

  iQFT (Reg2);

  QFT_2(Reg10, Reg00);

  QADD_2(Reg10, Reg00);

  // FIXME: incomplete document specification -- create |1> ctrl signal
  X(anc[0]);
  //QMAC_N(anc[0], Reg2, Reg10, Reg00);

  iQFT_2(Reg10, Reg00);


  //------------------------- UnCompute (fig. 14) ------------------------/

  QFT(Reg3);

  iQADDn(Reg3, Reg4);

  CQADD_1(Aqbit[0], Reg3);

  iQFT(Reg3);

  for (i=0; i<_n; i++) {
    CNOT(Reg3[i], Reg51[i]);
  }

  QFT_2(Reg6, Reg51); 
  
  //FIXME: code me
  //QMAC_mdash();

  iQFT_2(Reg6, Reg51);

  QFT(Reg4);
  
  iCQADD_1(Aqbit[0], Reg4);

  QFT(Reg6);

  // SLL(HIGH(z),n-l) --> Reg0[0 .. l-1] |  Reg5[0 .. n-l-1]
  // Reg4[0 .. n-1]
  iQADDn(Reg00, Reg4);

  iCQADD_1(Aqbit[0], Reg6);

  // SLL(LOW(z),n-l) --> Reg1[0 .. l-1] | Reg5[0 .. n-l-1]
  // Reg6[0 .. n-1]
  QADDn(Reg10, Reg6);

  iQFT(Reg6);
  
  // SLL(LOW(z),n-l) --> Reg1[0 .. l-1] | Reg5[0 .. n-l-1]
  // Reg6[0 .. n-1]
  iQADDn(Reg10, Reg4);
  
  iQFT(Reg4);

  QFT(Reg4);

  // SLL(LOW(z),n-l) --> Reg1[0 .. l-1] | Reg5[0 .. n-l-1]
  // Reg6[0 .. n-1]
  iQADDn(Reg10, Reg4);

  iQFT(Reg4);
  
  QFT_2(Reg10, Reg00);

  // FIXME: code me
  //QMAC(, -_N);

  iQFT_2(Reg10, Reg00);

}


module iGMQDIV2( 
               // dividend z at the start of computation (2*_n qubits)
               qbit Reg00[_n],   // lower bits: l bits
               qbit Reg10[_n]   // lower bits: l bits
               )
{

  // quotient q at the end of computation (n qubits)
  qbit Reg2[_n];    // n bits   

  // ancilla qubits  
  qbit Reg3[_n];   // ancilla -- q1
  qbit Reg4[_n];   // ancilla -- n2, n2+n1, n2, 0, n1, 0
  qbit Reg51[_n];
  qbit Reg6[_n]; // ancilla -- LOW(m'(n2+n1)+nadj)
  qbit Aqbit[1]; // ancilla - sign(n1)  
  qbit anc[1];

  // loop variable
  int i;

  
  //------------------------- UnCompute (fig. 14) ------------------------/

  QFT_2(Reg10, Reg00);  

  // FIXME: code me
  //iQMAC(, -_N);

  iQFT_2(Reg10, Reg00);

  QFT(Reg4);

  // SLL(LOW(z),n-l) --> Reg1[0 .. l-1] | Reg5[0 .. n-l-1]
  // Reg6[0 .. n-1]
  QADDn(Reg10, Reg4);

  iQFT(Reg4);

  QFT(Reg4);

  // SLL(LOW(z),n-l) --> Reg1[0 .. l-1] | Reg5[0 .. n-l-1]
  // Reg6[0 .. n-1]
  QADDn(Reg10, Reg4);

  QFT(Reg6);

  // SLL(LOW(z),n-l) --> Reg1[0 .. l-1] | Reg5[0 .. n-l-1]
  // Reg6[0 .. n-1]
  iQADDn(Reg10, Reg6);

  CQADD_dc(Aqbit[0], Reg6);

  // SLL(HIGH(z),n-l) --> Reg0[0 .. l-1] |  Reg5[0 .. n-l-1]
  // Reg4[0 .. n-1]
  QADDn(Reg00, Reg4);

  iQFT(Reg6);

  CQADD_1(Aqbit[0], Reg4);

  iQFT(Reg4);

  QFT_2(Reg6, Reg51);

  //FIXME: code me
  //iQMAC_mdash();

  iQFT_2(Reg6, Reg51); 

  for (i=_n-1; i>=0; i--) {
    CNOT(Reg3[i], Reg51[i]);
  }

  QFT(Reg3);

  iCQADD_1(Aqbit[0], Reg3);

  iQADDn(Reg3, Reg4);
  
  iQFT(Reg3);

  // -------------------- Compute (fig. 13) ------------------------/

  QFT_2(Reg10, Reg00);

  // FIXME: incomplete document specification
  X(anc[0]);
  //iQMAC_N(anc[0], Reg2, Reg10, Reg00);

  iQADD_2(Reg10, Reg00);

  iQFT_2(Reg10, Reg00);

  QFT (Reg2);

  QFT_2(Reg10, Reg00);

  iQFT(Reg2);

  QADD_2(Reg10, Reg00);

  // FIXME: code me
  //iQMAC(, -_N);

  for (i=_n-1; i>=0; i--)
    CNOT(Reg3[i], Reg2[i]);

  iQFT_2(Reg10, Reg00);

  QFT(Reg2);

  CQADD_1(Aqbit[0], Reg2);

  iQADDn(Reg2, Reg4);

  iQFT(Reg2);

  for (i=_n-1; i>=0 ; i--) {
    CNOT(Reg2[_n-_n+i], Reg51[i]);
  }

  QFT_2(Reg6, Reg51);

  //FIXME: code me (algorithm does not show control signal)
  //iQMAC_mdash();

  QFT(Reg4);

  // Reg6[n]|Reg51[l]
  iQFT_2(Reg6, Reg51); 

  QFT(Reg6);

  iCQADD_dc(Aqbit[0], Reg6);

  iQFT(Reg6);

  iCQADD_1(Aqbit[0], Reg4);

  // CNOT(target, control)
  CNOT(Aqbit[0], Reg6[_n-1]);

  QFT(Reg6);

  // SRL(LOW(z), l) --> Reg1[l .. n-1] | Reg5[n-l .. n-1]
  // Reg4[0 .. n-1]
  iQADDn(Reg51, Reg4);

  // SLL(LOW(z),n-l) --> Reg1[0 .. l-1] | Reg5[0 .. n-l-1]
  // Reg6[0 .. n-1]
  iQADDn(Reg10, Reg6);

  // SLL(HIGH(z),n-l) --> Reg0[0 .. l-1] |  Reg5[0 .. n-l-1]
  // Reg4[0 .. n-1]
  iQADDn(Reg00, Reg4);
  
}




// Optimized controlled modular multiplier/accumulator (Fig. 19)
// 4n+1 qubits + 5n+1 ancillas
module QMAC_MOD2 (qbit ctrl, 
                  qbit y[_n], 
                  qbit R10[_n],
                  qbit R20[_n],
                  qbit R30[_n]
                  )
{
  int i = 0;
 
  QFT_2(R20, R10);

  QMAC_a(ctrl, y, R10, R20);

  iQFT_2(R20, R10);

  GMQDIV2(R20, R10); // only GMQDIV2 with parameter _N is used

  for (i=0; i<_n; i++)
    CNOT(R30[i], R10[i]);

  iGMQDIV2(R20, R10); // only iGMQDIV2 with parameter _N is used
  
  QFT_2(R20, R30);

  iQMAC_a(ctrl, y, R20, R30);

  iQFT_2(R20, R30);

}

module iQMAC_MOD2 (qbit ctrl, 
                  qbit y[_n], 
                  qbit R10[_n],
                  qbit R20[_n],
                  qbit R30[_n])
{
  int i = 0;
 
  QFT_2(R20, R30);
  
  QMAC_a(ctrl, y, R20, R30);

  iQFT_2(R20, R30);

  GMQDIV2(R20, R10);

  for (i=_n-1; i>=0; i--)
    CNOT(R30[i], R10[i]);
  
  iGMQDIV2(R20, R10);

  QFT_2(R20, R10);

  iQMAC_a(ctrl, y, R10, R20);

  iQFT_2(R20, R10);
  
}

// Optimized controlled modular multiplier (Fig. 20) -- specialized a=_a and N=_N
// 4n+1 qubits + 5n+1 ancillas
// In total: depth = 1045n-38
module CU(qbit ctrl, qbit x[_n], int k)
{
  //Compute U^(2^k) = a^(2^k) mod N

  //Uf = a^x mod N. 
  //When x is expressed in binary as x[n-1]:x[n-2]:...:x[1]:x[0],
  //a^x mod N = PRODUCT{a^(2^(k)*x[k]}, where k goes from 0 to (n-1)

  // iteration indices
  int i, j;

  // ancilla qubits
  qbit R10[_n];
  qbit R20[_n];
  qbit R30[_n];

  for (i=0; i<_n; i++){
    PrepZ(R10[i], 0);
    PrepZ(R20[i], 0);
    PrepZ(R30[i], 0);  
  }

  // QMAC_MOD2 is only used in the overall design with (_a, _N) as parameters
  QMAC_MOD2(ctrl, x, R10, R20, R30);

  for (i=0; i<_n; i++) {
    //Fredkin(x[i], R10[i], ctrl);
    // Fredkin decomposition (J. A. Smolin and D. P. DiVincenzo, Phys. Rev. A, 53, 2855 (1996).)
    CNOT(R10[i], ctrl);
    Toffoli(x[i], R10[i], ctrl);
    CNOT(R10[i], ctrl);
  }

  iQMAC_MOD2(ctrl, x, R10, R20, R30);
  
}


module RotBy(qbit q, int k, int neg)
{
  //neg = +1 for positive angle
  //neg = -1 for negative angle

  //Rk = [1 0; 0 e^i(2*pi/2^k) ]
  //Rk(theta) performed using Rz(theta/2), and ignoring global phase shift

  //angle is negative for inverse QFT
  double angle = neg*pi/pow(2,k); //theta/2

  Rz(q, angle);
}

module CRinv(qbit ctrl, qbit q, int k) //Controlled RotBy
{
  RotBy(q,k-1, -1); //SP: negative angle
  CNOT(q, ctrl);  // ajavadia: changed order of ctrl and target
  RotBy(q,k-1, 1); //positive angle
  CNOT(q, ctrl);
}

module AQFT(qbit x[_n_upper], qbit y[_n])
{
    cbit measBits[_n_upper];
    int i = 0, j = 0;
    
    for(i=0; i<_n_upper; i++)
        H(x[i]);

    for(i=0; i<_n_upper; i++)
      CU(x[i], y, i);

    for(i=_n_upper-1; i>=0; i--)
    {
        for(j=i+AQFTk; j>i; j--)
            if(j<_n_upper)
                CRinv(x[j], x[i], j-i+1);
        H(x[i]);
    }
    
    for(i=0; i<_n_upper; i++)
        measBits[i] = MeasZ(x[i]);
}

int main()
{
    qbit x[_n_upper];
    qbit y[_n];
     
    AQFT(x,y); //Implement AQFT

    return 0;
}

back to top