仓库源文站点原文


layout: post title: 关于分子动力学模拟的可重复性 categories:


前些日子有些关于MD模拟可重复性的讨论, 这里随记一下我的观点想法以及看到的资料, 供参考.

无论讨论什么问题, 首先要做的就是给出问题的定义和范围, 界定一些概念的含义, 达到共识. 如果定义范围不明确, 苹果对桔子, 没有什么讨论的必要. 有些问题之所以无法深入探讨, 其原因就在于无法明确定义, 各以自己的定义为是, 鸡同鸭讲, 自然谁也说服不了谁, 最后只能不了了之. 这种情况在社会科学中尤甚, 自然科学中情况好些, 数学中则做得最好, 所以各种学科都要向数学学习.

哲学和自然科学中一直以来就有决定论(或称确定论)的观点. 广为人知的是拉普拉斯妖的说法. 这种基于经典力学的决定论, 后来受到了很大的质疑, 其中有些来自混沌理论, 有些源自量子力学, 有些则与热力学和统计力学有关.

对于混沌系统, 需要明确的是, 根据定义, 系统是确定性的, 但由于初值敏感性, 所以并不能在现实中表现出确定性; 对于量子力学, 一般认为其本质上是非确定性的, 因为只存在概率描述, 但同时也存在确定性说法, 相关翻译中测不准原理和不确定原理两种说法, 就是这两种观点的反映. 从微观角度而言, 世界本质上是确定性的, 只是表现出随机性, 抑或相反, 这是一个很深刻的问题. 再深入下去就进入了哲学的范畴, 不是科学所能解决的了, 暂且只能存而不论.

让我们不要讨论那么宽泛的问题, 关注具体而微的问题, 也就是计算机程序的确定性问题. 在这里我们暂且假定确定性包含了可重复性: 一份程序具有确定性, 那么在初始条件相同的情况下, 运行任意多次总会给出相同的运行结果, 从而具有可重复性. 反之, 则未必成立. 数学上可说确定性为可重复性的充分条件.

从计算机理论科学的角度而言, 在图灵机上运行的计算机程序和数学理论一样, 毫无疑问地具有确定性(只考虑实际的算法). 但我们毕竟没有生活在理论的完美世界(类似哲学上柏拉图的理念世界)中, 而是生活在现实世界中(虽然我们无法确定现实世界是否只是完美世界的模仿). 理论中作为计算机模型的图灵机具有无限精度, 无限存储, 完全不受外界影响, 是个孤立体系, 但现实中实际运行的计算机只是对图灵机的一种近似, 既没有无限精度, 也没有无限存储, 还要与外界交互. 从这一点上来看, 如果承认现实世界本质上具有非确定性, 那么现实世界中的一切都具有本质上的非确定性, 计算机也不例外, 它的确定性只是表象, 我们无法证明它所具有的确定性在任何时候都成立. 计算机在多年来的发展中一直向着更高的确定性逼近, 但从理论上而言, 只要处于现实中, 永远也不可能达到完美的确定性.

可以设想, 如果我们需要现实的计算机运行具有确定性, 那基本不可能. 在程序运行结束后, 如果查看内存中的数据, 它们是不是确定性的? 这很难, 因为在程序执行过程中, CPU等硬件会有很多操作, 每次操作具体如何实现, 涉及哪些部分都不是我们完全能控制的. 那好, 我们不使用高级语言, 而是使用汇编语言直接操控内存和寄存器等, 这下结果应该具有确定性了吧. 很遗憾, 只要涉及与现实交互, 总有你无法控制的地方. 你能控制对内存, 寄存器的操作, 可你能控制电压电流么? 电压电流不同, 对结果的影响如何? 你能控制电压电流, 那你能控制电子么? 电子在芯片线路中的运动, 是经典的还是量子的, 会随着环境温度的不同而不同么? 即便你能让计算机运行在绝对零度, 那你能控制太阳么? 太阳黑子爆发也会对电子运行产生影响. 你能控制太阳系, 那你能控制宇宙射线么? 高能宇宙射线中的粒子可能会导致内存中的bit位发生翻转. 如果这样细究下去, 最终你需要控制整个宇宙才能保证计算机运行的确定性, 而你所用的计算机也就一步一步趋近于作为理论模型的图灵机. 所以我们只能说, 完全的确定性只是理论上的, 现实中并不存在. 即便你一生写过的程序都具有确定性, 那相对于无限的时空, 其概率也只是零, 不能用以证明确定性的问题.

这样看来, 我们需要降低标准, 要求程序的运行结果具有确定性, 其输出文件具有二进制的可重复性, 虽然将每次运行的结果输出到文件, 会涉及计算机的基本输入输出系统, 过程中也存在很多不可控的因素, 我们暂且忽略它们.

