Comparison to Q#

To compare Silq to Q#, we solved all 28 tasks of Microsoft’s Q# Summer 2018 and Winter 2019 coding contest in Silq. We compared the Silq solutions to the Q# reference solutions provided by the language designers from 2018 and 2019.

Examples

Based on manual investigation of the contestants’ code, we believe they could encode their intended solutions better in Silq. In the following, we show two frequently occurring patterns.

Flip Before Control

// Q# code snippet
X(qs[0]); X(qs[1]);
(Controlled X)(qs, a[0]);
X(qs[0]); X(qs[1]);

In the above Q# code snippet, the programmer wants to flip the bit of a[0] if both qs[0] and qs[1] are 0. In Q#, this requires (i) flipping qs[0] and qs[1], (ii) applying X conditioned on qs, and (iii) reversing step (i).

In contrast, Silq leverages automatic uncomputation to express this snippet as:

// Silq code snippet corresponding to the above Q# code snippet
if !qs[0] && !qs[1] {
  a[0] := X(a[0]);
}

Initializing Qubits

// Q# code snippet (some parts omitted)
operation Set(des:Result,q:Qubit):(){
  ... // omitted
}
operation Solve(qs:Qubit[]):(){ body{
  for (i in 0..Length(qs)-1){
    Set(Zero,qs[i]);
  }
  ... // omitted
}}

In the above Q# code snippet, the programmer wants to initialize the k-bit integer qs to zero, operate on it, and return the result. However, since Q# does not allow to allocate and return qubits, the code must take a pre-allocated qs and explicitly set it to zero.

In contrast, Silq simply initializes qs to zero:

// Silq code snippet corresponding to the above Q# code snippet
def solve(k:!){
  qs:=0:int[k];
  ... // omitted
}