关于

这个项目始于2019年,当时我试图找到一种更好的方法来处理工作中各种恼人的数据项目。那时,我对在python中使用pandas和numpy,或者OOP之类的东西已经有点厌倦了。说实话,我很喜欢pandas,它就像我的朋友,陪伴我度过了整个大学生活。但突然有一天,我发现它再也没有任何闪光点了。它不再给我惊喜。剩下的只有熟悉感。

也是在那个时候,我的朋友Daniel来到我所在的城市看望我。Daniel是个很有创造力的人,他总是能给我带来很多好点子。我们甚至设计了一个蓝图,内容是如何用热力学中的模型来解释股票走势,这有点疯狂,我们都认为我们的父母或祖父母绝不会用这个来决定买哪只股票。

你应该和王教授谈谈这个问题,我敢肯定他会把你当成物理学院最可耻的异教徒来诅咒你。

这是Daniel告诉我的。王教授是我们大学最喜欢的教授,他认为我不应该转专业。我说也许他是对的,我真的受够了不断涌来的数据。

你还记得你在申请金融研究生学位时说过的话吗?

当然不记得了,那是很多年前的事了。

让我带你回忆一下,你说你玩够了神的游戏,想玩人类的游戏。现在人类的游戏你也玩够了?

不,我只是又开始相信神了。人类的游戏更糟糕。

在哪方面更糟糕?

每天都是同样的事情,价格、金额、数量……你用同样的方法处理它们,机器学习什么的,这里是矩阵,那里是矩阵,到处都是矩阵……

那为什么还要用矩阵?

它速度快,而且我们的计算机技术都是关于半导体晶格的,本质上就是矩阵。

听起来不像你会说的话,你什么时候开始考虑乱七八糟的限制了?我才是告诉你现实的限制在哪里的人,你应该是那个出馊主意的人。

你在开玩笑吗?树形或图形计算机从未发明过,你是说让我去发明一个么?确实有一个团队发明了水滴计算机,但速度太慢,没法用。

那就用软件来做?你还是用矩阵计算机,但你可以在软件中用树或图来做一些事情,然后自动转换成矩阵。

这就是这个故事的开始。

疯狂的想法

我很认真地对待这件事。在接下来的两周里,我和同事Yanki谈了很多关于应该使用哪种编程语言的问题。使用python中的类来生成树和图并不是我们的首选,因为它既慢又初级。我认为用C++的结构体框架会更好。Yanki坚持认为,核心不应该是运行速度有多快,而应该是你编写代码并不断迭代的速度有多快。他说,只要使用半导体计算机,图形计算就永远不可能像矩阵那样快,所以为什么不疯狂一点,一开始就放弃对速度的执着呢?

我和Yanki都知道,现在已经有很多图库,比如Python中的NetworkX或C++中的Boost Graph Library。它们和我想象中的不一样。在阅读了它们的文档后,我仍然有一个疑问: 这些库究竟是如何让数据处理变得更有趣的?你甚至无法轻松编写一个合适的函数来计算你想要的数据。它们更像是增强型图数据库,用于添加、删除、过滤、更改数据或应用某些图算法。它们适用于自然而然呈现图结构的数据,如人际关系等。我们想要的是可以用于任何数据,但通过图结构来处理数据的东西。

这两点构成了RiskQuantLib的基础:

通用性是第一位的,速度是最后一位的。

一个月后,我开始编写RiskQuantLib的第一行。0.0.1版本使用excel文件保存工具和工具列表的信息,使其看起来真的像一个玩具项目。为了加快编码速度,并让数据分析像我们期望的那样快乐,我们最终放弃了使用C++和SFINAE(替换失败不是错误),转而使用python和自省机制。Daniel也同意这样做,但他认为的原因是我们需要尽可能快地完成原型开发。

我们担心的一点是,在Python中使用类会让用户将RiskQuantLib视为一个OOP库,而这与它的本意相去甚远。但如果我们在其中添加太多新东西,我们担心它会像热力学中解释股票走势的那个模型一样,没有人理解或使用它。

你知道我们的项目在Github上有多少颗星星吗?

三颗,现在已经很棒了!

你知道我们有三个人参与这个项目,对吧?

放心,Daniel从来没有给我们的项目打星,说明我们还有一个粉丝。

如果你要自己创业,别忘了告诉我。我一定会做空你的公司。

谢谢,我会的。

跳舞的方式

