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

More fixes while debugging the Q# IQFT



We need to handle rotation around I (global phase adjustment) since this is the way Q# implement CPhase (called R1)

Added the full QPE test to make sure the runtime is fully compatible.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 86697187
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -11,3 +11,4 @@ endfunction()
add_qcor_qsharp_test(qcor_qsharp_bell FTQC/Bell/bell.qs FTQC/Bell/bell_driver.cpp)
add_qcor_qsharp_test(qcor_qsharp_deuteron FTQC/Deuteron/vqe_ansatz.qs FTQC/Deuteron/vqe_driver.cpp)
add_qcor_qsharp_test(qcor_qsharp_functor FTQC/Functor/functor.qs FTQC/Functor/driver.cpp)
add_qcor_qsharp_test(qcor_qsharp_qpe FTQC/qpe/qpe.qs FTQC/qpe/driver.cpp)
 No newline at end of file
+0 −33
Original line number Diff line number Diff line
namespace QCOR 
{
// Using QCOR Intrinsic instruction set
// see QirTarget.qs    
open QCOR.Intrinsic;
@EntryPoint()
operation ValidEntryPoint() : Unit { }

@EntryPoint()
operation TestBell(count : Int) : Unit {
    // Simple bell test
    mutable numOnes = 0;
    mutable agree = 0;
    use q = Qubit[2];
    for test in 1..count {
        H(q[0]);
        CNOT(q[0],q[1]);
        let res0 = M(q[0]);
        let res1 = M(q[1]);
        if res0 == res0 {
            set agree += 1;
        }

        // Count the number of ones we saw:
        if res0 == One {
            set numOnes += 1;
        }
        
        Reset(q[0]);
        Reset(q[1]);
    }
}
}
 No newline at end of file
+12 −0
Original line number Diff line number Diff line
#include <iostream> 
#include <vector>


qcor_include_qsharp(QCOR__QuantumPhaseEstimation__Interop, int64_t)

int main() {
  auto result = QCOR__QuantumPhaseEstimation__Interop();
  std::cout << "Result decimal: " << result << "\n";
  qcor_expect(result == 4);
  return 0;
}
 No newline at end of file
+76 −0
Original line number Diff line number Diff line
namespace QCOR 
{
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Canon;
operation SWAP(q1 : Qubit, q2: Qubit) : Unit is Adj {
  CNOT(q1, q2);
  CNOT(q2, q1);
  CNOT(q1, q2);
}

operation Rotation (q : Qubit, angle: Double) : Unit is Adj+Ctl {
  R1(angle, q);
}

operation IQFT(qq: Qubit[]): Unit {
  for i in 0 .. Length(qq)/2 - 1 {
    SWAP(qq[i], qq[Length(qq)-i-1]);
  }
    
  for i in 0 .. Length(qq) - 2 {
    H(qq[i]);
    let j = i + 1;
    mutable y = i;
    repeat {
      let theta = -3.14159 / IntAsDouble(1 <<< (j-y));
      Controlled Rotation([qq[j]], (qq[y], theta));
      set y = y - 1;
    } until (y < 0);
  }

  H(qq[Length(qq) -1]);
}

operation t_oracle (qb: Qubit) : Unit is Adj+Ctl {
  // Oracle = T gate
  T(qb);
}

@EntryPoint() 
operation QuantumPhaseEstimation(): Int {
  // 3-qubit QPE:
  use (counting, state) = (Qubit[3], Qubit()) 
  {
    // We want T |1> = exp(2*i*pi*phase) |1> = exp(i*pi/4)
    // compute phase, should be 1 / 8;
    // Initialize to |1>
    X(state);
    // Put all others in a uniform superposition
    // Use this Q# equiv. of broadcast:
    ApplyToEach(H, counting);
    mutable repetitions = 1;
    for i in 0 .. Length(counting) - 1 {
      // Loop over and create ctrl-U**2k
      for j in 1 .. repetitions {
        Controlled t_oracle([counting[i]], state);
      }
      set repetitions = repetitions * 2;
    }

    // Run IQFT 
    IQFT(counting);
    mutable result = 0; 
    // Now lets measure the counting qubits
    // Convert it to MSB ==> expect 4
    for i in 0 .. Length(counting) - 1 {
      if (M(counting[i]) == One) {
        set result = result + (1 <<< (Length(counting) - i - 1));
        X(counting[i]);
      }
    }
    Message($"Result = {result}");
    return result;
  }
}
}
 No newline at end of file
+12 −2
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
#include <iostream>
#include <math.h>
#include <stdexcept>
#include "qrt.hpp"

namespace {
static std::vector<Pauli> extractPauliIds(Array *paulis) {
@@ -61,9 +62,18 @@ void __quantum__qis__r__body(Pauli pauli, double theta, Qubit *q) {
  if (verbose)
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
  switch (pauli) {
  case Pauli::Pauli_I:
    // nothing to do
  case Pauli::Pauli_I: {
    // Q# use rotation aroung I to cancel global phase
    // due to Rz and U1 differences.
    // Since Q# doesn't have native CPhase gate, we need to handle
    // this properly in order for phase estimation to work.
    // Rotation(theta) aroung I is defined as:
    // diag(exp(-i*theta/2), exp(-i*theta/2)) == Phase(-theta)*Rz(theta)
    __quantum__qis__rz(theta, q);
    std::size_t qcopy = q->id;
    ::quantum::u1({"q", qcopy}, -theta);
    break;
  }
  case Pauli::Pauli_X: {
    __quantum__qis__rx(theta, q);
    break;