《尘世之外》

第三卷-职场沉浮 · 第 062 章

第六十二章 遗传算法

屏幕上的数字一行行往上翻。黑底绿字。迭代信息跑得很快,眼睛跟不上,只能看到数字在变——从大到小,从快到慢,像河里的水位从汛期落回枯水期。

第1500代:适应度 721.4
第1600代:适应度 712.8
第1700代:适应度 706.3
第1800代:适应度 701.9

适应度在降。降意味着成本在降——每一代淘汰一批差的管径组合,保留一批好的。好的再交叉,再变异,产生更好的。一代一代,像河水冲沙——沙被冲走了,金子留下来。

十一月的哈尔滨已经很冷了。实验室的暖气管在墙角嘶嘶响——水蒸气在管道里走的声音,和主程序里水在管网里走是一回事。暖气把室内顶到了二十度,窗玻璃上结了一层冰花——六角形的,从窗框边缘往中间长,长到一半停住了,中间剩下一圈透明的玻璃,能看到外面黑的天。

程序是上个月开始写的。GA_pipe_v2.0.c。第二版和第一版的区别在于加了精英保留——每代适应度前五的个体不参与交叉和变异,直接进入下一代。像给最好的种子留一块不受打扰的田,让它们原封不动地活到下一季。第一版没有精英保留,最优秀的个体也会被交叉打乱、被变异改写——好东西留不住。加了保留之后收敛速度快了将近一倍。

键盘敲了一天。代码从八百行涨到一千五百行。变量名越来越长——population_size、crossover_rate、mutation_rate、elite_count。函数越分越细——select()、crossover()、mutate()、evaluate()、evolve()。主干函数evolve()里面一个while循环,循环条件是generation < MAX_GEN。每次循环做五件事:选择、交叉、变异、评价、淘汰。做完一代,generation加一,再来。两千代。三千代。四千代。直到收敛。

键盘上的空格键被敲得最亮——循环体里的缩进全靠空格,一层缩进四个空格,嵌套三层就是十二个空格。空格键的漆磨没了,露出底下的白色塑料。


中午去食堂打饭。糖醋里脊、土豆丝、米饭。端着餐盘回到实验室,放在键盘旁边——餐盘的边磕到了回车键,屏幕上弹出一行"Continue? (Y/N)"。按了Y。程序继续跑。

扒了两口饭。里脊肉外面挂的糊太厚了,咬开里面是粉色的——没炸透。土豆丝切得粗细不匀,粗的像筷子,细的像牙签。嚼着嚼着看屏幕。

第2000代:适应度 698.7

六百九十八。比一千五百代的时候降了二十三点七。降速在放缓——像一条河从山里冲出来,刚出山的时候落差大,流速猛;到了平原落差小了,流速慢了,开始打弯。前五百代适应度从两千多直接砸到一千以下,那是大山里的河——陡、急、冲力大。现在两千代了,从七百零几磨到六百九十八,六代才降不到两个点——那是平原上的河,懒洋洋地走,每走一步只低了半个公分。

但还在降。程序还在学。学得很慢了——像一个人在黄昏的院子里一圈圈踱步,每走一圈步子都一样,但他还在走。


下午钱老师来了。

钱老师五十多岁,瘦,戴一副厚眼镜——镜片厚得像瓶底,看人的时候眼睛在镜片后面缩小了,像隔着两层水看鱼。他走路没声音——橡胶底的布鞋踩在实验室的水泥地上,不响。他什么时候进来的我不知道——直到他站在我背后说了一句话。

"第几代了?"

我转过头。他看着屏幕,没看我。

"两千三百代。适应度六百八十三。"

"收敛了?"

"快了。两百代降不到一个点。"

他把手背在身后,站了五秒。实验室里只有电脑风扇嗡嗡响和暖气管嘶嘶响。他站起来的时候膝盖咔嚓响了一下——年纪大了,关节里的软骨磨薄了,骨头碰骨头就响。和管道用久了内壁结垢是一个道理——时间长了,垢比管壁厚,关节里的软骨比骨头薄。

"你那遗传算法,三个算子——选择、交叉、变异——是怎么想的?"

"照着自然选择写的。选择保留好的,交叉产生新的,变异防止早熟。"

"嗯。"他推了推眼镜。镜片反光,看不到他的眼。"做研究是为了找问题。不是找答案。"

他没解释这句话。他说完就走了——橡胶底的布鞋踩在水泥地上,不响。门关上了。实验室里又只剩电脑风扇和暖气管的声音。

做研究是为了找问题。我在心里把这句话翻来覆去嚼了两遍——像嚼那块没炸透的里脊肉,嚼不烂,咽不下去。找答案是从A走到B,A是问题,B是答案。找问题是从A走到另一个A——原来以为答案是B,走到B发现B也是问题。


晚上九点。实验室只剩我。

程序跑到了第2800代。适应度672.1。我盯着屏幕上的数字看——672.1。这个数字的意思是:在这个管网的拓扑结构下,在给定的水压约束和流速约束下,用遗传算法搜索了两千八百代之后,找到的最低建造成本是六百七十二万一千。

