├── Chapter07
├── bellstate.slq
├── decomposedcx.slq
├── ghz.slq
├── superdensecoding.slq
├── halfadder.slq
├── multiqubitgates.slq
└── teleportation.slq
├── Chapter06
├── geometric.slq
├── uniformsuperposition.slq
├── singlequbitgates.slq
└── superposition.slq
├── Chapter09
├── helpers
│ ├── groverDiffusion.slq
│ └── rand.slq
├── simon.slq
├── groverSimple.slq
├── groverMultiple.slq
└── groverUnknown.slq
├── Chapter10
├── qft.slq
└── phaseEstimation.slq
├── LICENSE
├── Chapter08
├── bernsteinVazirani.slq
└── deutschJozsa.slq
├── Chapter11
├── bitFlipCode.slq
├── phaseFlipCode.slq
└── shorCode.slq
├── README.md
└── Chapter12
└── qkd.slq
/Chapter07/bellstate.slq:
--------------------------------------------------------------------------------
1 | def main() {
2 | return BellState();
3 | }
4 |
5 | def BellState(){
6 | b:=1:𝔹;
7 | b:=H(b);
8 |
9 | c:=1:𝔹;
10 | if b{
11 | c := X(c);
12 | }
13 |
14 | return (b,c);
15 |
16 | }
--------------------------------------------------------------------------------
/Chapter07/decomposedcx.slq:
--------------------------------------------------------------------------------
1 | def main() {
2 | return DecomposedCX();
3 | }
4 |
5 | def DecomposedCX(){
6 | b:=1:𝔹;
7 | b:=H(b);
8 |
9 | a:=1:𝔹;
10 | if a{
11 | b := Z(b);
12 | }
13 |
14 | b:=H(b);
15 |
16 | return b;
17 | }
--------------------------------------------------------------------------------
/Chapter06/geometric.slq:
--------------------------------------------------------------------------------
1 | def main() {
2 | return geometric();
3 | }
4 |
5 | def geometric():!ℕ{
6 | count := 0;
7 | ok := true;
8 | while ok{
9 | count += 1;
10 | ok = measure(H(false));
11 | }
12 | return count;
13 | }
--------------------------------------------------------------------------------
/Chapter09/helpers/groverDiffusion.slq:
--------------------------------------------------------------------------------
1 | // Grover Diffusion Operator
2 |
3 | def groverDiffusion[n:!ℕ](cand:uint[n])mfree: uint[n]{
4 | for k in [0..n) { cand[k] := H(cand[k]); }
5 | if cand!=0{ phase(π); }
6 | for k in [0..n) { cand[k] := H(cand[k]); }
7 | return cand;
8 | }
9 |
--------------------------------------------------------------------------------
/Chapter07/ghz.slq:
--------------------------------------------------------------------------------
1 | def main() {
2 | return GHZ();
3 | }
4 |
5 | def GHZ(){
6 | a:=0:𝔹;
7 | b:=0:𝔹;
8 | c:=0:𝔹;
9 |
10 | a:=H(a);
11 |
12 | if a{
13 | b := X(b);
14 | }
15 |
16 | if b{
17 | c := X(c);
18 | }
19 |
20 | return (a,b,c);
21 |
22 | }
--------------------------------------------------------------------------------
/Chapter06/uniformsuperposition.slq:
--------------------------------------------------------------------------------
1 | def main() {
2 | return UniformSuperposition[1]();
3 | }
4 |
5 | def UniformSuperposition[n:!ℕ]():𝔹^n{
6 | qubits := vector(n,0:𝔹); // vector of length n filled with zeros
7 | for i in [0..n){
8 | qubits[i] := H(qubits[i]);
9 | }
10 | return qubits;
11 | }
--------------------------------------------------------------------------------
/Chapter06/singlequbitgates.slq:
--------------------------------------------------------------------------------
1 | def main() {
2 | return Hadamard();
3 | }
4 |
5 | def Hadamard() {
6 | x:=0:𝔹;
7 | return H(x);
8 | }
9 |
10 | def PauliZ() {
11 | z:=1:𝔹;
12 | return Z(z);
13 | }
14 |
15 | def PauliY() {
16 | y:=1:𝔹;
17 | return Y(y);
18 | }
19 |
20 | def PauliX() {
21 | x:=0:𝔹;
22 | return X(x);
23 | }
--------------------------------------------------------------------------------
/Chapter10/qft.slq:
--------------------------------------------------------------------------------
1 | // Quantum Fourier Transform
2 |
3 |
4 | def QFT[n:!ℕ](ψ: int[n])mfree: int[n]{
5 | for k in [0..n div 2){
6 | (ψ[k],ψ[n-k-1]) := (ψ[n-k-1],ψ[k]);
7 | }
8 | for k in [0..n){
9 | ψ[k] := H(ψ[k]);
10 | for l in [k+1..n){
11 | if ψ[l] && ψ[k]{
12 | phase(2*π * 2^(k-l-1));
13 | }
14 | }
15 | }
16 | return ψ;
17 | }
18 |
19 |
20 | def main(){
21 | ψ := 2:int[2];
22 | return QFT(ψ);
23 | }
24 |
--------------------------------------------------------------------------------
/Chapter07/superdensecoding.slq:
--------------------------------------------------------------------------------
1 | def main() {
2 | return SuperDenseCoding();
3 | }
4 |
5 | def SuperDenseCoding(){
6 | a:=0:𝔹;
7 | b:=0:𝔹;
8 |
9 | // Bell State Preparation
10 | a:=H(a);
11 | if a{
12 | b := X(b);
13 | }
14 |
15 | // Alice's Operation - 11 is sent
16 | a:=Z(a);
17 | a:=X(a);
18 |
19 | // Bob's Operation
20 | if a{
21 | b := X(b);
22 | }
23 |
24 | a:=H(a);
25 |
26 | return(a,b);
27 | }
--------------------------------------------------------------------------------
/Chapter07/halfadder.slq:
--------------------------------------------------------------------------------
1 | def main() {
2 | return HalfAdder();
3 | }
4 |
5 | def HalfAdder(){
6 | // Define 4 Qubits - a & b inputs, s & c are sum and carry - outputs
7 | a:=1:𝔹;
8 | b:=1:𝔹;
9 | s:=0:𝔹;
10 | c:=0:𝔹;
11 |
12 | // XOR Gate Operation
13 |
14 | // CX operation on b and s qubit
15 | if b{
16 | s := X(s);
17 | }
18 |
19 | // CX operation on a and s
20 | if a{
21 | s := X(s);
22 | }
23 |
24 | // AND Gate Operation
25 |
26 | if a && b{
27 | c := X(c);
28 | }
29 |
30 | return (s,c);
31 | }
--------------------------------------------------------------------------------
/Chapter09/helpers/rand.slq:
--------------------------------------------------------------------------------
1 | // Random number generators
2 |
3 | def uniformInt(range:!ℕ){
4 | // returns x~{0,...range-1}
5 | n:=ceil(log(range)/log(2)) coerce !ℕ;
6 | r:=range;
7 | while (r>range-1) {
8 | // rerolls r if it is greater than range
9 | r=0;
10 | for k in [0..n){
11 | // rolls each bit of r
12 | r+=2^k*rand();
13 | }
14 | }
15 | return r;
16 | }
17 |
18 | def rand(){
19 | // quantum number generator
20 | return measure(H(false));
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/Chapter07/multiqubitgates.slq:
--------------------------------------------------------------------------------
1 | def CSWAP(x:𝔹, y:𝔹, z:𝔹) {
2 | if x{
3 | a:=z;
4 | z:=y;
5 | y:=a;
6 | }
7 | return (x,y,z);
8 | }
9 |
10 | def SWAP(x:𝔹, y:𝔹) {
11 | a:=y;
12 | y:=x;
13 | x:=a;
14 | return (x,y);
15 | }
16 |
17 | def CCX(const x:𝔹,const y:𝔹,z:𝔹):𝔹{
18 | if x && y{
19 | z := X(z);
20 | }
21 | return (z);
22 | }
23 |
24 | def CZ(const x:𝔹,y:𝔹):𝔹{
25 | if x{
26 | y := Z(y);
27 | }
28 | return y;
29 | }
30 |
31 | def CX(const x:𝔹,y:𝔹):𝔹{
32 | if x{
33 | y := X(y);
34 | }
35 | return y;
36 | }
--------------------------------------------------------------------------------
/Chapter10/phaseEstimation.slq:
--------------------------------------------------------------------------------
1 | // Phase Estimation algorithm
2 |
3 | import qft;
4 |
5 | def phaseEstimation[k:!ℕ](
6 | U:int[k] !->mfree int[k],
7 | u:int[k],
8 | precision:!ℕ) {
9 |
10 | ancilla := 0:int[precision];
11 | for i in [0..precision) { ancilla[i] := H(ancilla[i]); }
12 |
13 | for i in [0..precision) {
14 | if ancilla[i] {
15 | for l in [0..2^i) {
16 | u := U(u);
17 | }
18 | }
19 | }
20 |
21 | ancilla := reverse(QFT[precision])(ancilla);
22 | result := measure(ancilla);
23 | measure(u);
24 | return result;
25 | }
26 |
--------------------------------------------------------------------------------
/Chapter07/teleportation.slq:
--------------------------------------------------------------------------------
1 | def main() {
2 | return Teleportation();
3 | }
4 |
5 | def Teleportation(){
6 |
7 | // Initialize Qubits - 'a' qubit is to be teleported by Alice to Bob
8 | a:=0:𝔹;
9 | b:=0:𝔹;
10 | c:=0:𝔹;
11 |
12 | // Alice's Operations
13 |
14 | // Creating the Bell State
15 | b:=H(b);
16 |
17 | if b{
18 | c := X(c);
19 | }
20 |
21 | // Alice applies CX and H to 'a' qubit
22 |
23 | if a{
24 | b := X(b);
25 | }
26 |
27 | a:=H(a);
28 |
29 | // Alice measures her qubits 'a' and 'b'
30 |
31 | ma1:=measure(a);
32 | ma2:=measure(b);
33 | print(ma1);
34 | print(ma2);
35 |
36 | // Bob's measurement
37 |
38 | //c:=X(c);
39 | //c:=Z(c);
40 |
41 | return (c);
42 | }
--------------------------------------------------------------------------------
/Chapter09/simon.slq:
--------------------------------------------------------------------------------
1 | // Simon's algorithm
2 |
3 | def main() {
4 | return Simon();
5 | }
6 |
7 | def Simon(){
8 | // Initializing Qubits for Inputs - a,b,c and Oracle - d,e,f
9 | a:=0:𝔹;
10 | b:=0:𝔹;
11 | c:=0:𝔹;
12 | d:=0:𝔹;
13 | e:=0:𝔹;
14 | f:=0:𝔹;
15 |
16 | // Applying Hadamard to Inputs
17 | a:=H(a);
18 | b:=H(b);
19 | c:=H(c);
20 |
21 | // Encoding 011 secret key in the Oracle
22 |
23 | if b{
24 | d := X(d);
25 | }
26 |
27 | if b{
28 | e := X(e);
29 | }
30 |
31 | if c{
32 | d := X(d);
33 | }
34 |
35 | if b{
36 | f := X(f);
37 | }
38 |
39 | if c{
40 | e := X(e);
41 | }
42 |
43 | if c{
44 | f := X(f);
45 | }
46 |
47 | // Applying Hadamard to Inputs
48 |
49 | a:=H(a);
50 | b:=H(b);
51 | c:=H(c);
52 |
53 | // Measure the d,e,f qubits for variable consumption
54 |
55 | md:=measure(d);
56 | me:=measure(e);
57 | mf:=measure(f);
58 |
59 | return (a,b,c,md,me,mf);
60 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Packt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Chapter09/groverSimple.slq:
--------------------------------------------------------------------------------
1 | // Grover's algorithm for a single solution
2 | // - Returns the only x for which f(x) = 1
3 | //
4 | // - More detailed description: https://www.scottaaronson.com/qclec/22.pdf
5 |
6 | import helpers.groverDiffusion;
7 |
8 | def grover[n:!ℕ](f: const uint[n] !→ lifted 𝔹):!ℕ{
9 | nIterations:= round(π / 4 * sqrt(2^n));
10 | cand:=0:uint[n];
11 | for k in [0..n) {cand[k] := H(cand[k]);}
12 |
13 | for k in [0..nIterations){
14 | if f(cand){
15 | phase(π);
16 | }
17 | // state ignoring normalization:
18 | // ∑(v≠w)|v⟩ - |w*⟩
19 | cand:=groverDiffusion(cand);
20 | // ∑(v≠w)γ₋|v⟩ + γ₊|w*⟩
21 | }
22 | return measure(cand) as !ℕ;
23 | }
24 |
25 | /* EXAMPLE CALL */
26 |
27 | def main() {
28 | f := λ(x:uint[5])lifted:𝔹{return x==3;}; // creates an oracle which outputs one only when x=3
29 | x := grover(f);
30 | assert(x==3); // verifies that grover finds the right solution
31 |
32 | return x;
33 | }
34 |
35 | /* TEST */
36 |
37 | // This function defines a test for Grover
38 | def test_grover() {
39 | def f(x:uint[3])lifted:𝔹{
40 | return x==7;
41 | } // creates an oracle which outputs one only when x=3
42 | x := grover(f);
43 | // verifies that grover finds the right solution
44 | assert(x==7);
45 |
46 | return x;
47 | }
48 |
49 |
50 |
--------------------------------------------------------------------------------
/Chapter08/bernsteinVazirani.slq:
--------------------------------------------------------------------------------
1 | // Bernstein-Vazirani algorithm
2 | // - Returns s where f(x) = s·x mod 2
3 | //
4 |
5 | def bernstein_vazirani[n:!ℕ](f: const uint[n] !→ lifted 𝔹):!uint[n]{
6 | cand := 0:uint[n];
7 | for k in [0..n) { cand[k] := H(cand[k]); }
8 |
9 | // state ignoring normalization:
10 | // ∑ᵥ|v⟩
11 |
12 | if f(cand) {
13 | phase(π);
14 | }
15 |
16 | // state ignoring normalization:
17 | // ∑ᵥ(-1)^f(v) |v⟩
18 | // = ∑ᵥ(-1)^(s·v) |v⟩
19 | // = (|0⟩+(-1)^(s₁)|1⟩) ⊗ ⋯ ⊗ (|0⟩+(-1)^(sₙ)|1⟩)
20 |
21 | for k in [0..n) { cand[k] := H(cand[k]); }
22 |
23 | s := measure(cand);
24 | return s;
25 | }
26 |
27 | /* TEST */
28 |
29 | def f[n:!ℕ](s:!uint[n])(x:uint[n])lifted:𝔹{
30 | y := scal(s, x)%2;
31 | return y==1;
32 | }
33 |
34 | def scal[n:!ℕ](const x:uint[n], const y:uint[n])qfree:uint[n] {
35 | // computes the scalar product x·y
36 | count := 0:uint[n];
37 | for k in [0..n) {
38 | count+=x[k] && y[k];
39 | }
40 | return count;
41 | }
42 |
43 | def main() {
44 | // test with all secret strings on 3 bits
45 | for i in [0..8) {
46 | s := i coerce !uint[3];
47 | s₀ := bernstein_vazirani(f(s));
48 | assert(s==s₀);
49 | }
50 |
51 | // test with secret string s = 01
52 | s := 1 coerce !uint[2];
53 | s₀ := bernstein_vazirani(f(s));
54 | return s₀;
55 |
56 | }
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/Chapter11/bitFlipCode.slq:
--------------------------------------------------------------------------------
1 | // Bit-Flip code (Quantum error correction)
2 | // - Returns the qubit ψ where ψ is encoded to a 3-qubit state and then
3 | // - passed through a noisy channel potentially flipping one of the qubits
4 |
5 |
6 | def encode(ψ:𝔹) mfree { // encode a single qubit ψ into a 3-qubit state
7 | ψ := (dup(ψ), dup(ψ), ψ);
8 |
9 | return ψ;
10 | }
11 |
12 | def correct(ψ:𝔹^3) { // correct a single bit-flip error if there is one
13 | // measure the error syndrome
14 | p1 := measure(ψ[0] ⊕ ψ[1]);
15 | p2 := measure(ψ[0] ⊕ ψ[2]);
16 |
17 | // apply the appropriate correction
18 | if (p1 && p2) {
19 | ψ[0] := X(ψ[0]);
20 | } else if (p1) {
21 | ψ[1] := X(ψ[1]);
22 | } else if (p2) {
23 | ψ[2] := X(ψ[2]);
24 | }
25 |
26 | return ψ;
27 | }
28 |
29 | def bit_flip_code(ψ: 𝔹, channel: 𝔹^3 !→ 𝔹^3) { // simulate the bit-flip code error-correcting process
30 | ψ := encode(ψ);
31 | ψ := channel(ψ);
32 | ψ := correct(ψ);
33 | ψ := reverse(encode)(ψ);
34 |
35 | return ψ;
36 | }
37 |
38 | /* EXAMPLES */
39 |
40 | def channel(ψ:𝔹^3) { // flip the first qubit of a 3-qubit state
41 | ψ[0] := X(ψ[0]);
42 | return ψ;
43 | }
44 |
45 | def main() {
46 | // Example 1: basis state
47 | ψ := 1:𝔹;
48 | φ := bit_flip_code(ψ, channel);
49 | // verifies that φ = 1
50 | forget(φ = 1);
51 |
52 | // Example 2: superposition
53 | ψ := H(1:𝔹);
54 | φ := bit_flip_code(ψ, channel);
55 | // verifies that φ = H(|1>)
56 | return φ;
57 | }
58 |
59 |
60 |
--------------------------------------------------------------------------------
/Chapter08/deutschJozsa.slq:
--------------------------------------------------------------------------------
1 | // Deutsch-Jozsa algorithm
2 | // - Returns : | 0 if f is balanced (#{x, f(x)=0} = #{x, f(x)=1})
3 | // | 1 if f is constant (∀x f(x)=0 or ∀x f(x)=1)
4 |
5 |
6 | def deutsch_jozsa[n:!ℕ](f: const int[n] !→ lifted 𝔹):!𝔹{
7 | cand := 0:int[n];
8 | for k in [0..n) { cand[k] := H(cand[k]); }
9 |
10 | // state ignoring normalization:
11 | // ∑ᵥ|v⟩
12 |
13 | if f(cand) {
14 | phase(π);
15 | }
16 |
17 | // state ignoring normalization:
18 | // ∑ᵥ(-1)^f(v)|v⟩
19 |
20 | for k in [0..n) { cand[k] := H(cand[k]); }
21 |
22 | // state ignoring normalization:
23 | // ∑ᵥ(-1)^f(v) ∑ᵤ (-1)^(u·v)|u⟩
24 |
25 | result := measure(cand);
26 | // probability to measure 0 is:
27 | // - 1 if f constant (constructive interference)
28 | // - 0 if f balanced (destructive interference)
29 | return result==0;
30 | }
31 |
32 | /* TEST */
33 |
34 | def test_balanced() {
35 | def balanced(x:int[2])lifted:𝔹{
36 | if (x[0]==1) {
37 | return 1:𝔹;
38 | }
39 | else {
40 | return 0:𝔹;
41 | }
42 | } // implements a balanced function (outputs half 0 and half 1)
43 | x := deutsch_jozsa(balanced);
44 | assert(x == 0);
45 | return x;
46 | }
47 |
48 | def test_constant() {
49 | def constant(x:int[2])lifted:𝔹{
50 | return 1:𝔹;
51 | } // implements a constant function (outputs only 1)
52 | x := deutsch_jozsa(constant);
53 | assert(x == 1);
54 | return x;
55 | }
56 |
57 | def main() {
58 | print(test_balanced()); // DJ on balanced function should output 0
59 | print(test_constant()); // DJ on constant function should output 1
60 | return;
61 | }
62 |
--------------------------------------------------------------------------------
/Chapter11/phaseFlipCode.slq:
--------------------------------------------------------------------------------
1 | // Phase-Flip code (Quantum error correction)
2 | // - Returns the qubit ψ where ψ is encoded to a 3-qubit state and then
3 | // - passed through a noisy channel potentially flipping the phase of one of the qubits
4 |
5 |
6 | def encode(ψ:𝔹) mfree { // encode a single qubit ψ into a 3-qubit state
7 | ψ := (dup(ψ), dup(ψ), ψ);
8 |
9 | return ψ;}
10 |
11 | def correct(ψ:𝔹^3) { // correct a single bit-flip error if there is one
12 | // measure the error syndrome
13 | p1 := measure(ψ[0] ⊕ ψ[1]);
14 | p2 := measure(ψ[0] ⊕ ψ[2]);
15 |
16 | // apply the appropriate correction
17 | if (p1 && p2) {
18 | ψ[0] := X(ψ[0]);
19 | } else if (p1) {
20 | ψ[1] := X(ψ[1]);
21 | } else if (p2) {
22 | ψ[2] := X(ψ[2]);
23 | }
24 |
25 | return ψ;
26 | }
27 |
28 | def phase_flip_code(ψ: 𝔹, channel: 𝔹^3 !→ 𝔹^3) { // simulate the phase-flip code error-correcting process
29 | ψ := encode(ψ);
30 |
31 | for k in [0..3) {ψ[k] := H(ψ[k]);}
32 | ψ := channel(ψ);
33 | for k in [0..3) {ψ[k] := H(ψ[k]);}
34 |
35 | ψ := correct(ψ);
36 | ψ := reverse(encode)(ψ);
37 |
38 | return ψ;
39 | }
40 |
41 | /* EXAMPLES */
42 |
43 | def channel(ψ:𝔹^3) { // flip the phase of the second qubit of a 3-qubit state
44 | ψ[1] := Z(ψ[1]);
45 | return ψ;
46 | }
47 |
48 | def main() {
49 | // Example 1: basis state
50 | ψ := 0:𝔹;
51 | φ := phase_flip_code(ψ, channel);
52 | // verifies that φ = 0
53 | forget(φ = 0);
54 |
55 | // Example 2: superposition
56 | ψ := H(0:𝔹);
57 | φ := phase_flip_code(ψ, channel);
58 | // verifies that φ = H(|0>)
59 | return φ;
60 | }
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Chapter09/groverMultiple.slq:
--------------------------------------------------------------------------------
1 | // Grover's algorithm for a known number (M) of solutions
2 | // - Returns one of the x for which f(x) = 1
3 | //
4 | // - More detailed description: https://arxiv.org/ftp/arxiv/papers/0705/0705.4171.pdf
5 |
6 |
7 | import helpers.groverDiffusion;
8 |
9 | def grover_multiple[n:!ℕ](f: const uint[n] !→ lifted 𝔹, M:!ℕ):!ℕ{
10 | nIterations:= round((π/4) * sqrt(2^n/M));
11 | cand:=0:uint[n];
12 | for k in [0..n) { cand[k] := H(cand[k]); }
13 |
14 | for k in [0..nIterations){
15 | if f(cand){
16 | phase(π);
17 | }
18 | cand:=groverDiffusion(cand);
19 | }
20 | return measure(cand) as !ℕ;
21 | }
22 |
23 | /* EXAMPLE CALL */
24 |
25 | def main(){
26 | f := λ(x:uint[6])lifted:𝔹{ return x==4 || x==5 || x==6; };
27 | // creates an oracle which outputs one only when x is in {4,5,6}
28 |
29 | x := grover_multiple(f, 3);
30 |
31 | assert(x==4 || x==5 || x==6);
32 | // verifies that grover_multiple finds one of the right solutions
33 |
34 | return x;
35 | }
36 |
37 | /* TEST */
38 |
39 | // This function defines tests for Grover with respectively 2, 3 and 4 solutions
40 | def test_grover_multiple() {
41 | n := 6;
42 | def f2(x:uint[n])lifted:𝔹{
43 | return x==2 || x==3;
44 | }
45 | def f3(x:uint[n])lifted:𝔹{
46 | return x==4 || x==5 || x==6;
47 | }
48 | def f4(x:uint[n])lifted:𝔹{
49 | return x==7 || x==8 || x==9 || x==10;
50 | } // creates oracles with respectively 2, 3 and 4 solutions
51 | x := grover_multiple(f2, 2);
52 | y := grover_multiple(f3, 3);
53 | z := grover_multiple(f4, 4);
54 | // verifies that grover_multiple finds one of the right solutions
55 | assert(x==2 || x==3);
56 | assert(y==4 || y==5 || y==6);
57 | assert(z==7 || z==8 || z==9 || z==10);
58 | }
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Chapter09/groverUnknown.slq:
--------------------------------------------------------------------------------
1 | // Grover's algorithm for an unknown number of solutions
2 | // - Returns one of the x for which f(x) = 1
3 | //
4 | // - More detailed description: https://arxiv.org/pdf/1709.01236.pdf
5 |
6 | import helpers.groverDiffusion;
7 | import helpers.rand;
8 |
9 | def grover_unknown[n:!ℕ](f: const uint[n] !→ lifted 𝔹):!ℕ{
10 | m := 1:!ℚ;
11 | l := 6/5;
12 |
13 | while (m <= 2^(n/2)) {
14 | nIterations := uniformInt(floor(m) coerce !ℕ) + 1;
15 |
16 | cand := 0:uint[n];
17 | for k in [0..n) {cand[k] := H(cand[k]);}
18 |
19 | for k in [0..nIterations){
20 | if f(cand){
21 | phase(π);
22 | }
23 | cand:=groverDiffusion(cand);
24 | }
25 |
26 | x := measure(cand);
27 |
28 | if f(x) {return x as !ℕ;}
29 | else {m=l*m;}
30 | }
31 |
32 | return 0;
33 | }
34 |
35 | /* EXAMPLE CALL */
36 |
37 | def main(){
38 | f := λ(x:uint[5])lifted:𝔹{ return x==1 || x==2 || x==5 || x==8; };
39 | // creates an oracle which outputs one only when x is in {1,2,5,8}
40 |
41 | x := grover_unknown(f);
42 |
43 | assert(x==1 || x==2 || x==5 || x==8);
44 | // verifies that grover_unknown finds one of the right solutions
45 |
46 | return x;
47 | }
48 |
49 |
50 |
51 | /* TEST */
52 |
53 | // This function defines tests for Grover with respectively 1, 2, 3 and 4 solutions
54 | def test_grover_unknown() {
55 | n := 5;
56 | def f1(x:uint[n])lifted:𝔹{
57 | return x==1;
58 | }
59 | def f2(x:uint[n])lifted:𝔹{
60 | return x==2 || x==3;
61 | }
62 | def f3(x:uint[n])lifted:𝔹{
63 | return x==4 || x==5 || x==6;
64 | }
65 | def f4(x:uint[n])lifted:𝔹{
66 | return x==7 || x==8 || x==9 || x==10;
67 | }
68 | // creates oracles with respectively 1, 2, 3 and 4 solutions
69 | x := grover_unknown(f1);
70 | y := grover_unknown(f2);
71 | z := grover_unknown(f3);
72 | w := grover_unknown(f4);
73 | // verifies that grover_unknown finds one of the right solutions
74 | assert(x==1);
75 | assert(y==2 || y==3);
76 | assert(z==4 || z==5 || z==6);
77 | assert(w==7 || w==8 || w==9 || w==10);
78 | }
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/Chapter11/shorCode.slq:
--------------------------------------------------------------------------------
1 | // Shor code (Quantum error correction)
2 | // - Returns the qubit ψ where ψ is encoded to a 9-qubit state and then
3 | // - passed through a noisy channel potentially altering the state of one of the qubits
4 |
5 |
6 | // Helper function
7 |
8 | def applyToEach[τ,τ'](triple:τ^3, f: τ !→ τ') { // apply a function to each element of a triple
9 | (h0,h1,h2) := triple;
10 | fTriple := (f(h0),f(h1),f(h2));
11 |
12 | return fTriple;
13 | }
14 |
15 |
16 | def triplicate(ψ:𝔹) mfree { // entangle a qubit with two duplicates
17 | ψ := (dup(ψ), dup(ψ), ψ);
18 |
19 | return ψ;
20 | }
21 |
22 | def encode(ψ:B) { // encode a single qubit ψ into a 9-qubit state
23 | ψ := triplicate(ψ);
24 | ψ := applyToEach(ψ, H);
25 | ψ := applyToEach(ψ, triplicate);
26 |
27 | return ψ;
28 | }
29 |
30 | def correct(ψ:𝔹^3) { // correct a single bit-flip error if there is one
31 | // measure the error syndrome
32 | a1 := measure(ψ[0] ⊕ ψ[1]);
33 | a2 := measure(ψ[0] ⊕ ψ[2]);
34 |
35 | // apply the appropriate correction
36 | if (a1 && a2) {
37 | ψ[0] := X(ψ[0]);
38 | } else if (a1) {
39 | ψ[1] := X(ψ[1]);
40 | } else if (a2) {
41 | ψ[2] := X(ψ[2]);
42 | }
43 |
44 | return ψ;
45 | }
46 |
47 | def correctBitFlip(ψ:(B^3)^3) { // correct a single bit-flip error in each triplet of a triplet of triplets
48 | ψ := applyToEach(ψ, correct);
49 |
50 | return ψ;
51 | }
52 |
53 | def correctPhaseFlip(ψ:(B^3)^3) { // correct a single phase-flip error
54 | ψ := applyToEach(ψ, reverse(triplicate));
55 | ψ := applyToEach(ψ, H);
56 | ψ := correct(ψ);
57 |
58 | return ψ
59 | }
60 |
61 | def shor_code(ψ:B, channel: (B^3)^3 !→ (B^3)^3){ // simulate the Shor code error-correcting process
62 | ψ := encode(ψ);
63 |
64 | ψ := channel(ψ);
65 |
66 | ψ := correctBitFlip(ψ);
67 | ψ := correctPhaseFlip(ψ);
68 |
69 | ψ := reverse(triplicate)(ψ);
70 |
71 | return ψ;
72 | }
73 |
74 | /* EXAMPLES */
75 |
76 | def channel(ψ:(𝔹^3)^3) { // flip both one qubit and its phase in a 3x3 structure
77 | ψ[0][1] := Z(ψ[0][1]);
78 | ψ[0][1] := X(ψ[0][1]);
79 | return ψ;
80 | }
81 |
82 | def main() {
83 | // Example 1: basis state
84 | ψ := 1:𝔹;
85 | φ := shor_code(ψ, channel);
86 | // verifies that φ = 1
87 | forget(φ=1);
88 |
89 | // Example 2: superposition
90 | ψ := H(1:𝔹);
91 | φ := shor_code(ψ, channel);
92 | // verifies that φ = H(|1>)
93 | return φ;
94 | }
--------------------------------------------------------------------------------
/Chapter06/superposition.slq:
--------------------------------------------------------------------------------
1 | // Superposition generation
2 | // - Generates the (normalized) superposition |0⟩ + ... + |N-1⟩ on k qubits
3 | //
4 | // - Requires N < 2^k
5 |
6 | def superposition[k:!ℕ](N:!ℕ, qs:𝔹^k)mfree:𝔹^k{
7 | // generates the (normalized) superposition |0⟩ + ... + |N-1⟩ on k qubits
8 |
9 | assert(N <= 2^k);
10 | // ensures that the biggest state |N-1⟩ requires less than k qubits to be written
11 |
12 | n := floor(log(N)/log(2)) coerce !ℕ;
13 | r := N - 2^n coerce !ℕ;
14 | // decomposition N = 2^n + r
15 |
16 | // rotate first qubit
17 | (head,)~tail := qs;
18 | θ := 2*asin(sqrt(r)/sqrt(N));
19 | // sin(θ/2) = sqrt(r/N), cos(θ/2) = sqrt((N-r)/N) = sqrt(2^n/N)
20 |
21 | head := rotY(θ, head);
22 | // |0⟩ ↦ cos(θ/2)|0⟩ + sin(θ/2)|1⟩ = sqrt(2^n/N) |0⟩ + sqrt(r/N)|1⟩
23 |
24 | // state :
25 | // (sqrt(2^n)/sqrt(N))|0⟩⊗(|0⟩⊗ ⋯ ⊗|0⟩) + (sqrt(r)/sqrt(N))|1⟩⊗(|0⟩⊗ ⋯ ⊗|0⟩)
26 |
27 | // conditionally on first qubit either prepare
28 | // the uniform distribution on n qubits or
29 | // (recursively) the remainder |0⟩ + ... + |r-1⟩
30 | if head {
31 | tail := superposition(r, tail); // (|0⟩ + ... + |r-1⟩)/sqrt(r)
32 | }
33 | else {
34 | for i in [0..n) { tail[i] := H(tail[i]); } // ∑ᵥ|v⟩/sqrt(2^n)
35 | }
36 |
37 | // tail = (x₁, ..., xₙ, xₙ₊₁, ..., xₖ) and
38 | // head (= x₀) is the MSB of (x₁, ..., xₙ, x₀)
39 | for i in [0..n div 2) { (tail[i], tail[n-1-i]) := (tail[n-1-i], tail[i]); }
40 | // tail = (xₙ, ..., x₁, xₙ₊₁, ..., xₖ)
41 |
42 | qs:=(head,)~tail;
43 | // qs = (x₀, xₙ, ..., x₁, xₙ₊₁, ..., xₖ)
44 |
45 | for i in [0..(n+1) div 2) { (qs[i], qs[n-i]) := (qs[n-i], qs[i]); }
46 | // qs = (x₁, ..., xₙ, x₀, xₙ₊₁, ..., xₖ)
47 |
48 | // state :
49 | // (sqrt(2^n)/sqrt(N))|0⟩⊗(∑ᵥ|v⟩/sqrt(2^n)) +
50 | // (sqrt(r)/sqrt(N))|1⟩⊗((|0⟩ + ... + |r-1⟩)/sqrt(r)
51 | // = (1/sqrt(N))(|0⟩ + ... + |N-1⟩)
52 |
53 | return qs;
54 | }
55 |
56 | /* TEST */
57 |
58 | def test_superposition() {
59 | k := 5;
60 | qs := vector(k, 0:𝔹);
61 | qs := superposition(19, qs);
62 | measure(qs);
63 | }
64 |
65 | /* EXAMPLE CALL */
66 |
67 | def main() {
68 | N := 19;
69 | // generates the normalized superposition |0⟩ + ... + |18⟩ on 5 qubits
70 | qs := superposition(N, vector(5, 0:𝔹)) as uint[5];
71 |
72 | // measures 0 <= n < 19
73 | n := measure(qs);
74 | assert(n < N);
75 | return(n);
76 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # Quantum Computing with Silq Programming
5 |
6 |
7 |
8 | This is the code repository for [Quantum Computing with Silq Programming](https://www.packtpub.com/in/programming/quantum-computing-with-silq-programming?utm_source=github&utm_medium=repository&utm_campaign=9781800569669), published by Packt.
9 |
10 | **Get up and running with quantum computing with the simplicity of this new high-level programming language**
11 |
12 | ## What is this book about?
13 | Quantum computing is a growing field, with many research projects focusing on programming quantum computers in the most efficient way possible. One of the biggest challenges faced with existing languages is that they work on low-level circuit model details and are not able to represent quantum programs accurately. Developed by researchers at ETH Zurich after analyzing languages including Q# and Qiskit, Silq is a high-level programming language that can be viewed as the C++ of quantum computers! Quantum Computing with Silq Programming helps you explore Silq and its intuitive and simple syntax to enable you to describe complex tasks with less code.
14 |
15 | This book covers the following exciting features:
16 | Identify the challenges that researchers face in quantum programming
17 | Understand quantum computing concepts and learn how to make quantum circuits
18 | Explore Silq programming constructs and use them to create quantum programs
19 | Use Silq to code quantum algorithms such as Grover's and Simon’s
20 | Discover the practicalities of quantum error correction with Silq
21 | Explore useful applications such as quantum machine learning in a practical way
22 |
23 | If you feel this book is for you, get your [copy](https://www.amazon.com/dp/1800569661) today!
24 |
25 |
27 |
28 | ## Instructions and Navigations
29 | All of the code is organized into folders. For example, Chapter02.
30 |
31 | The code will look like the following:
32 | ```
33 | def geometric():!?? {
34 | count := 0;
35 | ok := true;
36 | while ok{
37 | count += 1;
38 | ```
39 |
40 | **Following is what you need for this book:**
41 | This Silq quantum computing book is for students, researchers, and scientists looking to learn quantum computing techniques and software development. Quantum computing enthusiasts who want to explore this futuristic technology will also find this book useful. Beginner-level knowledge of any programming language as well as mathematical topics such as linear algebra, probability, complex numbers, and statistics is required.
42 |
43 | With the following software and hardware list you can run all code files present in the book (Chapter 1-13).
44 | ### Software and Hardware List
45 | | No. | Software required | OS required |
46 | | -------- | ------------------------------------ | ----------------------------------- |
47 | | 1 | Visual Studio with Silq plugin | Windows, Mac OS X, and Linux (Any) |
48 |
49 |
50 | We also provide a PDF file that has color images of the screenshots/diagrams used in this book. [Click here to download it](https://static.packt-cdn.com/downloads/9781800569669_ColorImages.pdf).
51 |
52 | ### Related products
53 | * Dancing with Qubits [[Packt]](https://www.packtpub.com/product/dancing-with-qubits/9781838827366?utm_source=github&utm_medium=repository&utm_campaign=9781838827366) [[Amazon]](https://www.amazon.com/dp/1838827366)
54 |
55 | * Learn Quantum Computing with Python and IBM Quantum Experience [[Packt]](https://www.packtpub.com/product/learn-quantum-computing-with-python-and-ibm-quantum-experience/9781838981006?utm_source=github&utm_medium=repository&utm_campaign=9781838981006) [[Amazon]](https://www.amazon.com/dp/1838981004)
56 |
57 | ## Get to Know the Author
58 | **Srinjoy Ganguly**
59 | Srinjoy Ganguly is the founder and CEO of AdroitERA, an EdTech firm, and possesses a Master's in quantum computing technology from the Technical University of Madrid, and a Master's in artificial intelligence from the University of Southampton. He has over 4 years' experience in quantum computing and 5 years' experience in machine learning and deep learning. He currently leads the Quantum Machine Learning (QML) study space at QWorld. He has given an expert talk on QML at IEEE SPS. His research interests include QML, Quantum Image Processing, Quantum Natural Language Processing (QNLP), machine learning, and deep learning.
60 |
61 | **Thomas Cambier**
62 | Thomas Cambier is a French programmer and software developer. After studying top-level mathematics, physics, and computer science at Ecole Polytechnique, France's leading engineering school, he obtained a Master's degree in computer science at ETH Zürich on a broad range of subjects going from algorithmics and cryptography to object-oriented programming. Deeply interested in the promising possibilities resulting from quantum computing, he wrote his Master's thesis on the design of quantum algorithms with Silq, a brand-new high-level quantum language created by a research group at ETH Zürich.
63 |
64 | ### Download a free PDF
65 |
66 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
67 |