《尘世之外》

第二卷-大学时代 · 第 053 章

第五十三章 毕业设计

凌晨两点的实验室只有日光灯的嗡嗡声。

日光灯管在天花板上挂着两根——两根的频率差了零点几赫兹,光线每隔几秒就闪一下极细微的暗,不是灭,是暗那么零点零几秒。人眼几乎看不到,但电脑屏幕的边框在灯管暗的那一瞬间会亮一点——像在补那一瞬间的光。

我在写毕业设计。

"基于图论的给水管网优化设计"——十二个字打在论文封面上,宋体三号字,加粗。标题下面是"哈尔滨工业大学"五个字,小一号,不加粗。再下面是我的名字——林之宇——两个字摊在正中间,和两边留白的距离差不多,像管网的一个中间节点,上游连着学校、下游连着答辩委员会。

论文技术路线画了一张流程图:管网拓扑→节点编码→初始种群→适应度计算→选择→交叉→变异→新一代种群→收敛判断→输出最优方案。箭头的方向只有一个——从上到下,从问题到答案。

但程序从第一行到第三千行,没有箭头——只有缩进、循环、条件分支和函数调用。


程序从两百行变成了三千行。

两百行的时候还是Dijkstra算法——输入管网拓扑和节点权重,输出从起点到终点的最短路径。像在地图上找路:把所有路走一遍,留下最短的那条。两百行代码写了一个星期,跑了一次五分钟出结果。结果是对的——最短的路径和手算的一样。

但Dijkstra只能找最短路径。给水管网不是只找最短路径——它要找最优管径组合,每组管径对应不同的造价和水压损失,管径粗了造价高但水压够,管径细了造价低但水压不够。最优解不是最短路径——是造价和水压之间的平衡。一棵树可以有很多种走法,但只有一种走法让每片叶子都得到足够的水,同时造价最省。

两百行变五百行的时候加了遗传算法。遗传算法是从自然选择里学来的——把管网的所有管径组合变成一个"种群",每个组合是一个"个体",每个个体的"适应度"是造价和水压的综合评分。适应度高的个体留下,适应度低的淘汰。留下的个体之间进行"交叉"——两套管径组合各取一部分拼成新组合。再加"变异"——随机改变某一条管段的管径,看看会不会出现更优的解。

交叉的时候程序从父体I取前半截管径、从父体II取后半截管径,拼在一起变成子代。像两条管段在一个三通处对接——父体I的水从左边来,父体II的水从右边来,子代把两边的水接在一起从下面走。

变异的时候程序随机选中一条管段,把DN150改成DN200——像管网上某一段突然换了一根更粗的管子,水流从头到尾重新分配了。

五百行变一千行的时候加了约束条件——最大流速不超三米每秒,最小服务水头不低于二十八米,管径只能选标准规格。约束像阀门——水压太高了关小,水压太低了开大。

一千行变两千行的时候加了用户界面——输入表格、结果显示、管网图形输出。界面不算好看,但在屏幕上能跑——输入参数在左边,运行结果在右边,中间是程序运行的进度条,绿色的,一格一格往右走,像管道里的水从一个节点流到下一个节点。

两千行变三千行的时候加了收敛判据——当连续十代最优解的差值小于千分之一时程序自动停止迭代,把最终方案输出到文件。收敛——这个词在数学里是序列趋向极限,在程序里是数字趋向最优。写到那里,我第一次觉得,一个词放到不同地方,会露出不同的侧面。


王强推门进来的时候是晚上十点半。

他在校门外面的小修车铺干了一天活。出门的时候穿的是工服——蓝色的,袖口和前襟有一层洗不掉的机油渍。他的手指甲缝里是黑的——机油和铁锈的混合物用肥皂洗三次才能洗淡,但洗不干净,指甲缝里的黑要长出新的指甲才会掉。他的手比大三的时候粗糙了——指关节的骨头变大了,手掌的茧从掌心蔓延到了指根,像管道里的水垢越长越厚。

"你这是什么?"他走到电脑前面看了一眼——屏幕上绿色的进度条正在一格一格地走。

"管网优化程序。"

"能修车吗?"

"不能。"

"那没用。"他说没用的时候嘴角往上歪了一下——不是笑,是嘴部肌肉的一种习惯性收缩,像他拧螺丝时嘴唇动了一下帮手使劲。但那个歪让"没用"两个字变轻了——不是真的没用,是他说了没用就走了。他的脚底在实验室的水泥地上踩出湿润的印子——外面下雪了,他的鞋底带着雪水进来,每一步都是一个湿脚印,走了六步之后在椅腿旁边停住。

他坐下来看我跑了十分钟程序。进度条走了四分之一。绿色的光一格一格地填,像水从一个节点慢慢流到下一个节点。

"一千八百块。"他没头没脑说了一句。

"什么?"

"月薪。修车铺开的。"他翻了一下口袋——口袋里有两把螺丝刀、一卷生料带和半包烟。他把烟掏出来,没点,在手指间转了两圈又塞回去了。

"管吃住。刨去吃住能剩八九百。"他掰着手指头算,食指和中指交替点了两下,像在数管道的节点编号。"比你们写代码挣得多吧?"

