保存QuTiP对象和数据集

在进行耗时的计算时,通常需要将结果存储到磁盘上的文件中,以便进行后处理和存档。在QuTiP中,有两种存储数据的工具:量子对象可以存储到文件中,并稍后作为python pickle读回,而数值数据(向量和矩阵)可以导出为纯文本文件,例如CSV(逗号分隔值)、TSV(制表符分隔值)等。前者在需要对数据进行进一步计算时是首选方法,而后者在计算完成并需要将数据导入后处理工具(例如生成图表)时使用。

存储和加载QuTiP对象

为了存储和加载任意的QuTiP相关对象(Qobj, Result, 等),有两个函数:qutip.fileio.qsavequtip.fileio.qload。函数 qutip.fileio.qsave 以任意对象作为第一个参数,并以可选的文件名作为第二个参数(默认文件名为 qutip_data.qu)。文件扩展名始终为 .qu。函数 qutip.fileio.qload 以必需的文件名作为第一个参数,加载并返回文件中的对象。

为了说明如何使用这些函数,考虑一个简单的谐波振荡器稳态计算

>>> a = destroy(10); H = a.dag() * a
>>> c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.dag()]
>>> rho_ss = steadystate(H, c_ops)

稳态密度矩阵 rho_ssQobj 的一个实例。可以使用以下方法将其存储到文件 steadystate.qu 中。

>>> qsave(rho_ss, 'steadystate')
>>> !ls *.qu
density_matrix_vs_time.qu  steadystate.qu

并且它可以在以后再次加载,并用于进一步的计算

>>> rho_ss_loaded = qload('steadystate')
Loaded Qobj object:
Quantum object: dims = [[10], [10]], shape = (10, 10), type = oper, isHerm = True
>>> a = destroy(10)
>>> np.testing.assert_almost_equal(expect(a.dag() * a, rho_ss_loaded), 0.9902248289345061)

关于qutip.fileio.qsavequtip.fileio.qload函数的好处是,几乎任何对象都可以被存储并在以后再次加载。 例如,我们可以存储由mesolve返回的密度矩阵列表。

>>> a = destroy(10); H = a.dag() * a ; c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.dag()]
>>> psi0 = rand_ket(10)
>>> times = np.linspace(0, 10, 10)
>>> dm_list = mesolve(H, psi0, times, c_ops, [])
>>> qsave(dm_list, 'density_matrix_vs_time')

然后它可以被加载并再次使用,例如在另一个程序中

>>> dm_list_loaded = qload('density_matrix_vs_time')
Loaded Result object:
Result object with mesolve data.
--------------------------------
states = True
num_collapse = 0
>>> a = destroy(10)
>>> expect(a.dag() * a, dm_list_loaded.states) 
array([4.63317086, 3.59150315, 2.90590183, 2.41306641, 2.05120716,
   1.78312503, 1.58357995, 1.4346382 , 1.32327398, 1.23991233])

存储和加载数据集

qutip.fileio.qsavequtip.fileio.qload 非常棒,但使用的文件格式只能被 QuTiP(python)程序理解。当数据必须导出到其他程序时,首选方法是将数据存储为常用的纯文本文件格式。使用 QuTiP 函数 qutip.fileio.file_data_storequtip.fileio.file_data_read,我们可以使用分隔符分隔的值格式(例如逗号分隔值 CSV)将 numpy 数组和矩阵存储和加载到磁盘上的文件中。几乎任何程序都可以处理这种文件格式。

qutip.fileio.file_data_store 接受两个必需参数和三个可选参数:

>>> file_data_store(filename, data, numtype="complex", numformat="decimal", sep=",") 

其中 filename 是文件的名称,data 是要写入文件的数据(必须是一个 numpy 数组),numtype(可选)是一个标志,表示数值类型,可以取值为 complexrealnumformat(可选)指定数值格式,可以取值为 exp 表示格式 1.0e1decimal 表示格式 10.0sep(可选)是一个任意的单字符字段分隔符(通常是制表符、空格、逗号、分号等)。

