Skip to content

Commit 2ebdb41

Browse files
authored
Merge branch 'dev' into add_tests
2 parents 5202bb7 + 8dbe25c commit 2ebdb41

32 files changed

+4067
-503
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ repos:
1616
additional_dependencies: [cma==3.0.3,
1717
numpy==1.19.5,
1818
scipy==1.5.2,
19-
tensorflow==2.4.1,
19+
tensorflow==2.4.2,
2020
tensorflow-probability==0.12.1,
2121
tensorflow-estimator==2.4.0
2222
]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# C3 - An integrated tool-set for Control, Calibration and Characterization
22

3-
[![codecov](https://codecov.io/gh/q-optimize/c3/branch/master/graph/badge.svg)](https://codecov.io/gh/q-optimize/c3)
3+
[![codecov](https://codecov.io/gh/q-optimize/c3/branch/dev/graph/badge.svg)](https://codecov.io/gh/q-optimize/c3)
44
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/q-optimize/c3.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/q-optimize/c3/context:python)
55
<a href="https://codeclimate.com/github/q-optimize/c3/maintainability"><img src="https://api.codeclimate.com/v1/badges/a090831b106f863dc223/maintainability" /></a>
66
[![Documentation Status](https://readthedocs.org/projects/c3-toolset/badge/?version=latest)](https://c3-toolset.readthedocs.io/en/latest/?badge=latest)

c3/experiment.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@
2424
from c3.signal.gates import Instruction
2525
from c3.model import Model
2626
from c3.utils.tf_utils import (
27-
tf_batch_propagate,
28-
tf_propagation_lind,
2927
tf_matmul_left,
3028
tf_state_to_dm,
3129
tf_super,
3230
tf_vec_to_dm,
3331
)
32+
33+
from c3.libraries.propagation import (
34+
tf_batch_propagate,
35+
tf_propagation_lind,
36+
)
3437
from c3.utils.qt_utils import perfect_single_q_parametric_gate
3538

3639

@@ -325,7 +328,7 @@ def process(self, populations, labels=None):
325328
populations_final = []
326329
populations_no_rescale = []
327330
for pops in populations:
328-
# TODO: Loop over all tasks in a general fashion
331+
# TODO: Loop over all model.tasks in a general fashion
329332
# TODO: Selecting states by label in the case of computational space
330333
if "conf_matrix" in model.tasks:
331334
pops = model.tasks["conf_matrix"].confuse(pops)

c3/libraries/fidelities.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@
1919
tf_average_fidelity,
2020
tf_superoper_average_fidelity,
2121
tf_state_to_dm,
22+
)
23+
24+
from c3.libraries.propagation import (
2225
evaluate_sequences,
2326
)
27+
2428
from c3.utils.qt_utils import (
2529
basis,
2630
perfect_cliffords,

c3/libraries/propagation.py

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
"A library for propagators and closely related functions"
2+
3+
import tensorflow as tf
4+
from c3.utils.tf_utils import (
5+
tf_kron_batch,
6+
tf_matmul_left,
7+
tf_spre,
8+
tf_spost,
9+
)
10+
11+
12+
@tf.function
13+
def tf_dU_of_t(h0, hks, cflds_t, dt):
14+
"""
15+
Compute H(t) = H_0 + sum_k c_k H_k and matrix exponential exp(i H(t) dt).
16+
17+
Parameters
18+
----------
19+
h0 : tf.tensor
20+
Drift Hamiltonian.
21+
hks : list of tf.tensor
22+
List of control Hamiltonians.
23+
cflds_t : array of tf.float
24+
Vector of control field values at time t.
25+
dt : float
26+
Length of one time slice.
27+
28+
Returns
29+
-------
30+
tf.tensor
31+
dU = exp(-i H(t) dt)
32+
33+
"""
34+
h = h0
35+
ii = 0
36+
while ii < len(hks):
37+
h += cflds_t[ii] * hks[ii]
38+
ii += 1
39+
# terms = int(1e12 * dt) + 2
40+
# dU = tf_expm(-1j * h * dt, terms)
41+
# TODO Make an option for the exponentation method
42+
dU = tf.linalg.expm(-1j * h * dt)
43+
return dU
44+
45+
46+
# @tf.function
47+
def tf_dU_of_t_lind(h0, hks, col_ops, cflds_t, dt):
48+
"""
49+
Compute the Lindbladian and it's matrix exponential exp(L(t) dt).
50+
51+
Parameters
52+
----------
53+
h0 : tf.tensor
54+
Drift Hamiltonian.
55+
hks : list of tf.tensor
56+
List of control Hamiltonians.
57+
col_ops : list of tf.tensor
58+
List of collapse operators.
59+
cflds_t : array of tf.float
60+
Vector of control field values at time t.
61+
dt : float
62+
Length of one time slice.
63+
64+
Returns
65+
-------
66+
tf.tensor
67+
dU = exp(L(t) dt)
68+
69+
"""
70+
h = h0
71+
for ii in range(len(hks)):
72+
h += cflds_t[ii] * hks[ii]
73+
lind_op = -1j * (tf_spre(h) - tf_spost(h))
74+
for col_op in col_ops:
75+
super_clp = tf.matmul(tf_spre(col_op), tf_spost(tf.linalg.adjoint(col_op)))
76+
anticomm_L_clp = 0.5 * tf.matmul(
77+
tf_spre(tf.linalg.adjoint(col_op)), tf_spre(col_op)
78+
)
79+
anticomm_R_clp = 0.5 * tf.matmul(
80+
tf_spost(col_op), tf_spost(tf.linalg.adjoint(col_op))
81+
)
82+
lind_op = lind_op + super_clp - anticomm_L_clp - anticomm_R_clp
83+
# terms = int(1e12 * dt) # Eyeball number of terms in expm
84+
# print('terms in exponential: ', terms)
85+
# dU = tf_expm(lind_op * dt, terms)
86+
# Built-in tensorflow exponential below
87+
dU = tf.linalg.expm(lind_op * dt)
88+
return dU
89+
90+
91+
@tf.function
92+
def tf_propagation_vectorized(h0, hks, cflds_t, dt):
93+
dt = tf.cast(dt, dtype=tf.complex128)
94+
if hks is not None and cflds_t is not None:
95+
cflds_t = tf.cast(cflds_t, dtype=tf.complex128)
96+
hks = tf.cast(hks, dtype=tf.complex128)
97+
cflds = tf.expand_dims(tf.expand_dims(cflds_t, 2), 3)
98+
hks = tf.expand_dims(hks, 1)
99+
if len(h0.shape) < 3:
100+
h0 = tf.expand_dims(h0, 0)
101+
prod = cflds * hks
102+
h = h0 + tf.reduce_sum(prod, axis=0)
103+
else:
104+
h = tf.cast(h0, tf.complex128)
105+
dh = -1.0j * h * dt
106+
return tf.linalg.expm(dh)
107+
108+
109+
def tf_batch_propagate(hamiltonian, hks, signals, dt, batch_size):
110+
"""
111+
Propagate signal in batches
112+
Parameters
113+
----------
114+
hamiltonian: tf.tensor
115+
Drift Hamiltonian
116+
hks: Union[tf.tensor, List[tf.tensor]]
117+
List of control hamiltonians
118+
signals: Union[tf.tensor, List[tf.tensor]]
119+
List of control signals, one per control hamiltonian
120+
dt: float
121+
Length of one time slice
122+
batch_size: int
123+
Number of elements in one batch
124+
125+
Returns
126+
-------
127+
128+
"""
129+
if signals is not None:
130+
batches = int(tf.math.ceil(signals.shape[0] / batch_size))
131+
batch_array = tf.TensorArray(
132+
signals.dtype, size=batches, dynamic_size=False, infer_shape=False
133+
)
134+
for i in range(batches):
135+
batch_array = batch_array.write(
136+
i, signals[i * batch_size : i * batch_size + batch_size]
137+
)
138+
else:
139+
batches = int(tf.math.ceil(hamiltonian.shape[0] / batch_size))
140+
batch_array = tf.TensorArray(
141+
hamiltonian.dtype, size=batches, dynamic_size=False, infer_shape=False
142+
)
143+
for i in range(batches):
144+
batch_array = batch_array.write(
145+
i, hamiltonian[i * batch_size : i * batch_size + batch_size]
146+
)
147+
148+
dUs_array = tf.TensorArray(tf.complex128, size=batches, infer_shape=False)
149+
for i in range(batches):
150+
x = batch_array.read(i)
151+
if signals is not None:
152+
result = tf_propagation_vectorized(hamiltonian, hks, x, dt)
153+
else:
154+
result = tf_propagation_vectorized(x, None, None, dt)
155+
dUs_array = dUs_array.write(i, result)
156+
return dUs_array.concat()
157+
158+
159+
def tf_propagation(h0, hks, cflds, dt):
160+
"""
161+
Calculate the unitary time evolution of a system controlled by time-dependent
162+
fields.
163+
164+
Parameters
165+
----------
166+
h0 : tf.tensor
167+
Drift Hamiltonian.
168+
hks : list of tf.tensor
169+
List of control Hamiltonians.
170+
cflds : list
171+
List of control fields, one per control Hamiltonian.
172+
dt : float
173+
Length of one time slice.
174+
175+
Returns
176+
-------
177+
list
178+
List of incremental propagators dU.
179+
180+
"""
181+
dUs = []
182+
183+
for ii in range(cflds[0].shape[0]):
184+
cf_t = []
185+
for fields in cflds:
186+
cf_t.append(tf.cast(fields[ii], tf.complex128))
187+
dUs.append(tf_dU_of_t(h0, hks, cf_t, dt))
188+
return dUs
189+
190+
191+
@tf.function
192+
def tf_propagation_lind(h0, hks, col_ops, cflds_t, dt, history=False):
193+
col_ops = tf.cast(col_ops, dtype=tf.complex128)
194+
dt = tf.cast(dt, dtype=tf.complex128)
195+
if hks is not None and cflds_t is not None:
196+
cflds_t = tf.cast(cflds_t, dtype=tf.complex128)
197+
hks = tf.cast(hks, dtype=tf.complex128)
198+
cflds = tf.expand_dims(tf.expand_dims(cflds_t, 2), 3)
199+
hks = tf.expand_dims(hks, 1)
200+
h0 = tf.expand_dims(h0, 0)
201+
prod = cflds * hks
202+
h = h0 + tf.reduce_sum(prod, axis=0)
203+
else:
204+
h = h0
205+
206+
h_id = tf.eye(h.shape[-1], batch_shape=[h.shape[0]], dtype=tf.complex128)
207+
l_s = tf_kron_batch(h, h_id)
208+
r_s = tf_kron_batch(h_id, tf.linalg.matrix_transpose(h))
209+
lind_op = -1j * (l_s - r_s)
210+
211+
col_ops_id = tf.eye(
212+
col_ops.shape[-1], batch_shape=[col_ops.shape[0]], dtype=tf.complex128
213+
)
214+
l_col_ops = tf_kron_batch(col_ops, col_ops_id)
215+
r_col_ops = tf_kron_batch(col_ops_id, tf.linalg.matrix_transpose(col_ops))
216+
217+
super_clp = tf.matmul(l_col_ops, r_col_ops, adjoint_b=True)
218+
anticom_L_clp = 0.5 * tf.matmul(l_col_ops, l_col_ops, adjoint_a=True)
219+
anticom_R_clp = 0.5 * tf.matmul(r_col_ops, r_col_ops, adjoint_b=True)
220+
clp = tf.expand_dims(
221+
tf.reduce_sum(super_clp - anticom_L_clp - anticom_R_clp, axis=0), 0
222+
)
223+
lind_op += clp
224+
225+
dU = tf.linalg.expm(lind_op * dt)
226+
return dU
227+
228+
229+
def evaluate_sequences(propagators: dict, sequences: list):
230+
"""
231+
Compute the total propagator of a sequence of gates.
232+
233+
Parameters
234+
----------
235+
propagators : dict
236+
Dictionary of unitary representation of gates.
237+
238+
sequences : list
239+
List of keys from propagators specifying a gate sequence.
240+
The sequence is multiplied from the left, i.e.
241+
sequence = [U0, U1, U2, ...]
242+
is applied as
243+
... U2 * U1 * U0
244+
245+
Returns
246+
-------
247+
tf.tensor
248+
Propagator of the sequence.
249+
250+
"""
251+
gates = propagators
252+
# get dims to deal with the case where a sequence is empty
253+
dim = list(gates.values())[0].shape[0]
254+
dtype = list(gates.values())[0].dtype
255+
# TODO deal with the case where you only evaluate one sequence
256+
U = []
257+
for sequence in sequences:
258+
if len(sequence) == 0:
259+
U.append(tf.linalg.eye(dim, dtype=dtype))
260+
else:
261+
Us = []
262+
for gate in sequence:
263+
Us.append(gates[gate])
264+
265+
Us = tf.cast(Us, tf.complex128)
266+
U.append(tf_matmul_left(Us))
267+
# ### WARNING WARNING ^^ look there, it says left WARNING
268+
return U
269+
270+
271+
def tf_expm(A, terms):
272+
"""
273+
Matrix exponential by the series method.
274+
275+
Parameters
276+
----------
277+
A : tf.tensor
278+
Matrix to be exponentiated.
279+
terms : int
280+
Number of terms in the series.
281+
282+
Returns
283+
-------
284+
tf.tensor
285+
expm(A)
286+
287+
"""
288+
r = tf.eye(int(A.shape[-1]), batch_shape=A.shape[:-2], dtype=A.dtype)
289+
A_powers = A
290+
r += A
291+
292+
for ii in range(2, terms):
293+
A_powers = tf.matmul(A_powers, A) / tf.cast(ii, tf.complex128)
294+
ii += 1
295+
r += A_powers
296+
return r
297+
298+
299+
def tf_expm_dynamic(A, acc=1e-5):
300+
"""
301+
Matrix exponential by the series method with specified accuracy.
302+
303+
Parameters
304+
----------
305+
A : tf.tensor
306+
Matrix to be exponentiated.
307+
acc : float
308+
Accuracy. Stop when the maximum matrix entry reaches
309+
310+
Returns
311+
-------
312+
tf.tensor
313+
expm(A)
314+
315+
"""
316+
r = tf.eye(int(A.shape[0]), dtype=A.dtype)
317+
A_powers = A
318+
r += A
319+
320+
ii = tf.constant(2, dtype=tf.complex128)
321+
while tf.reduce_max(tf.abs(A_powers)) > acc:
322+
A_powers = tf.matmul(A_powers, A) / ii
323+
ii += 1
324+
r += A_powers
325+
return r

0 commit comments

Comments
 (0)