那么, 让我们将目光放得更低些, 不讨论具有哲学意味的确定性问题, 而是考虑更具体现实的问题: 实际运行的计算机程序具有一定的确定性, 其结果也具有一定的可重复性, 这些可重复性受哪些可控因素的影响, 如何尽可能地使运行结果具有可重复性? 这是一个实际的问题, 也是在计算机发展初期颇受关注的一个问题, 有很多相应的讨论. 毕竟, 要想使用计算机处理实际问题, 那么首先必须保证它给出的结果具有尽可能高的可重复性, 即便所给结果是错的, 那也要每次都错得完全一样才好, 否则, 你该相信哪次的结果呢? 这就像有一个处于封闭屋子中的人, 你给他一块表, 他知道是什么时间, 如果你再给他一块走时不同的表, 他反而不知道到底是什么时间了.

对现实的计算机而言, 由于精度和存储有限, 在实数计算中采用的表示模型不同, 得到的结果也会不同. 现在大部分实数计算都采用浮点数IEEE 754标准, 这个标准的一个重要方面就是要保证计算结果的可重复性, 尽量减少截断误差和舍入误差的影响.

由于浮点数的表示精度有限, 导致的一个问题就是加法不具有可交换性, 在计算机中a+b=b+a并不总是成立的. 因而, 在进行累加时, 如果无法确切地规定累加顺序, 那很可能会得到不同的结果. 编译程序时, 编译器一般会对各种操作进行优化和向量化, 这常会改变累加顺序, 从而导致结果不同. 如果使用了并行, 就更难保证累加顺序了. 在GPU上, 核心数非常多, 且可以同时运行, 很难保证累加顺序, 因此这个问题更严重.

浮点数精度有限导致的另一个问题是舍入误差, 这个问题现在影响不大了, 但也很难说完全解决了.

如果想更多地了解浮点数计算以及可重复性方面的问题, 可以看看几篇资料:

关于程序的可重复性, 游戏领域的相关讨论更多些, 因为具有现实意义. 大型的在线游戏会有很多用户在玩, 每个用户都可能会随时退出, 过段时间再重新上线. 要记录每个用户退出时的精确状态是很困难的, 会涉及大量的参数. 那么当用户退出时, 能不能只记录几个重要的初始参数, 等他重新登录时, 先虚拟运行一遍, 得到他退出时的状态以便继续呢? 这就要求精确地还原状态, 否则可能会导致完全不同的结果. 举个极端的例子, 射出来一颗子弹, 在未击中敌人之前, 敌人下线了, 你认为击中了, 对方认为没击中, 这两种不同的结果可能会导致十分不同的后果, 差之毫厘, 谬以千里, 就像西方那首歌谣中说的:

少了一枚铁钉, 掉了一只马掌; 掉了一只马掌, 瘸了一匹战马; 瘸了一匹战马, 败了一次战役; 败了一次战役, 丢了一个国家.

目前看来, 这种课重复性还是可以做到的, 虽然代价不小. 具体可以参考一下程序员的经验.

如果你同意上面的一些说法, 那就容易理解为什么MD程序无法保证可重复性了. 毕竟, 比起计算速度, 可重复性在MD模拟方面并没有那么重要.

那么, 不可重复就一定是错的么? 倒也不能这么说, 因为可重复性并不是可靠性的唯一保证. 毕竟, 实际的实验结果也无法做到每次都得到完全相同的数据. 与其相比, 计算机程序的可重复性还要高不少. 我们需要关注的是结果的不确定性是不是可控的, 能否满足我们的要求. 但实际上, 对于处于混沌的系统而言, 这也是无法做到的, 为此, 我们只能希望自己的体系没有处于混沌区域.

关于MD可重复性的另外一个观点是影子理论, 我没有去查证它的具体来源和说法了, 大致而言, 有点像是柏拉图的理念世界和洞穴假象. 我们认为体系实际存在真实的演化轨迹, 具有确定性, 但这条轨迹处于理念世界(相空间)中,无法被我们直接感知, 我们每次的模拟结果只是它在现实世界的投影, 我们只能根据这些投影推断理念轨迹的性质. 我们得到的每条轨迹可能无法确定是否真实, 但我们仍然认为它模仿了真实轨迹(假定存在真实轨迹的话), 是真实轨迹的影子, 我们无法区分真实和影子, 但认为它们是存在对应关系的. 实际上, 我倒认为这是科学, 唯物主义必须承认的前提, 像是康德所谓的物自体, 存在是第一位的, 如果连其存在都未必承认, 像佛家那样, 那就没有必要继续探究下去了. 到这里已经触碰到了科学的边界, 再继续下去就是哲学, 神学的领域里, 打住吧.

上面是随便想想, 随口说的, 没什么条理, 姑妄言之, 姑妄听之. 下面我们来具体地做些实际测试.