Commit a442c950 authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Arithmetic standard implementation to use qalloc to create anc. qubits



Update the unit tests as well

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 52aa2745
Loading
Loading
Loading
Loading
+11 −18
Original line number Diff line number Diff line
@@ -6,14 +6,13 @@ __qpu__ void test_add_integer(qreg q) {
  Measure(q);
}

__qpu__ void test_add_integer_mod(qreg q, qubit anc) {
__qpu__ void test_add_integer_mod(qreg q) {
  H(q[2]); // |000> + |001>
  add_integer_mod(q, anc, 3, 5); // |3 mod 5> and |7 mod 5>
  add_integer_mod(q, 3, 5); // |3 mod 5> and |7 mod 5>
  Measure(q);
  Measure(anc);
}

__qpu__ void test_mul_integer(qreg x, qreg b, qubit anc, int a, int N) {
__qpu__ void test_mul_integer(qreg x, qreg b, int a, int N) {
  // b = 1;
  X(b[0]); 
  // x = |1> + |3>
@@ -22,18 +21,18 @@ __qpu__ void test_mul_integer(qreg x, qreg b, qubit anc, int a, int N) {

  // ==> |a*x + b> 
  
  mul_integer_mod(x, b, anc, a, N);
  mul_integer_mod(x, b, a, N);
  Measure(b);
  Measure(x);
}

__qpu__ void test_mul_integer_inline(qreg x, qreg anc, int a, int N) {
__qpu__ void test_mul_integer_inline(qreg x, int a, int N) {
  // x = |1> + |3>
  X(x[0]);
  H(x[1]);
  // ==> |a*x> inline (save in x)
  // anc register is just for scratch pad.
  mul_integer_mod_in_place(x, anc.head(x.size() + 1), anc[x.size() + 1], a, N);
  mul_integer_mod_in_place(x, a, N);
  Measure(x);
}

@@ -51,17 +50,13 @@ int main(int argc, char **argv) {

  // Test modular add
  auto b = qalloc(3);
  auto anc = qalloc(1);
  test_add_integer_mod::print_kernel(b, anc[0]);
  test_add_integer_mod(b, anc[0]);
  test_add_integer_mod::print_kernel(b);
  test_add_integer_mod(b);
  // |3 mod 5> and |7 mod 5> == |2> + |3>
  b.print();
  qcor_expect(b.counts().size() == 2);
  qcor_expect(b.counts()["110"] > 400);
  qcor_expect(b.counts()["010"] > 400);
  anc.print();
  // anc returns to 0
  qcor_expect(anc.counts()["0"] == 1024);

  // Test modular multiply 
  int a_val = 3;
@@ -70,9 +65,8 @@ int main(int argc, char **argv) {
  // More qubits to save the result
  auto b_reg = qalloc(5);
  auto x_reg = qalloc(2);
  auto anc_reg = qalloc(1);
  test_mul_integer::print_kernel(x_reg, b_reg, anc_reg[0], a_val, N_val);
  test_mul_integer(x_reg, b_reg, anc_reg[0], a_val, N_val);
  test_mul_integer::print_kernel(x_reg, b_reg, a_val, N_val);
  test_mul_integer(x_reg, b_reg, a_val, N_val);
  // x = |1> + |3>; |b> = 1
  // |a*x + b> = |4> + |10>
  b_reg.print();
@@ -91,8 +85,7 @@ int main(int argc, char **argv) {
  a_val = 2;
  N_val = 8;
  auto x_reg2 = qalloc(3);
  auto anc_reg2 = qalloc(5);
  test_mul_integer_inline(x_reg2, anc_reg2, a_val, N_val);
  test_mul_integer_inline(x_reg2, a_val, N_val);
  x_reg2.print();
  qcor_expect(x_reg2.counts().size() == 2);
  // 2
+22 −5
Original line number Diff line number Diff line
@@ -144,13 +144,18 @@ __qpu__ void phase_add_integer_mod(qreg q, qubit anc, int a, int N) {
// Add an integer a mod N to the a qubit register:
// |q> --> |q + a mod N>
// TODO: ability to create scratch qubits
__qpu__ void add_integer_mod(qreg q, qubit anc, int a, int N) {
__qpu__ void add_integer_mod_impl(qreg q, qubit anc, int a, int N) {
  // Bring it to Fourier basis
  // (IQFT automatically)
  compute { qft_opt_swap(q, 0); }
  action { phase_add_integer_mod(q, anc, a, N); }
}

__qpu__ void add_integer_mod(qreg q, int a, int N) {
  auto anc = qalloc(1);
  add_integer_mod_impl(q, anc[0], a, N);
}

// Modular multiply in phase basis:
// See Fig. 6 of https://arxiv.org/pdf/quant-ph/0205095.pdf  
// |x>|b> ==> |x> |b + ax mod N>
@@ -164,20 +169,25 @@ __qpu__ void phase_mul_integer_mod(qreg x, qreg b, qubit anc, int a, int N) {
  }
}

__qpu__ void mul_integer_mod(qreg x, qreg b, qubit anc, int a, int N) {
__qpu__ void mul_integer_mod_impl(qreg x, qreg b, qubit anc, int a, int N) {
  // Bring it to Fourier basis
  // (IQFT automatically)
  compute { qft_opt_swap(b, 0); }
  action { phase_mul_integer_mod(x, b, anc, a, N); }
}

__qpu__ void mul_integer_mod(qreg x, qreg b, int a, int N) {
  auto anc = qalloc(1);
  mul_integer_mod_impl(x, b, anc[0], a, N);
}

// Modular multiply in-place:
// See Fig. 7 (https://arxiv.org/pdf/quant-ph/0205095.pdf)
// |x>|0> ==> |ax mod N>|0>
// x and aux_reg must have the same size.
__qpu__ void mul_integer_mod_in_place(qreg x, qreg aux_reg, qubit anc, int a, int N) {
__qpu__ void mul_integer_mod_in_place_impl(qreg x, qreg aux_reg, qubit anc, int a, int N) {
  Reset(aux_reg);
  mul_integer_mod(x, aux_reg, anc, a, N);
  mul_integer_mod_impl(x, aux_reg, anc, a, N);
  // Swap the result to x register
  for (int i = 0; i < x.size(); ++i) {
    Swap(x[i], aux_reg[i]);
@@ -186,5 +196,12 @@ __qpu__ void mul_integer_mod_in_place(qreg x, qreg aux_reg, qubit anc, int a, in
  int aInv = 0;
  qcor::internal::modinv(aInv, a, N);
  // Apply modular multiply of 1/a
  mul_integer_mod::adjoint(x, aux_reg, anc, aInv, N);
  mul_integer_mod_impl::adjoint(x, aux_reg, anc, aInv, N);
}

// |x> ==> |ax mod N> in-place
__qpu__ void mul_integer_mod_in_place(qreg x, int a, int N) {
  auto aux_reg = qalloc(x.size() + 1);
  auto anc_reg = qalloc(1);
  mul_integer_mod_in_place_impl(x, aux_reg, anc_reg[0], a, N);
}
 No newline at end of file