microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.1.3

Branches

Tags

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

Clone

HTTPS

Download ZIP

samples/estimation/Dynamics.qs

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