程序跑完了。屏幕上跳出一行白字:**迭代收敛。最优方案已输出。** 最优方案的总造价比手算的低百分之七点三,水压余量比手算的高了零点五米。

"你这个跑一晚上?"他指着屏幕上的结果。

"快了。明天应该出结果。"

他站起来,拍了拍裤腿上的铁屑——铁屑是从修车铺带来的,蓝色的工服上沾了一层银灰色的粉末,拍了两下没拍干净,还是银灰色的。"走了。明天早班。"

他走的时候门没关严,实验室的灯从门缝里漏出去一条线,光线打在走廊的水泥地上,窄窄的一条,像管道截面图上的管壁线。


林小月是十一点四十进来的。

她带了两个泡面桶——红烧牛肉面,她的是香辣海鲜。两桶泡面在实验室的暖气管上放了两分钟等水烧开——暖气管在十一月的哈尔滨已经开始供热了,铁管烫得不敢摸,水壶放在旁边三分钟水就温了。她把暖气管上烘热的水壶拿下来倒水,热水冲进泡面桶的时候面饼被水冲得蜷了一下又伸开,调料包的红色在水面上散成一片薄薄的油花。

"你的管网优化跑了一晚上?"她坐在我旁边的折叠椅上,椅子腿在水泥地上卡嗒一声——折叠椅年久失修,坐下去的时候要歪一下才能稳住。

"快了。明天应该出结果。"

"明天答辩还是后天?"

"后天。"

她"哦"了一声,没接话。低头吃面——筷子挑起面条的时候热气从碗口往上飘,飘到她刘海的末端凝成了小水珠,她在小水珠上吹了一口气,水珠就散了。

实验室只有暖气管的咕噜声和两个人吃面的声音。

她吃完了面,把泡面桶放在暖气管旁边。她拿出自己的毕业论文初稿——"市政道路排水系统设计",A4纸,边角用回形针别着。

"我的初稿写完了。你帮我看一下第三章的暴雨强度公式有没有算错。"

暴雨强度公式。q=167A1(1+ClgP)/(t+b)^n——她写在稿纸上的公式字母写得工整,数学符号的间距和赵启明在论文上的一样均匀。我接过来看了一遍。公式没问题。参数取值没问题。计算过程没问题。我递回去的时候在第三章最后一页的空白处写了一行字:"没问题。"

她把初稿收回去,站起身的时候折叠椅又卡嗒一声收回去——金属腿在水泥地上蹭了一声,像踩到小石子。她走到门口回头看了一眼我的屏幕——进度条还在走。绿色的光一格一格地走,走到大半了。

"明天我来看结果。"

门关上了。脚步声在走廊里远了。她的鞋底是软胶的,走在水泥地上没有声音——只有暖气管的咕噜声在走廊里回响,像很远很远的地方有人在敲一根很长很长的管子。


凌晨三点。

屏幕上的迭代已经收敛了。收敛图是一条从高处往低处走的曲线——第一代到第五代降得快,第六代到第十五代降得慢了,第十六代到第二十三代几乎平了。最优解从四十七万三千降到四十三万九千——降了百分之七点三。

八十块。最后一代只降了八十块——在四十三万九千的总额里,八十块是一个几乎看不到的数字。但程序没有放过这八十块——它把所有管径组合翻了一遍,找到只省八十块的那一组变化,把它留下来。八十块是这一代比上一代多省下来的——像管道最后一段的压降只有零点零几米,很小,但如果没有这零点零几米,末梢的水龙头就差那么一点水压。

最优方案在屏幕上打印出来了。十二个节点,三根干管,五根支管——和三年前在孙工旁边画的管网一样。但管径不同了:孙工凭经验选的DN200在这里变成了DN150+DN250的组合——细的更细、粗的更粗,水压分配更合理。造价低了百分之七点三。水压余量高了零点五米。

三千行代码在凌晨三点吐出了一个结果。结果安静地停在屏幕上,绿色的光从CRT显示器里照出来,把我的脸照成一片淡绿色的底色。日光灯还在嗡嗡响。暖气管还在咕噜走水。走廊里有老鼠在暖气管的缝隙里跑过去了——爪子在铁皮上嗒嗒嗒嗒,跑得很快,像程序里的一行代码从开头跑到结尾。

我关了电脑。屏幕上的绿色一行一行地暗下去,像管网的节点一个一个地关灯。最后也是最亮的那一行——最优方案——在屏幕中间闪了两下才灭。

灭了屏幕是黑的。日光灯还是白的。暖气管还是热的。

实验室外面的天开始有一点亮了——不是天亮,是天要亮之前的灰。灰从窗户的边缘往里渗,像管网的压降从源头往末梢渗,到了末梢只剩一点了。

我在笔记本最后一页写了一行数字:439087。总造价。

这个数字安静地躺在笔记本的白纸上。数字和数字之间的空白是迭代的过程——交叉、变异、选择、淘汰——每一代都比上一代省一点点,直到最后一代只省了八十块。

八十块是一顿泡面的钱。王强能修两辆车的钱。陈默在东莞一天的工资。

我把笔记本合上。赵启明送的蓝色钢笔放在桌面上——四年了,笔帽上的"方向对了"四个字已经摩挲得只剩一条浅槽。后天答辩。答辩完了就是毕业了。