Skip to content

Commit b8eb6f0

Browse files
committed
added demo applyTrotterizedPauliNoisyTimeEvolution
though it is unsure this should be the final interface; we can also accept jump operators given as projectors and diagonal matrices without much greater complexity, and SHOULD also deal with exponentiating general dense matrices. This commit also includes a Trotter patch we'll commit separately to dev for publicity
1 parent 5cf77b5 commit b8eb6f0

File tree

3 files changed

+144
-29
lines changed

3 files changed

+144
-29
lines changed

quest/include/trotterisation.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,13 +320,19 @@ extern "C" {
320320
/// @notyettested
321321
/// @notyetvalidated
322322
/// @notyetdoced
323-
void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamiltonian, qreal time, int order, int reps);
323+
void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps);
324324

325325

326326
/// @notyettested
327327
/// @notyetvalidated
328328
/// @notyetdoced
329-
void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamiltonian, qreal tau, int order, int reps);
329+
void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps);
330+
331+
332+
/// @notyettested
333+
/// @notyetvalidated
334+
/// @notyetdoced
335+
void applyTrotterizedPauliNoisyTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal* damps, PauliStr* jumps, int numJumps, qreal time, int order, int reps);
330336

331337

332338
// end de-mangler

quest/src/api/trotterisation.cpp

Lines changed: 128 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ extern PauliStr paulis_getShiftedPauliStr(PauliStr str, int pauliShift);
2929

3030
void internal_applyFirstOrderTrotterRepetition(
3131
Qureg qureg, vector<int>& ketCtrls, vector<int>& braCtrls,
32-
vector<int>& states, PauliStrSum sum, qcomp angle, bool reverse
32+
vector<int>& states, PauliStrSum sum, qcomp angle, bool postmultiply, bool reverse
3333
) {
3434
// apply each sum term as a gadget, in forward or reverse order
3535
for (qindex i=0; i<sum.numTerms; i++) {
@@ -41,9 +41,14 @@ void internal_applyFirstOrderTrotterRepetition(
4141
qcomp arg = angle * coeff;
4242
localiser_statevec_anyCtrlPauliGadget(qureg, ketCtrls, states, str, arg);
4343

44+
// term finished upon statevector
4445
if (!qureg.isDensityMatrix)
4546
continue;
4647

48+
// Linbladian propagator is only ever pre-multiplied
49+
if (!postmultiply)
50+
continue;
51+
4752
// effect rho -> rho dagger(i angle * sum)
4853
arg *= paulis_hasOddNumY(str) ? 1 : -1;
4954
str = paulis_getShiftedPauliStr(str, qureg.numQubits);
@@ -53,32 +58,32 @@ void internal_applyFirstOrderTrotterRepetition(
5358

5459
void internal_applyHigherOrderTrotterRepetition(
5560
Qureg qureg, vector<int>& ketCtrls, vector<int>& braCtrls,
56-
vector<int>& states, PauliStrSum sum, qcomp angle, int order
61+
vector<int>& states, PauliStrSum sum, qcomp angle, int order, bool postmultiply
5762
) {
5863
if (order == 1) {
59-
internal_applyFirstOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, angle, false);
64+
internal_applyFirstOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, angle, postmultiply, false);
6065

6166
} else if (order == 2) {
62-
internal_applyFirstOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, angle/2, false);
63-
internal_applyFirstOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, angle/2, true);
67+
internal_applyFirstOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, angle/2, postmultiply, false);
68+
internal_applyFirstOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, angle/2, postmultiply, true);
6469

6570
} else {
6671
qreal p = 1. / (4 - std::pow(4, 1./(order-1)));
6772
qcomp a = p * angle;
6873
qcomp b = (1-4*p) * angle;
6974

7075
int lower = order - 2;
71-
internal_applyFirstOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, a, lower);
72-
internal_applyFirstOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, a, lower);
73-
internal_applyFirstOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, b, lower);
74-
internal_applyFirstOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, a, lower);
75-
internal_applyFirstOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, a, lower);
76+
internal_applyHigherOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, a, lower, postmultiply); // angle -> a
77+
internal_applyHigherOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, a, lower, postmultiply);
78+
internal_applyHigherOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, b, lower, postmultiply); // angle -> b
79+
internal_applyHigherOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, a, lower, postmultiply);
80+
internal_applyHigherOrderTrotterRepetition(qureg, ketCtrls, braCtrls, states, sum, a, lower, postmultiply);
7681
}
7782
}
7883

7984
void internal_applyAllTrotterRepetitions(
8085
Qureg qureg, int* controls, int* states, int numControls,
81-
PauliStrSum sum, qcomp angle, int order, int reps
86+
PauliStrSum sum, qcomp angle, int order, int reps, bool postmultiply
8287
) {
8388
// exp(i angle sum) = identity when angle=0
8489
if (angle == qcomp(0,0))
@@ -94,7 +99,7 @@ void internal_applyAllTrotterRepetitions(
9499
// perform carefully-ordered sequence of gadgets
95100
for (int r=0; r<reps; r++)
96101
internal_applyHigherOrderTrotterRepetition(
97-
qureg, ketCtrlsVec, braCtrlsVec, statesVec, sum, arg, order);
102+
qureg, ketCtrlsVec, braCtrlsVec, statesVec, sum, arg, order, postmultiply);
98103

99104
/// @todo
100105
/// the accuracy of Trotterisation is greatly improved by randomisation
@@ -117,7 +122,8 @@ void applyNonUnitaryTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, q
117122
validate_trotterParams(qureg, order, reps, __func__);
118123
// sum is permitted to be non-Hermitian
119124

120-
internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps);
125+
bool postmultiply = true;
126+
internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps, postmultiply);
121127
}
122128

