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

Added QFT in Q#



Fixed interop issue with Pauli types in ctrl-version: need to use fixed-size bool array to match LLVM i2 type.

Added a cpp script to inspect the qs IQFT circuit.

Cannot used w/ QASM3 yet due to internal-declared issue (cannot link)

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent bb8a4c2b
Loading
Loading
Loading
Loading
+61 −0
Original line number Diff line number Diff line
namespace QCOR 
{
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Convert;

operation SWAP(q1 : Qubit, q2: Qubit) : Unit is Adj {
  CNOT(q1, q2);
  CNOT(q2, q1);
  CNOT(q1, q2);
}

// 1-qubit QFT
operation OneQubitQFT (q : Qubit) : Unit is Adj {
  H(q);
}
// Rotation gate
// Applies a rotation about the |1⟩ state by an angle 
// specified as a dyadic fraction.
operation Rotation (q : Qubit, k : Int) : Unit is Adj+Ctl {
  let angle = 2.0 * 3.14159 / IntAsDouble(1 <<< k);
  // Message($"Angle {angle}");
  Rz(angle, q);
}
// Prepare binary fraction exponent in place (quantum input)
operation BinaryFractionQuantumInPlace (register : Qubit[]) : Unit is Adj {
  OneQubitQFT(register[0]);
  for ind in 1 .. Length(register) - 1 {
      // Message("Apply BinaryFractionQuantumInPlace");
      Controlled Rotation([register[ind]], (register[0], ind + 1));
  }
}
// Reverse the order of qubits
operation ReverseRegister (register : Qubit[]) : Unit is Adj {
    let N = Length(register);
    for ind in 0 .. N / 2 - 1 {
        SWAP(register[ind], register[N - 1 - ind]);
    }
}
// Quantum Fourier transform
// Input: A register of qubits in state |j₁j₂...⟩
// Goal: Apply quantum Fourier transform to the input register
operation QuantumFourierTransform (register : Qubit[]) : Unit is Adj {
  let n = Length(register);
  for i in 0 .. n - 1 {
      BinaryFractionQuantumInPlace(register[i ...]);
  }
  ReverseRegister(register);
}

operation IQFT (register : Qubit[]) : Unit {
  Adjoint QuantumFourierTransform(register);
}

@EntryPoint() 
operation Dummy(): Unit {
  use qubits = Qubit[3] 
  {
    IQFT(qubits);
  }
}
}
 No newline at end of file
+18 −0
Original line number Diff line number Diff line
#include <iostream>
#include <vector>

// For testing Q# IQFT circuit...
// Currently, Qubits are **not** allowed in EntryPoint => need to use a dummy entry point.
qcor_include_qsharp(QCOR__Dummy, void);

// Compile with:
// Include both the qsharp source and this driver file
// in the command line.
// Use print-final-submission to see the instructions executed.
// $ qcor -qrt ftqc -print-final-submission ...
// Run with:
// $ ./a.out
int main() {
  QCOR__Dummy();
  return 0;
}
 No newline at end of file
+7 −2
Original line number Diff line number Diff line
@@ -85,20 +85,24 @@ void __quantum__qis__r__adj(Pauli pauli, double theta, Qubit *q) {
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
  __quantum__qis__r__body(pauli, -theta, q);
}
void __quantum__qis__r__ctl(Array *ctls, Pauli pauli, double theta, Qubit *q) {

void __quantum__qis__r__ctl(Array *ctls, bool pauli_raw[2], double theta, Qubit *q) {
  if (verbose)
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
  
  std::vector<Qubit *> ctrl_qubits;
  for (int i = 0; i < ctls->size(); ++i) {
    int8_t *arrayPtr = (*ctls)[i];
    Qubit *ctrl_qubit = *(reinterpret_cast<Qubit **>(arrayPtr));
    ctrl_qubits.emplace_back(ctrl_qubit);
  }
  Pauli pauli = static_cast<Pauli>(*pauli_raw);
  __quantum__rt__start_ctrl_u_region();
  __quantum__qis__r__body(pauli, theta, q);
  __quantum__rt__end_multi_ctrl_u_region(ctrl_qubits);
}
void __quantum__qis__r__ctladj(Array *ctls, Pauli pauli, double theta,

void __quantum__qis__r__ctladj(Array *ctls, bool pauli_raw[2], double theta,
                               Qubit *q) {
  if (verbose)
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
@@ -109,6 +113,7 @@ void __quantum__qis__r__ctladj(Array *ctls, Pauli pauli, double theta,
    Qubit *ctrl_qubit = *(reinterpret_cast<Qubit **>(arrayPtr));
    ctrl_qubits.emplace_back(ctrl_qubit);
  }
  Pauli pauli = static_cast<Pauli>(*pauli_raw);
  __quantum__rt__start_ctrl_u_region();
  __quantum__qis__r__body(pauli, -theta, q);
  __quantum__rt__end_multi_ctrl_u_region(ctrl_qubits);
+5 −2
Original line number Diff line number Diff line
@@ -14,10 +14,13 @@ void __quantum__qis__exp__ctladj(Array *ctls, Array *paulis, double angle,
                                 Array *qubits);
void __quantum__qis__h__body(Qubit *q);
void __quantum__qis__h__ctl(Array *ctls, Qubit *q);

void __quantum__qis__r__body(Pauli pauli, double theta, Qubit *q);
void __quantum__qis__r__adj(Pauli pauli, double theta, Qubit *q);
void __quantum__qis__r__ctl(Array *ctls, Pauli pauli, double theta, Qubit *q);
void __quantum__qis__r__ctladj(Array *ctls, Pauli pauli, double theta,
// Use bool array to get the i2 Pauli from LLVM:
// To prevent any potential padding issues for these function signatures.
void __quantum__qis__r__ctl(Array *ctls, bool pauli[2], double theta, Qubit *q);
void __quantum__qis__r__ctladj(Array *ctls, bool pauli[2], double theta,
                               Qubit *q);
void __quantum__qis__s__body(Qubit *q);
void __quantum__qis__s__adj(Qubit *q);