Skip to content

Examples

This page contains examples for you to learn language features and see how they are used in practice.

Bell state, slightly refactored

qfunc main(output a: qbit, output b: qbit) {
    allocate<1>(a);
    allocate<1>(b);
    bell_state(a, b);
}

qfunc bell_state(inout a: qbit, inout b: qbit) {
   H(a);
   CX(a, b);
}

This is the same Bell state you can see in the default example, but with logic extracted to a function.

GHZ

qfunc main(output a: qbit, output b: qbit, output c: qbit) {
    allocate<1>(a);
    allocate<1>(b);
    allocate<1>(c);
    ghz(a, b, c);
}

qfunc ghz(inout a: qbit, inout b: qbit, inout c: qbit) {
    bell_state(a, b);
    CX(b, c);
}

qfunc bell_state(inout ctrl: qbit, inout target: qbit) {
   H(ctrl);
   CX(ctrl, target);
}

Quantum Phase Estimation

Below is a complete implementation of the QPE algorithm and a couple of required building blocks.

// Can be inlined to `my_qft` but this looks cleaner.
qfunc my_qft_step(qbv: qbit[]){
  H(qbv[0]);
  repeat<len(qbv) - 1, lambda<j>(){
    CPHASE<pi/2**(j+1)>(qbv[j+1], qbv[0])
  }>();
}

qfunc my_qft(qbv: qbit[]) {
  repeat<len(qbv)/2, lambda<i>(){ // swap pairs outer to inner.
    SWAP(qbv[i], qbv[len(qbv)-1-i]);
  }>();
  repeat<len(qbv), lambda<i>(){
    my_qft_step(qbv[i:len(qbv)]);
  }>();
}

qfunc my_apply_to_all<single_qubit_operand: qfunc (target: qbit)>(q: qbit[]){
  repeat<len(q), lambda<i>(){single_qubit_operand(q[i]);}>();
}

qfunc my_hadamard_transform(q: qbit[]){
  my_apply_to_all<H>(q);
}

qfunc my_qpe<unitary: qfunc (), precision: int>(output phase: qnum) {
  packed: qbit[];
  msb: qbit;
  allocate<1>(msb);
  allocate<precision>(phase);
  my_hadamard_transform(phase);
  {phase, msb} -> packed;

  repeat<precision, lambda<i>(){
    control<lambda<>(){
      power<2**i, lambda (){
        unitary()
      }>();
    }>(packed[i]);
  }>();

  packed -> {phase, msb};
  invert<lambda (){
    my_qft(phase);
  }>();
}

The following code demonstrates how the function my_qpe defined above is used to estimate the eigenvalue phase of a simple unitary.

qfunc main(output phase: qnum) {
    state: qbit[2];
    allocate<2>(state);
    my_apply_to_all<X>(state);
    my_qpe<lambda (){
      RZZ<pi>(state);
    }, 4>(phase);
}

Below is a complete implementation of the grover search algorithm and a couple of required building blocks.

qfunc my_apply_to_all<single_qubit_operand: qfunc (target: qbit)>(q: qbit[]){
  repeat<len(q), lambda<i>(){single_qubit_operand(q[i]);}>();
}

qfunc my_hadamard_transform(q: qbit[]){
  my_apply_to_all<H>(q);
}

qfunc my_grover_diffuser(target: qbit[]){
  msbs: qbit[len(target)-1];
  lsb: qbit;
  my_apply_to_all<X>(target);
  target -> {msbs, lsb}
  control<lambda (){
    Z(lsb);
  }(msbs);
  {msbs, lsb} -> target;
}

qfunc my_grover_operator<sp_op: qfunc (q: qbit[len(target)]), oracle_op: qfunc (oq: qbit[len(target)])>(target: qbit[]){
  oracle_op(target);
  sp_op(target);
  my_grover_diffuser(target);
  invert<lambda (){
    sp_op(target)
  }>();
  U<0, 0, 0, pi>(target[0]);
}

qfunc my_grover_search<reps: int, oracle_op: qfunc (oq: qbit[len(packed)])>(packed: qbit[]) {
  my_hadamard_transform(packed);
  repeat<reps, lambda <i>() {
    my_grover_operator<my_hadamard_transform, oracle_op>(packed);
  }();
}

The following code demonstrates how the function my_grover_search defined above is used to search for the solutions of the arithmetic expression 2a + b == 6.

qfunc my_oracle<predicate: qfunc(vars: qbit[len(target)], result: qbit)>(target: qbit[]){
  aux: qbit;
  allocate<1>(aux);
  X(aux);
  H(aux);
  predicate(target, aux);
  H(aux);
  X(aux);
  free(aux);
}

qfunc my_predicate(a: qbit[3], b: qbit[3], res: qbit){
  res ^= 2* a + b == 6;
}

qfunc main(output a: qbit[3], output b: qbit[3]){
  allocate<3>(a);
  allocate<3>(b);
  packed: qbit[];
  {a, b} -> packed;
  my_grover_search<1, lambda (oq) {
    my_oracle<lambda (vars, result){
      my_predicate(vars[0:3], vars[3: len(vars)], result);
    }>(oq);
  }(packed);
  packed -> {a, b};
}