123129
void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps) {
@@ -127,7 +133,8 @@ void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle
127133
validate_pauliStrSumIsHermitian(sum, __func__);
128134
validate_trotterParams(qureg, order, reps, __func__);
129135

130-
internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps);
136+
bool postmultiply = true;
137+
internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps, postmultiply);
131138
}
132139

133140
void applyControlledTrotterizedPauliStrSumGadget(Qureg qureg, int control, PauliStrSum sum, qreal angle, int order, int reps) {
@@ -137,7 +144,8 @@ void applyControlledTrotterizedPauliStrSumGadget(Qureg qureg, int control, Pauli
137144
validate_controlAndPauliStrSumTargets(qureg, control, sum, __func__);
138145
validate_trotterParams(qureg, order, reps, __func__);
139146

140-
internal_applyAllTrotterRepetitions(qureg, &control, nullptr, 1, sum, angle, order, reps);
147+
bool postmultiply = true;
148+
internal_applyAllTrotterRepetitions(qureg, &control, nullptr, 1, sum, angle, order, reps, postmultiply);
141149
}
142150

143151
void applyMultiControlledTrotterizedPauliStrSumGadget(Qureg qureg, int* controls, int numControls, PauliStrSum sum, qreal angle, int order, int reps) {
@@ -147,7 +155,8 @@ void applyMultiControlledTrotterizedPauliStrSumGadget(Qureg qureg, int* controls
147155
validate_controlsAndPauliStrSumTargets(qureg, controls, numControls, sum, __func__);
148156
validate_trotterParams(qureg, order, reps, __func__);
149157

150-
internal_applyAllTrotterRepetitions(qureg, controls, nullptr, numControls, sum, angle, order, reps);
158+
bool postmultiply = true;
159+
internal_applyAllTrotterRepetitions(qureg, controls, nullptr, numControls, sum, angle, order, reps, postmultiply);
151160
}
152161

153162
void applyMultiStateControlledTrotterizedPauliStrSumGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, qreal angle, int order, int reps) {
@@ -158,7 +167,8 @@ void applyMultiStateControlledTrotterizedPauliStrSumGadget(Qureg qureg, int* con
158167
validate_controlStates(states, numControls, __func__); // permits states==nullptr
159168
validate_trotterParams(qureg, order, reps, __func__);
160169

161-
internal_applyAllTrotterRepetitions(qureg, controls, states, numControls, sum, angle, order, reps);
170+
bool postmultiply = true;
171+
internal_applyAllTrotterRepetitions(qureg, controls, states, numControls, sum, angle, order, reps, postmultiply);
162172
}
163173

164174
} // end de-mangler
@@ -180,25 +190,116 @@ void applyMultiStateControlledTrotterizedPauliStrSumGadget(Qureg qureg, vector<i
180190
* CLOSED TIME EVOLUTION
181191
*/
182192

183-
void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamiltonian, qreal time, int order, int reps) {
193+
void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps) {
184194
validate_quregFields(qureg, __func__);
185-
validate_pauliStrSumFields(hamiltonian, __func__);
186-
validate_pauliStrSumTargets(hamiltonian, qureg, __func__);
187-
validate_pauliStrSumIsHermitian(hamiltonian, __func__);
195+
validate_pauliStrSumFields(hamil, __func__);
196+
validate_pauliStrSumTargets(hamil, qureg, __func__);
197+
validate_pauliStrSumIsHermitian(hamil, __func__);
188198
validate_trotterParams(qureg, order, reps, __func__);
189199

190200
// exp(-i t H) = exp(x i H) | x=-t
191-
qreal angle = - time;
192-
internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, hamiltonian, angle, order, reps);
201+
qcomp angle = - time;
202+
bool postmultiply = true;
203+
internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, hamil, angle, order, reps, postmultiply);
193204
}
194205