qutip.fileio.file_data_store 函数的一个常见用途是存储一组算符在一系列时间点的期望值,例如由 mesolve 函数返回的值,这正是以下示例所做的

>>> a = destroy(10); H = a.dag() * a ; c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.dag()]
>>> psi0 = rand_ket(10)
>>> times = np.linspace(0, 100, 100)
>>> medata = mesolve(H, psi0, times, c_ops, e_ops=[a.dag() * a, a + a.dag(), -1j * (a - a.dag())])
>>> np.shape(medata.expect)
(3, 100)
>>> times.shape
(100,)
>>> output_data = np.vstack((times, medata.expect))   # join time and expt data
>>> file_data_store('expect.dat', output_data.T) # Note the .T for transpose!
>>> with open("expect.dat", "r") as f:
...    print('\n'.join(f.readlines()[:10]))
# Generated by QuTiP: 100x4 complex matrix in decimal format [',' separated values].
0.0000000000+0.0000000000j,3.2109553666+0.0000000000j,0.3689771549+0.0000000000j,0.0185002867+0.0000000000j
1.0101010101+0.0000000000j,2.6754598872+0.0000000000j,0.1298251132+0.0000000000j,-0.3303672956+0.0000000000j
2.0202020202+0.0000000000j,2.2743186810+0.0000000000j,-0.2106241300+0.0000000000j,-0.2623894277+0.0000000000j
3.0303030303+0.0000000000j,1.9726633457+0.0000000000j,-0.3037311621+0.0000000000j,0.0397330921+0.0000000000j
4.0404040404+0.0000000000j,1.7435892209+0.0000000000j,-0.1126550232+0.0000000000j,0.2497182058+0.0000000000j
5.0505050505+0.0000000000j,1.5687324121+0.0000000000j,0.1351622725+0.0000000000j,0.2018398581+0.0000000000j
6.0606060606+0.0000000000j,1.4348632045+0.0000000000j,0.2143080535+0.0000000000j,-0.0067820038+0.0000000000j
7.0707070707+0.0000000000j,1.3321818015+0.0000000000j,0.0950352763+0.0000000000j,-0.1630920429+0.0000000000j
8.0808080808+0.0000000000j,1.2533244850+0.0000000000j,-0.0771210981+0.0000000000j,-0.1468923919+0.0000000000j
../_images/guide-saving-1.png

在这种情况下,我们实际上不需要同时存储实部和虚部,因此我们可以使用numtype="real"选项

>>> file_data_store('expect.dat', output_data.T, numtype="real")
>>> with open("expect.dat", "r") as f:
...    print('\n'.join(f.readlines()[:5]))
# Generated by QuTiP: 100x4 real matrix in decimal format [',' separated values].
0.0000000000,3.2109553666,0.3689771549,0.0185002867
1.0101010101,2.6754598872,0.1298251132,-0.3303672956
2.0202020202,2.2743186810,-0.2106241300,-0.2623894277
3.0303030303,1.9726633457,-0.3037311621,0.0397330921
../_images/guide-saving-2.png

如果我们更喜欢科学记数法,我们可以使用numformat="exp"选项来请求

>>> file_data_store('expect.dat', output_data.T, numtype="real", numformat="exp")
../_images/guide-saving-3.png

加载之前使用qutip.fileio.file_data_store(或其他软件)存储的数据更加简单。无论使用了哪种分隔符,无论数据是以复数还是实数形式存储,无论是以十进制还是指数形式存储,都可以使用qutip.fileio.file_data_read加载数据,该函数只需要文件名作为必填参数。

input_data = file_data_read('expect.dat')
plt.plot(input_data[:,0], input_data[:,1]);  # plot the data
../_images/guide-saving-4.png

(如果使用了特别晦涩的分隔符,可能需要使用可选的第二个参数,例如 sep="_" 如果 _ 是分隔符)。