
/* Shors algorithm for factoring numbers using quantum computation.
 * code ported from OpenQuBit 3.1
 *
 * usage: QuBit(M,x); where M is the number to factorize, and x
 * is some number 1 <= x <= (M-1)
 */

/* : Check if a bit is set in a number */
IsBitSet(n, i) := Mod( (n>>i),2) = 1;


ReMask(mask, offset) := mask << offset;
 
/* reverse bits in num nbits is number of bits */
NumReverse(num, nbits) :=
[
  /* reverse the whole thing(i.e. log2(num)) */
  If (nbits = -1, nbits := CountBits(num));

  Local(result,i);
  result:=0;
  For(i:=0,i<nbits,i++)
       If(IsBitSet(num,i),
         result:=result+(1<<(nbits-i-1))
         );
  result;
];


/* Russian Peasant modular exponentiation */
modexp(x, y, m) :=
[
  Local(xx,p);
  xx:=1;
  p:=Mod(x,m);
  While(y>0)
  [
    If(Mod(y, 2) = 1, xx := Mod(xx*p, m));
    p := Mod(p*p, m);
    y := y>>1;
  ];
  xx;
];



 
/*TODO PeriodExtract */






RuleBase("QuBit",{M,x});
Rule("QuBit",2,0,Mod(M , 2) = 0)
    [
  WriteString("Number is even. Factors found : ");
  Write(M);
  WriteString(" = 2*");
  Write(M>>1);
  NewLine();
     ];

Rule("QuBit",2,0,IsPrime(M))
[
   WriteString("Numer is prime. It cannot be factored.");
   NewLine();
];


Rule("QuBit",2,0,
[
  Local(factor);
  factor := MathGcd(M,x);
  factor != 1 And factor != M;
])
    [
     Local(factor);
    factor := MathGcd(M,x);
    WriteString("Factor found since GCD(");
    Write(M);WriteString(",");Write(x);WriteString(")=");Write(factor);
    NewLine();
    Write(M);WriteString(" = ");Write(factor);WriteString("*");
    Write(N(M/factor));
    NewLine();
    ];

Rule("QuBit",2,0,True)
    [
     Local(first,second);
    first  := CountBits(M*M);
    second := CountBits(M);

    /* TODO etc. */
    WriteString("Not yet implemented");
    NewLine();
    ];


/* ClassicPeriod : this is the computation that the Shor
   algorithm is supposed to perform more efficiently.
   It tries to find the period of n^(p+1) mod m. That is, it
   will return the p for which n mod m = n^p mod m
   Example: ClassicPeriod(4,15) -> 2
 */

ClassicPeriod(n,m):=
[
  Local(i,first,period);
  i:=n;
  period:=1;
  first:=Mod(i,m);
  i:=i*n;
  While(Mod(i,m)!=first)
  [
    i:=i*n;
    period++;
  ];
  period;
];

/* ClassicFactors does the same as Factors, but using a period
   Example: ClassicFactors(4,15,ClassicPeriod(4,15)) -> {5,3}
 */
ClassicFactors(n,m,period):=
[
  Local(res);
  res:=Sqrt(n^period);
  {Gcd(res+1,m),Gcd(res-1,m)};
];



QNormalize(vector):= vector/Sqrt(Sum(vector*Conjugate(vector)));


QBase(n):=BaseVector(1,2^n);