我和Daniel仔细讨论过如何让我们的项目看起来不像是一个图形数据库。这引出了另一个问题: 我们应该用图结构来存储数据,还是用图结构来计算数据,像是计算图那样?如果采用前者,我们就会变成另一个图数据库;如果采用后者,我们就会变成另一个tensorflow。这陷入了死胡同。

幸运的是,就像Daniel说的,我总是我们中最疯狂的那个。

我们两者都做,用图保存数据,也用图进行计算。

这是不可能的。如果数据形成图,而所有计算又形成另一个计算图,你怎么能把它们结合起来并使其正常工作呢?

把数据想象成岛屿,它们之间的边就像桥梁,如果我们进行计算,就会用到一些数据,所以我们可以让函数穿过桥梁去一个岛屿,得到数据,然后再去另一个岛屿,直到得到所有的数据。

接着说?

所以,任何函数都应该像旅行者一样,从一个岛到另一个岛,你有没有想到什么?

柯尼斯堡七桥问题!

没错。这就是我们要做的。我们要把每次函数调用都变成哥尼斯堡七桥问题。

我还记得Daniel听到我的想法时的样子。他就像看到自己的奶奶拿着吸尘器与蜜獾搏斗。我继续说:

要做到这一点,任何函数都应该有记忆性,它应该从一个节点获取一个参数,记住它,然后变成一个新函数,进入下一个节点,以此类推。函数无论需要多少个参数,一次只能获取一个参数。

兄弟,你知道你在说什么吗?

什么?

你知道Curry吗?Haskell Curry?

没听说过。

你不是第一个想到这个方式的人,他在100年前就想到了。

我还没说完。这是一种方法,另一种方法是,我们可以站在一个岛上,向不同的岛屿派出信使,获取我们需要的数据,然后他们把数据带回来,进行计算,我们让另一个信使携带计算结果,送到我们想要存储这个结果的岛屿上。

这就是 applyexecFunctunneling index 的诞生过程。 apply 代表了第一种方式,而 execFunc 代表了第二种方式。当我处理数据时,我会想象自己与数据共舞,这应该是愉快而优雅的。这两种方式正是我梦想中与数据共舞的方式。它们让我明白了我真正需要的是什么:

数据一旦创建,就永远不能更改、移除、复制或删除。相同的数据绝不能出现两次。

调用函数的方式很重要。任何函数调用都应取决于数据图的访问顺序。

他山之石

不久之后,我开始阅读一些Haskell Curry的研究。我很惊讶竟然有一种语言是以他的名字命名的。而这门语言–Haskell,有很多地方都和我的想法不谋而合。在这里,我应该提到的一点是它处理异常的方式。我对此深表赞同:

任何异常都应该被视为Monad,通过数据管道传递,而不是导致程序中断。

这就是为什么你在运行RiskQuantLib项目时几乎看不到错误。这并不意味着你的程序是正确的,相反,在编码时需要更加谨慎。

另一个在RiskQuantLib中经常出现的东西是lambda函数,它就像Haskell一样,是让函数在节点中穿行所必须的设计。

Haskell的惰性机制给了我灵感,让我明白代码其实就是字符串,你并不需要在写下它们的时候立刻运行它们。我做了一个大胆的尝试,我想也许它们也并不一定是需要被手工编写的,我们可以用机器生成它们,然后将它们插入到我们想要的位置。

就这样,Src 组件文件夹诞生了。就像网络开发中的组件一样,我想我们可以在Python的数据分析项目中尝试一下。

2023年底,我们找到了在RiskQuantLib中使用多进程和矢量化的方法,使其速度更快。终于,速度不再是缺陷。这些工作的灵感来自于numpy、dask、joblib等。

接下来的计划

Daniel认为是时候放弃python,转而使用更基本的方式,他所说的是全新的解释器。他认为我们应该有自己的python解释器,让RiskQuantLib嵌入到CPython中。这无疑是一项艰巨的工作。

Yanki对我们现在拥有的东西很满意。他认为为RiskQuantLib添加用户界面,让用户看到自己正在做什么至关重要。为什么不呢,我也想要一个用户界面,如果它不是由我自己开发的话。

至于我,我总是有一些奇怪的想法。我打算买一台Meta Quest或Apple Vision或什么其他VR设备,在VR世界中制作一个集成开发环境IDE,然后嵌入RiskQuantLib。我想让用户看到并感受到他们是如何穿越桥梁、连接岛屿的。我希望分析数据就像在加利福尼亚观光旅游一样。我敢肯定,Yanki正在攒钱来做空我的公司,而我的公司永远不会成立。