microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1365fba5cb78ce29bb89f92fea9c0419a3a85a14

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

samples/estimation/Dynamics.qs

172lines · modecode

1/// # Sample
2/// Quantum Dynamics
3///
4/// # Description
5/// This example demonstrates quantum dynamics in a style tailored for
6/// resource estimation. The sample is specifically the simulation
7/// of an Ising model Hamiltonian on an N1xN2 2D lattice using a
8/// fourth-order Trotter Suzuki product formula, assuming
9/// a 2D qubit architecture with nearest-neighbor connectivity.
10/// The is an example of a program that is not amenable to simulating
11/// classically, but can be run through resource estimation to determine
12/// what size of quantum system would be needed to solve the problem.
13
14import Std.Math.*;
15import Std.Arrays.*;
16
17operation Main() : Unit {
18 // n : Int, m : Int, t: Double, u : Double, tstep : Double
19
20 let n = 10;
21 let m = 10;
22
23 let J = 1.0;
24 let g = 1.0;
25
26 let totTime = 30.0;
27 let dt = 0.9;
28
29 IsingModel2DSim(n, m, J, g, totTime, dt);
30}
31
32/// # Summary
33/// The function below creates a sequence containing the rotation angles that will be applied with the two operators used in the expansion of the Trotter-Suzuki formula.
34/// # Input
35/// ## p (Double) : Constant used for fourth-order formulas
36///
37/// ## dt (Double) : Time-step used to compute rotation angles
38///
39/// ## J (Double) : coefficient for 2-qubit interactions
40///
41/// ## g (Double) : coefficient for transverse field
42///
43/// # Output
44/// ## values (Double[]) : The list of rotation angles to be applies in sequence with the corresponding operators
45///
46function SetAngleSequence(p : Double, dt : Double, J : Double, g : Double) : Double[] {
47
48 let len1 = 3;
49 let len2 = 3;
50 let valLength = 2 * len1 + len2 + 1;
51 mutable values = [0.0, size = valLength];
52
53 let val1 = J * p * dt;
54 let val2 = -g * p * dt;
55 let val3 = J * (1.0 - 3.0 * p) * dt / 2.0;
56 let val4 = g * (1.0 - 4.0 * p) * dt / 2.0;
57
58 for i in 0..len1 {
59
60 if (i % 2 == 0) {
61 set values w/= i <- val1;
62 } else {
63 set values w/= i <- val2;
64 }
65
66 }
67
68 for i in len1 + 1..len1 + len2 {
69 if (i % 2 == 0) {
70 set values w/= i <- val3;
71 } else {
72 set values w/= i <- val4;
73 }
74 }
75
76 for i in len1 + len2 + 1..valLength - 1 {
77 if (i % 2 == 0) {
78 set values w/= i <- val1;
79 } else {
80 set values w/= i <- val2;
81 }
82 }
83 return values;
84}
85
86/// # Summary
87/// Applies e^-iX(theta) on all qubits in the 2D lattice as part of simulating the transverse field in the Ising model
88/// # Input
89/// ## n (Int) : Lattice size for an n x n lattice
90///
91/// ## qArr (Qubit[][]) : Array of qubits representing the lattice
92///
93/// ## theta (Double) : The angle/time-step for which the unitary simulation is done.
94///
95operation ApplyAllX(n : Int, qArr : Qubit[][], theta : Double) : Unit {
96 // This applies `Rx` with an angle of `2.0 * theta` to all qubits in `qs`
97 // using partial application
98 for row in 0..n - 1 {
99 ApplyToEach(Rx(2.0 * theta, _), qArr[row]);
100 }
101}
102
103/// # Summary
104/// Applies e^-iP(theta) where P = Z o Z as part of the repulsion terms.
105/// # Input
106/// ## n, m (Int, Int) : Lattice sizes for an n x m lattice
107///
108/// ## qArr (Qubit[]) : Array of qubits representing the lattice
109///
110/// ## theta (Double) : The angle/time-step for which unitary simulation is done.
111///
112/// ## dir (Bool) : Direction is true for vertical direction.
113///
114/// ## grp (Bool) : Group is true for odd starting indices
115///
116operation ApplyDoubleZ(n : Int, m : Int, qArr : Qubit[][], theta : Double, dir : Bool, grp : Bool) : Unit {
117 let start = grp ? 1 | 0; // Choose either odd or even indices based on group number
118 let P_op = [PauliZ, PauliZ];
119 let c_end = dir ? m - 1 | m - 2;
120 let r_end = dir ? m - 2 | m - 1;
121
122 for row in 0..r_end {
123 for col in start..2..c_end {
124 // Iterate through even or odd columns based on `grp`
125
126 let row2 = dir ? row + 1 | row;
127 let col2 = dir ? col | col + 1;
128
129 Exp(P_op, theta, [qArr[row][col], qArr[row2][col2]]);
130 }
131 }
132}
133
134/// # Summary
135/// The main function that takes in various parameters and calls the operations needed to simulate fourth order Trotterizatiuon of the Ising Hamiltonian for a given time-step
136/// # Input
137/// ## N1, N2 (Int, Int) : Lattice sizes for an N1 x N2 lattice
138///
139/// ## J (Double) : coefficient for 2-qubit interactions
140///
141/// ## g (Double) : coefficient for transverse field
142///
143/// ## totTime (Double) : The total time-step for which unitary simulation is done.
144///
145/// ## dt (Double) : The time the simulation is done for each timestep
146///
147operation IsingModel2DSim(N1 : Int, N2 : Int, J : Double, g : Double, totTime : Double, dt : Double) : Unit {
148
149 use qs = Qubit[N1 * N2];
150 let qubitArray = Chunks(N2, qs); // qubits are re-arranged to be in an N1 x N2 array
151
152 let p = 1.0 / (4.0 - 4.0^(1.0 / 3.0));
153 let t = Ceiling(totTime / dt);
154
155 let seqLen = 10 * t + 1;
156
157 let angSeq = SetAngleSequence(p, dt, J, g);
158
159 for i in 0..seqLen - 1 {
160 let theta = (i == 0 or i == seqLen - 1) ? J * p * dt / 2.0 | angSeq[i % 10];
161
162 // for even indexes
163 if i % 2 == 0 {
164 ApplyAllX(N1, qubitArray, theta);
165 } else {
166 // iterate through all possible combinations for `dir` and `grp`.
167 for (dir, grp) in [(true, true), (true, false), (false, true), (false, false)] {
168 ApplyDoubleZ(N1, N2, qubitArray, theta, dir, grp);
169 }
170 }
171 }
172}
173