程序不知道六百七十二万是什么概念。程序不知道六百七十二万能买多少吨铸铁管、能请多少个管工、能挖多少米基坑。程序只知道数字——数字大就是差,数字小就是好。选择淘汰大的,保留小的,一代一代,数字越来越小。

我想起赵启明说过的"有效市场假说"。他说市场会不断定价,错的人付钱,对的人留下来。那和我屏幕上的淘汰、保留、再组合有一点相似,但也只是相似。管网不会害怕,市场里的人会。

选择。交叉。变异。

这三个词在屏幕上很冷,冷得像实验室的灯。

我把椅子往后推了推。椅子腿在水泥地上刮了一声。拿过笔记本,蓝色钢笔——笔帽裂了,缠了两圈透明胶——在空白页写了一行字:

自然选择。市场选择。最优路径?

写完看了三秒。问号后面没有答案。把笔记本合上,封面磕在桌面上,响了闷闷的一下。


门被推开了。风跟着灌进来——零下十几度的风,从门缝里挤进实验室,暖气管的热气被冲了一下,嘶嘶声大了一瞬又恢复原样。

王强站在门口,穿着那件军绿色棉大衣,领口一圈人造毛被风吹得立起来。他脸上冻红了——鼻尖最红,像抹了碘酒。他手里拎着两瓶哈尔滨啤酒——绿瓶的,瓶身上凝着水珠,水珠从瓶壁往下滑,滑到指缝里。

"在呢?"

"在。"

他走进来,把啤酒搁在我桌上。瓶底磕在桌面上,当的一声。他看了一眼屏幕——黑底绿字,数字还在翻。

"这一堆数字是啥?"

"管网优化。遗传算法。"

"啥意思?"

"用程序找最便宜的管径组合。比手算快。"

"比手算快吗?"

"快。手算一个方案要三天,程序两千八百代只要四十分钟。"

"那有用。"

他说完就开啤酒。启子没带,用牙咬的——瓶盖磕在桌沿上,当的一声弹开了,啤酒沫从瓶口冒出来,他拿嘴堵上去喝了一口。沫顺着嘴角淌下来,他用袖子擦了擦。

"你那修车铺怎么样?"

"还行。冬天车容易打不着火,电瓶换得多。"

"赚了没?"

"够吃。"

他把另一瓶推给我。我拿起来——瓶身是凉的,但没有铸铁管那么凉。玻璃的凉比铁的凉软,手指握上去玻璃会把温度慢慢接过来,不像铁那样猛吸。我喝了一口。啤酒很凉,从嗓子一路凉到胃里,胃缩了一下,又松开了。

王强拉了把椅子坐下——椅子是他自己从隔壁搬的,搬的时候椅腿在地板上刮出两道白印。他坐下来的姿势还是那个姿势——两腿分开,胳膊搁在膝盖上,手垂在两腿中间。修车的人坐下来都是这个姿势——随时准备站起来弯腰。他的手也变了——指节比大学时候粗了一圈,指甲缝里嵌着洗不掉的黑——那是机油,渗进皮肤纹路里,用肥皂搓三遍也只是淡了,没干净过。

他看着屏幕。屏幕上数字还在翻。

第2900代:适应度 671.4
第3000代:适应度 670.8

"还在算?"

"还在。快停了。"

"停了以后呢?"

"出一个方案。交给设计院。"

他点了点头。没再问。他不懂算法,但他懂"有用"——比手算快就是有用。修车也是:能修就是有用,不能修就是没用。简单。

啤酒喝完他把瓶子放在脚边。站起来的时候膝盖也咔嚓响了一声——和钱老师一样。二十三岁的膝盖不应该响。但修车的人蹲多了,蹲久了软骨也磨。

"走了。明天还有车。"

"嗯。"

他走到门口停了一下,回头看了屏幕最后一眼。数字还在翻。

"你这东西——"他想了想,"能修管子吗?"

"能算。不能修。"

"那还是人修。"他笑了一声,推门走了。

门关上了。实验室里又只剩电脑风扇和暖气管的声音。屏幕上数字继续翻。

第3100代:适应度 670.2

程序还在学。六百七十。比两千代的时候降了二十八个点。收敛了——曲线平得像平原上的河。程序找到了它的最优解。但它不知道为什么那是最优的——它只是按照规则走,走完了。

我看着屏幕上的670.2,想起了钱老师的话。做研究是为了找问题。最优解找到了——但最优解本身是一个新的问题:这个最优是对的还是错的?约束条件够不够?有没有更优的?程序停了,问题没停。

关掉显示器。屏幕黑了。程序在后台继续跑——也许跑到五千代会再降零点几个点,也许不会。但让它跑着。跑着总比停着好。

窗外的风在号。十一月的哈尔滨,夜里零下十五度。白杨树只剩黑枝,枝丫在路灯下投出交错的影子——像一张管网图从天上掉下来铺在雪地上。