195-
void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamiltonian, qreal tau, int order, int reps) {
206+
void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps) {
196207
validate_quregFields(qureg, __func__);
197-
validate_pauliStrSumFields(hamiltonian, __func__);
198-
validate_pauliStrSumTargets(hamiltonian, qureg, __func__);
208+
validate_pauliStrSumFields(hamil, __func__);
209+
validate_pauliStrSumTargets(hamil, qureg, __func__);
199210
validate_trotterParams(qureg, order, reps, __func__);
200211

201212
// exp(-tau H) = exp(x i H) | x=tau*i
202213
qcomp angle = qcomp(0, tau);
203-
internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, hamiltonian, angle, order, reps);
214+
bool postmultiply = true;
215+
internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, hamil, angle, order, reps, postmultiply);
216+
}
217+
218+
219+
220+
/*
221+
* OPEN TIME EVOLUTION
222+
*/
223+
224+
extern PauliStr paulis_getShiftedPauliStr(PauliStr str, int pauliShift);
225+
extern PauliStr paulis_getKetAndBraPauliStr(PauliStr str, Qureg qureg);
226+
227+
extern "C" {
228+
229+
void applyTrotterizedPauliNoisyTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal* damps, PauliStr* jumps, int numJumps, qreal time, int order, int reps) {
230+
validate_quregFields(qureg, __func__);
231+
validate_quregIsDensityMatrix(qureg, __func__);
232+
validate_pauliStrSumFields(hamil, __func__);
233+
validate_pauliStrSumTargets(hamil, qureg, __func__);
234+
validate_pauliStrSumIsHermitian(hamil, __func__);
235+
validate_trotterParams(qureg, order, reps, __func__);
236+
237+
// TODO: validate numJumps
238+
239+
// TODO; validate damps (looped); must be non-negative (0 legally disables one)
240+
241+
for (int n=0; n<numJumps; n++)
242+
validate_pauliStrTargets(qureg, jumps[n], __func__);
243+
244+
// when all jump operators are Paulis, the linblad superop simplifies to:
245+
// L = -i (Id (x) H - conj(H) (x) I) + sum_k gamma_k conj(L_k) (x) L_k - (sum_k gamma_k) Id
246+
// where the final term commutes with everything and can just be brought out the front of
247+
// the Trotter circuit; it becomes just a final scalar factor upon the state.
248+
//
249+
// So we need merely prepare a new PauliStrSum which contains
250+
// - old hamil times -i
251+
// - conj and shifted hamil times -i
252+
// - gamma_k conj(L_k) (x) L_k = +- gamma_k L_k (x) L_k depending on L_k Y parity
253+
// then after effecting that, scale the state
254+
255+
vector<PauliStr> newStrings;
256+
vector<qcomp> newCoeffs;
257+
258+
// premature optimisation
259+
qindex numNewTerms = 2 * hamil.numTerms + numJumps;
260+
newStrings.reserve(numNewTerms);
261+
newCoeffs.reserve(numNewTerms);
262+
263+
// collect -i[H,rho] terms
264+
for (qindex n=0; n<hamil.numTerms; n++) {
265+
PauliStr oldStr = hamil.strings[n];
266+
qcomp oldCoeff = hamil.coeffs[n];
267+
268+
// term of -i Id (x) H
269+
newStrings.push_back(oldStr);
270+
newCoeffs.push_back(-1_i * oldCoeff);
271+
272+
// term of i conj(H) (x) I
273+
newStrings.push_back(paulis_getShiftedPauliStr(oldStr, qureg.numQubits));
274+
newCoeffs.push_back(1_i * (paulis_hasOddNumY(oldStr) ? -1 : 1) * std::conj(oldCoeff));
275+
}
276+
277+
// collect jump terms
278+
for (int n=0; n<numJumps; n++) {
279+
280+
// gamma_k conj(L_k) (x) L_k
281+
newStrings.push_back(paulis_getKetAndBraPauliStr(jumps[n], qureg));
282+
newCoeffs.push_back(damps[n] * (paulis_hasOddNumY(jumps[n]) ? -1 : 1));
283+
}
284+
285+
// spoof a PauliStrSum to avoid superfluous alloc
286+
PauliStrSum temp;
287+
temp.numTerms = numNewTerms;
288+
temp.strings = newStrings.data();
289+
temp.coeffs = newCoeffs.data();
290+
temp.isApproxHermitian = nullptr; // will not be queried
291+
292+
// effect exp(t S) = exp(x i S) | x=-i*time, premultiplying only
293+
qcomp angle = qcomp(0, -time);
294+
bool postmultiply = false;
295+
internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, temp, angle, order, reps, postmultiply);
296+
297+
// scale by exp(- time sum_k gamma_k)
298+
qreal dampSum = 0;
299+
for (int n=0; n<numJumps; n++)
300+
dampSum += damps[n];
301+
qcomp fac = std::exp(- time * dampSum);
302+
localiser_statevec_setQuregToSuperposition(fac, qureg, 0, qureg, 0, qureg);
303+
}
304+
204305
}

tests/unit/trotterisation.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,11 @@ void applyControlledTrotterizedPauliStrSumGadget(Qureg qureg, int control, Pauli
3434
void applyMultiControlledTrotterizedPauliStrSumGadget(Qureg qureg, int* controls, int numControls, PauliStrSum sum, qreal angle, int order, int reps);
3535

3636
void applyMultiStateControlledTrotterizedPauliStrSumGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, qreal angle, int order, int reps);
37+
38+
void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps);
39+
40+
void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps);
41+
42+
43+
// TODO: just a draft function
44+
void applyTrotterizedPauliNoisyTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal* damps, PauliStr* jumps, int numJumps, qreal time, int order, int reps);

0 commit comments

Comments
 (0)