🏠

琥珀里来的欧几里得:《几何原本》重绘篇

欧几里得正忙于撰写他的新书《几何原本》。他的文字写在纸莎草纸上,他的插图也画在纸莎草纸上。他有一把尺子。他有一幅圆规。

Euklid-von-Alexandria.png

Figure 1: 欧几里得(Euklid von Alexandria)

然而有一天,也是已入深秋,天气转凉的当口,他的老友斐洛( \( \Phi\iota\lambda\omega\nu \) )——一个精力过剩、对数学一窍不通、却热衷于“传播知识”的雅典船主——突然要求他必须以“电子形式”提交。欧几里得争辩说,电子技术要到数千年后才会被发现;但斐洛告诉他:

  1. 纸莎草纸早已不再是尖端科技,
  2. Till Tantau 和 Alain Matthes 两位大神已携 TikZ 与 tkz-euclide 御风而来。

Till_Tantau.jpg

Figure 2: Till Tantau,TikZ 的作者,德国吕贝克大学计算机科学教授。

TikZ 最初只是 Till Tantau 为自己的论文和课程绘图而写的工具,后来却成了 LaTeX 世界最流行的绘图宏包之一。Alain Matthes 则是 tkz-euclide 的作者,法国数学教师。他开发这个宏包,是为了让欧几里得几何作图的代码更贴近几何构造本身;用他的话说,它面向的是“以数学方式、甚至更好的是以几何方式思考的人”。两位作者背景不同,却共同支撑起从通用绘图到纯几何作图的工具链。

alain-matthes.png

Figure 3: Alain Matthes,tkz-euclide 的作者,法国数学教师。

欧几里得眼见二位大神不入凡尘,似乎远超古人,心想:我这公元前的上古老登也就知道摩擦琥珀能产生电子,难不成要把《几何原本》写到琥珀之上?他略微思索,缓缓转向 Till,说:

image-90.png

Figure 4: 《几何原本》的开篇命题——在给定线段上作等边三角形

“Till 大神,”欧几里得指着上图,“这是《几何原本》第一卷的第一个命题。我如何把它摹印到琥珀之上?”

不料 Till Tantau 大神一听,纳头便拜,口称:“欧老前辈!晚辈实在不敢当大神二字。欧氏几何的源头在您那儿,坐标思想来自笛老前辈,排版基础是高老前辈打造的 TeX ;我这个 TikZ 不过是雕虫小技,何足挂齿呢?”

Alain Matthes 也抢上前来,口中喃喃:“前辈, tkz-euclide 就是以您命名的呀——”

欧几里得眼见二位神色慌张、手足无措,对他们所行的礼节也不太明白,心想:第一,他们来自未来,这是条我必须承认的公理;第二,他们能回转时光,必然是《几何原本》的公理化思想传到了他们那里。那是传走了样么?还是他们没学会?抑或我问题的表述有误?转念又想,能用电子在琥珀上刻字、刻完还可任时光回转,无论人神,一定了得。于是伸手把二位搀扶起来,说:

“咱们都是数学家,一家人不说两家的话。数学家不仅要读懂宇宙的道,还要能写宇宙的道。我现在《几何原本》开篇的命题,在给定线段上作等边三角形,如何写到琥珀之上?知我所不知者,可为我师。二位老师如有所知还请明示。”

Till 拿出自己的笔记本电脑(Laptop),打开,屏幕亮起,后有毒智慧果(图灵咬过)透出琥珀的微光。欧几里得定睛观瞧,看这神器好似琥珀,怎么有大千宇宙集于微沙的气质呢?

Till 说:“欧老前辈,还请近前来,看我屏幕;不要只盯后面看”,打开 Emacs ,开启 org mode :“我要先画两个点,然后用蓝色的线把他们连起来。”

two-points.png

欧几里得眼见屏幕上出现两个点,一条蓝色线段连在它们之间。这本没有什么稀奇,两点连一线么。但见代码 \coordinate (A) at(0,0) 坐标概念甚是新奇。想必 A 是给坐标点起个名字,而 (0,0) 一个数值对表明点的位置!在一个平面上 (0,0) 可以表示一个点的位置吗?推而广之 (x,y) 可以表示平面上一个点的位置吗?看起来可以,但需要一个严格的证明。退一步, (x) 可以表示直线上一个点吗?可以!这在之前证明过。进一步, (x, y, z) 可以表示三维空间一个点吗?应该也是可以的,但缺少一个严格的证明——欧几里得神游物外,一道道闪电划过脑海,感觉 Till 真是天才:“ Till大神,你可真是天才呀,坐标的概念是我一辈子想不出的,感觉您参与了宇宙的构建——”

Till 哪敢当此?连忙说这坐标概念是笛卡尔笛老前辈的创造。当然,笛老前辈也是我们叫,他对您来说也是晚了几千年的后辈。既然说到这里,那我就把坐标以及坐标系的意思也画上面吧。

about-coordinate.png “您看图中的 x , y 轴,可以把它们理解为您有刻度的两把直尺,垂直放置。至于笛前辈怎么想到的坐标系,我就不知道了。” Till 接着说到,“您知道硅基生命只认识数,由坐标系的概念,我们可以把一切的图形表示为数——”

“硅基生命?”欧几里得不由打断,“是琥珀聚灵而生的生命形式吗?”

“不是。琥珀就我的理解是树脂吧?Alain, 是不是树脂?” Till 问。

“是吧,是树脂的化石,确切讲很多琥珀是松树的眼泪经年累月形成的化石。”

“那就是了,而硅基的生命由沙提炼,以硅为体,以电为食,以信息为血液的流动——”

欧几里得大脑电闪雷鸣,他坚韧地思想,深秋午后,太阳和暖普照亚历山大大地,我尽量平心静气,安于在公元前细细雕琢我的《几何原本》,如今这3000年的2 个后辈,带来坐标以及坐标系的思想,将我的几何转化为数字,喂与硅基的生命。他顽强地牢记这可是秋日的午后,公元前的秋日,和暖的阳光普照大地,如此才能平静脑中血液——我可是长寿之人呀,这是写在历史书里的,不可改变。于是压一下心潮,问关于笛卡尔的事情。

Till 说,笛卡尔也是神人哪,他曾说过,我思故我在。现在的硅基生命,正是基于这一点而存在。谁也不能否认硅基生命在思考,或者换一个说法,训练或推理,因此硅基生命是存在的。

这几句话对欧几里得无异于氢弹的爆发!他坚韧的思想逼迫他使劲摇了摇头,紧咬牙关心想不想这些有的没的了,凑近 Till屏幕看了看:

“这两点你写死了。可我的命题不关心它们在哪里——给定的线段就是给定的,任意画一条即可。你写死坐标,读者会以为这两个位置有什么特殊。”

Till 点点头:“你说得对。TikZ 里可以给坐标加一点扰动。”

\coordinate (A) at (0+0.1*rand,0+0.1*rand);
\coordinate (B) at (1.25+0.1*rand,0.25+0.1*rand);

“每次编译,A 和 B 都会随机挪动一点。每一次都是新的线段,读者就不能把任何位置当成理所当然。”

欧几里得愣了一下:“每编译一次,图就变一次?这倒有意思。但你能不能把‘主坐标’和‘扰动’分开?我想让读者看清楚,我指定的仍然是 (0,0) 和 (1.25,0.25) ,只是外面加了一点微扰。”

“可以。”Till 加载了 calc 库:

two-points-with-rand.png

欧几里得盯着看了一会儿,说:“ \$ ... \$ 这是做什么的?”

“这是 TikZ 的坐标运算语法。方括号里的两点,先按通常的坐标去理解,但外面这一对 \$ 告诉 TikZ :里面是算式,不是坐标。所以 \$ (0,0) + .1*(rand,rand) \$ 的意思就是‘点 (0,0) 加上一个随机小向量’。主坐标还是 (0,0) ,扰动是外面的 .1 倍随机数。”

欧几里得点头:“这样好。读者一眼能认出,AB 的‘骨架’是 (0,0) 到 (1.25,0.25),剩下的都是装饰。笛卡尔真是个聪明人,这坐标的思想,我一下子又想不出来。”晃晃脑袋,“为什么说 又 ?”

“还有一个细节。”Till 补充,“如果算式里有乘法,比如这里的 .1* ,星号要紧贴在左括号前面写,不能有空格。”

欧几里得陷入沉思,“未来的人聪明是肯定,但这空格的约定谁又一下子就知道呢?”,他想,“这么约定的合理性又在哪里呢?”

“现在,”Till 说,“以 A 为圆心、 AB 为半径画圆。”

欧几里得问:“半径是多少?”

“这正是麻烦的地方。 AB 是一条线段,它的长度需要用坐标算出来。”

first-circle.png

欧几里得看着这段代码,皱起眉头:“ let 是什么? \p1 又是什么?我的作法里,‘以 A 为圆心、 AB 为半径画圆’一句话就够了。”

Till 解释:“ let ... in ... 是 TikZ 里的临时赋值语法。 \$ (B) - (A) \$ 算出来的是从 A 指向 B 的向量, let 把它存到一个临时名字 \p1 里。然后 \x1 和 \y1 就是这个向量的横纵坐标。 veclen(\x1,\y1) 算出它的长度——也就是 AB 的长。”

“所以 veclen 是你的‘圆规’?”

“可以这么说。它做的是勾股定理。”

欧几里得盯着那段代码看了几秒,又看了一遍,然后说:“那我每画一个圆,都要把 AB 的长重算一遍?”

“不用,可以用另一个变量记下长度。” Till 重写,

two-circles.png

“这次我把长度存在 \n2 里。一条 let ,画两个圆。 \p1 是‘点’(point), \n2 是‘数’(number)。它们各有各的命名空间, \p1 和 \n1 互不干扰, \x1 和 \y1 绑在同一个点上。”

欧几里得若有所思:“所以你的意思是,‘数’和‘点’要分开存。这个思路倒也清楚。”

“其实还能更简单。”Till 说着加载了 through 库

circle-with-through.png

“ circle through=(B) 直接告诉 TikZ:‘画一个圆,过 B 点,圆心在我指定的位置上。’半径的计算 TikZ 自己在内部做了。”

欧几里得看着屏幕上这个圆,说:“这个写法,和我说的‘以 A 为圆心、 AB 为半径’几乎一模一样。前一种写法里,我不得不念一段口诀;后一种才是我的几何。”

“现在,”Till 说,“以 B 为圆心、 BA 为半径,画第二个圆。然后求两圆交点。”

circle-intersections-through.png

欧几里得看到屏幕上多出来一个点 C,还有 AC、BC 两条红线,连成一个三角形。

“这就画好了?”他有点意外,“我以为最难的一步会是找交点。”

Till 说:“难点在‘告诉机器哪两条路径要相交’。所以前面画圆时我给它们起了名字: name path=D 和 name path=E 。然后用 name intersections={of=D and E} 让 TikZ 去找它们的交点。找到的交点按顺序命名为 intersection-1 、 intersection-2 。”

“它们默认会叫 intersection-1=、=intersection-2 ,”欧几里得重复了一遍,“所以我要自己把它们绑到 C 这个坐标上。”

“对。不过也可以一步到位。”

Till 又写了一段:

\path [name intersections={of=D and E,
  by={[label=above:$C$]C,
    [label=below:$C'$]C'}}];

“用 by 参数,TikZ 直接把第一个交点命名为 C,第二个命名为 C'。我连 intersection-1 这种名字都不用看见。”

intersections-through-by.png

欧几里得点点头:“这个好。直接给我 C ,我就只需要想几何。”

Till 把前面几步拼起来,加上一些颜色和层次,形成了最终版本:

tikz-the-final.png

Figure 5: 完整的刻画

欧几里得看完整个代码,沉默了一会儿。

“你用了 rand 让 A 和 B 每次编译都微微移动,”他说,“你用了 calc 把主坐标和扰动分开,你用了 through 让圆规的半径自动计算,你用了 intersections 让交点自己浮现。最后你把三角形铺在背景层,让两条红线浮在前面。”

“还有 pgfonlayer ,”Till 补充,“ backgrounds 库负责让三角形不挡住别的线。”

欧几里得点点头:“图是画出来了。可是 Till 大神,我数了数——从定义 A 和 B 到画出三角形,你用了六个库,写了几十行,中间还算了一次 veclen ,命名了一次路径,求了一次交点。”

Till 笑了:“是。TikZ 是通用工具。它能画任何东西,所以画一个纯粹的欧几里得几何图时,你得做很多与几何无关的事——给路径起名字、算长度、管理命名空间。”

欧几里得把目光从屏幕移到窗外,像是在想什么。然后他问:“有没有一种工具,让我只说我心里的几何,剩下的硅基生命去做?”

Till 转过头,朝 Alain 的方向看了一眼,心说,Alain,看你的表演。你只需要复刻最后一幅图的左边部分就可以了。也就是这个:

till-final.png

Alain 打开自己电脑,一台安装 CachyOS(Arch Linux)的笔记本电脑,暗蓝色发出沉沉的光。他早已看出欧几里得为了生命的漫长,而选择对激烈思考的逃避,他尽量慢地打开Emacs开启 Org Mode缓缓写下:

\usepackage{tkz-euclide}

欧几里得问:“就一个?你看刚才,Till 用了六个库。” Till略显惭愧,笑了笑。“而且你这宏包名字, tkz 显然是致敬 TikZ ,而 euclide 又是在致敬太古老登我吧:)”

“暂时就一个。”Alain 说,“ tkz-euclide 自己会去加载它需要的底层库。”

他继续写,“我认真读您的书,自认大体明白您的心意。你看我定义两个点”

alain-two-points.png

欧几里得看了看,心想Alain定义了两个点,脑海里清晰至极,屏幕上一片空白。他想拿“写死坐标,任意给定线段”说事儿,又觉得没啥意思。存在于脑海中概念,要表达出来,都得是具体写死的。所谓“此中有真意,欲辨已忘言”,也许确有其事,但那“真意”是否想清楚了,倒是也必须打大大的折扣呢。

Alain 看着思索中的欧几里得笑了:“这只是一个起点。TikZ 用 \coordinate 定义点,我用 \tkzDefPoint 。名字不同,功能一样。‘任意’这件事,我们后面再谈。我接着画两个圆。”

alain-two-circles.png

欧几里得愣了一下:“一条命令,画两个圆?”

“对。 A,B 的意思是‘以 A 为圆心、过 B 点’, B,A 的意思是‘以 B 为圆心、过 A 点’。”

欧几里得回味了一下这句话,说:“Till 那段代码里,我数了: name path 两次, circle through 两次,还有一次 veclen 。你这里,一行。”

“还不止,”Alain 说,“Till 写这个圆,靠的是 through 库。你的圆规得先算 AB 的长,再把它传给圆规。我这里, tkz-euclide 直接理解‘过 B 点’——半径怎么算,是它的事。”

Till 有点尴尬地笑。Alain 继续取两圆的交点:

alain-intercc.png

欧几里得盯着这段代码看了几秒,问:“这个 \tkzInterCC 就是……两圆相交?”

“对。 Inter 是 intersection, CC 是 circle-circle。两个圆 A,B 和 B,A 有两个交点, \tkzGetPoints{C}{D} 就把它们分别命名为 C 和 D。”

欧几里得沉默了片刻。

“Till 得先给两条路径起名字,再告诉机器 of=D and E ,然后从一堆 intersection-1 、 intersection-2 里挑一个。而你,只说了一句‘两圆相交’,交点就自己有了名字。”

Alain 点点头:“因为 tkz-euclide 知道这是两圆相交。它不需要你告诉它‘这是路径’。它知道圆是什么。”

Alain 接着画:

alain-with-labels.png

欧几里得说:“这些命令,全写到我的心巴里。”

“ DrawCircles 是画圆, DrawPolygon 是画多边形, DrawPoint 是画点, LabelPoint 是标标签。你告诉我你要画什么几何对象,我就画什么。”

“Till 那段代码里,画三角形要 \draw (A) -- (C) -- (B) ,画点是 \foreach ... \fill ... circle ,画标签藏在 \coordinate [label...] 里。看起来是在做几何,实际上是在控制路径。”

Alain 说:“ tkz-euclide 的每个命令,都对应一个几何动作。你看这个宏包的名字: tkz 是 Till 的 TikZ 传统, euclide 是你的《几何原本》。”

Alain 把代码整理成一个完整的文件。他给 B 取了点随机。他把三角形涂上橘色。

alain-final.png

欧几里得从头到尾读了一遍。他数了数,一共十行。

“Till 那张图,”他说,“我数了超过三十行,用了六个库,定义了五个颜色和五个标签宏,命名了两条路径,算了一次长度,求了一次交点,还有一层背景。”

“而你这里,”他顿了顿,“你只是把我脑子里想的事情,一件一件说出来。”

Alain 说:“这就是为什么我写这个宏包。我教数学,我知道几何作图时脑子里想的是什么——点、圆、交点、三角形、标签。 tkz-euclide 让你写出来的代码,和你想的东西一一对应。”

欧几里得看着屏幕,说:“这就像……”

他停了一下,像是在找一个合适的说法。

“这就像用圆规和直尺作图:圆规只管画圆,直尺只管画直线。我不需要知道圆规里的弹簧怎么工作,也不需要知道直尺上的刻度是怎么刻上去的。”

Alain 笑了:“对。 tkz-euclide 就是给你的电子圆规和电子直尺。”

欧几里得看着屏幕上那个等边三角形,沉默了片刻,说:“第一题,是告诉你们,等边三角形可以作。但一个命题的价值,不在它自己能做什么,而在它能帮后面的命题做什么。”

他翻开《几何原本》第一卷,指着第二个命题:

image-100.png

Figure 6: Book I, Proposition II——在给定点作一条线段,等于给定线段

“这是第二题。”欧几里得说,“在给定的点上,作一条线段,长度等于给定的线段。看似比第一题简单——我只是把一条线段的长度搬到另一个地方去。但怎么搬?你不能把长度装进箱子,也不能把它量出来再画一遍,因为那样就依赖‘长度’这个概念了,而我在第一卷里还没有定义长度。我只能用圆规和直尺,用第一题给我的东西,把它搬过去。”

他看了看 Till,又看了看 Alain:“第一题里,你们各自用不同的方式画了一个等边三角形。第二题里,我看你们怎么把这个三角形用起来。”

Till 点点头,打开 Emacs 说:“欧老前辈,第二题的第一步和第一题一样,定义三个点。”

ii-three-points.png

屏幕上出现三个点:A、B、C。B–C 是一条蓝线,A–B 是一条浅灰线。

欧几里得说:“BC 是给定的线段,A 是给定的点。我要在 A 点作一条线段,长度等于 BC。”

“我知道。”Till 说,“第一步是作等边三角形。以 AB 为边,向外作等边三角形ABD。这一步我在第一题里做过。”

他写下:

ii-computation-d.png

欧几里得看了看那行 D 的坐标,问:“ !.5! 、 ! {sin(60)*2} ! 、 ! 90:(B) ,这是什么?”

Till 说:“这是 TikZ 的‘部分路径’计算。 \$ (A)!.5!(B) \$ 取 AB 的中点; \$ ... ! {sin(60)*2} ! 90:(B) \$ 把那个点绕着 A 旋转 90 度,再乘以 sin(60)*2 这个比例。这是手工算等边三角形顶点坐标的公式。”

欧几里得皱了皱眉:“所以你不是在作等边三角形,你是在算它的坐标。”

“是。”Till 老实说,“TikZ 里没有‘作等边三角形’这条命令。我只能用坐标公式把它算出来。”

Alain 在一旁没有出声。

“继续。”欧几里得说。

Till 接着写:“下一步,把 D–A 和 D–B 两条线延长出去。然后以 B 为圆心、经过 C 画一个圆 H。”

ii-circle-h.png

欧几里得看着那个圆 H,问:“ D--F 这条线,你延长了多少?”

“ 3.5 倍 DB 的长度。”Till 说,“因为我不知道圆 H 会和 DF 交在哪里,只能估一个足够长的倍数,保证它一定穿过圆 H 。”

“你估的?”

“我估的。”

欧几里得点点头,没有评价。

Till 接着写:“现在求圆 H 和直线 BF 的交点 G 。这里我又得给圆起名字,给线起名字,然后求交点。”

ii-intersection-g.png

欧几里得盯着那段代码看了几秒。他看到了 name path 、 name intersections 、 of 、 by 这些词,和第一题里一样。他知道 Till 又要给路径起名字,又要让机器去找交点。

“还有几步?”他问。

“还有三步。”Till 说,“以 D 为圆心、经过 G 画圆 K ;求圆 K 与直线 AE 的交点 L ;然后连接 A--L 。”

ii-final.png

Figure 7: 完整的刻画

欧几里得看完了。他没有马上开口。

过了几秒,他说:“Till 大神,我数了一下:这道题,你用了 calc 、 intersections 、 through 三个库;定义了 E 、 F 、 G 、 H 、 K 、 L 六个点;给两条路径起了名字;求了两次交点;还手工估了一次延长的倍数。”

Till 说:“是。”

“第一题你也用了六个库,写了几十行。第二题,你没少写。”欧几里得说,“但我注意到一件更有意思的事:你每一步都知道自己在干什么。你知道 D 是等边三角形的顶点,你知道 G 是圆 H 和 BF 的交点,你知道 L 是圆 K 和 AE 的交点。你全都知道。”

Till 说:“是。”

“但你的代码里,”欧几里得说,“ D 是 !.5! 加 sin(60)*2 加 90:(B) 算出来的, G 是 name intersections 找出来的, L 是 name intersections 又找出来的。你心里的‘等边三角形’、‘交点’、‘交圆’,到屏幕上变成了坐标、路径、命名空间。中间隔了一层。”

Till 沉默了一下,说:“是隔了一层。TikZ 是通用工具,它不知道什么是圆,什么是交点,什么是等边三角形。它只知道路径和坐标。所以我得把几何翻译成路径和坐标。”

欧几里得说:“这一点我在第一题里已经看到了。但第二题让我看得更清楚。”

他转过头,看着 Alain。

Alain 早就准备好了。他把笔记本电脑转过来,屏幕上是他刚才在 Emacs 里写下的东西:

alain-book-i-propostion-ii-complete-code.png

欧几里得从头到尾看了一遍。他指着第二行:

“ \tkzDefTriangle[equilateral](A,B)\tkzGetPoint{D} 。”

“这是……作等边三角形?”

“对。”Alain 说,“ DefTriangle 是定义三角形, equilateral 是等边。给它AB 这条边,它把顶点算出来,命名为 D。”

欧几里得说:“Till 用了 !.5!=、=sin(60)*2=、=90:(B) 三个修饰符才算出 D 点。你这里,一行。”

Alain 说:“因为 tkz-euclide 知道什么是‘等边三角形’。它不是从坐标出发,而是从几何对象出发。”

欧几里得指着下一行:

“ \tkzInterLC[near](D,B)(B,C) \tkzGetSecondPoint{G} 。”

“ InterLC 是 line-circle 相交, D,B 是直线 DB, B,C 是以 B 为圆心经过 C的圆。 \tkzGetSecondPoint{G} 是取第二个交点。”

欧几里得说:“所以你知道这条线和这个圆有两个交点,你取第二个。”

“对。”

“Till 那里,”欧几里得说,“他得先给圆起名字 H,给线起名字 B–F,然后告诉机器 of=H and B--F ,再让机器把交点命名成 intersection-1 ,然后他自己从=intersection-1= 里挑。你这里,两行,直接交,直接得。”

Alain 点点头:“因为 tkz-euclide 知道什么是圆,什么是直线,什么是它们的交点。它不需要‘路径’这个概念做中介。”

欧几里得指着最后几行:

“ \tkzDrawCircles(B,C D,G) 一句画两个圆; \tkzDrawLines[add=0 and 2](D,A D,B) 一句画两条线并延长; \tkzDrawSegment(A,B) 一句画线段; \tkzDrawSegments[red](A,L B,C) 一句画两条红色线段。 \tkzDrawPoints 、 \tkzLabelPoints 、 \tkzLabelCircle ……全是几何动作。”

他停了一下,说:

“Alain,你的代码,几乎不是代码。它是一份作图步骤的陈述。 DefPoint 、 DefTriangle 、 InterLC 、 DrawCircles 、 DrawLines 、 LabelPoints ——每一条命令,都是一个几何动作的名字。你不是在告诉机器怎么算,你是在告诉它——我要作什么。”

Alain 说:“这就是我写 tkz-euclide 的初衷。我教数学,我知道老师在黑板上是怎么说的:‘作等边三角形’、‘延长 AB’、‘交圆于 G’、‘连接 AL’。这些话,就是 tkz-euclide 的命令。”

欧几里得沉默了一会儿,说:

“Till 的代码,是我说‘以 A 为圆心、AB 为半径画圆’时,机器听到的样子。 Alain 的代码,是我说这句话时,我心里的样子。”

他看了看 Till,又看了看 Alain。

“Till 大神,你的 TikZ 把 TeX 变成了一个可以画任何图形的系统,这是开创性的。但通用是要付出代价的——几何题里的‘圆’、‘交点’、‘等边三角形’,都要先降解成坐标和路径。你在第一题里让我看到了这个代价,第二题让我看得更清楚。”

“Alain 的 tkz-euclide ,建立在你的 TikZ 之上。它没有另起炉灶,它是在你的地基上,把笛卡尔坐标那一层藏起来,把欧几里得几何那一层露出来。”

Till 说:“是。 tkz-euclide 就是我最希望看到的那类宏包:在 TikZ 之上,做TikZ 自己不做的事。”

Alain 说:“没有 TikZ , tkz-euclide 不存在。”

欧几里得点点头:“这就是我为什么一直说,一个命题的价值,不在它自己能做什么,而在它能帮后面的命题做什么。TikZ 是第一题, tkz-euclide 是第二题。”

他站起来,看着屏幕上的两幅图——一幅是 Till 写的,一幅是 Alain 写的。它们画出来的图几乎一模一样。他不由得望向窗外,阳光,泉水叮咚,微寒的空气深吸一口。此时脑海中闪耀过的蛇状闪电已然平静,偶尔似夜幕中的烟花隐约,不过这些都在堤坝内,离决堤还远着呢。鼓足勇气再思考硅基生命。他知道它们离他很近,甚至能听到彼此的呼吸——一个风冷,一个液冷。它们已经欢快工作一个下午。他斗胆思考它们的食物,也就是他脑海中划过的闪电,是来自哪里。他想理出公理与定理来推理一下,又觉得心潮汹涌,喉咙发甜。他张嘴叫斐洛,天儿不早了,天黑留客吃饭,可不是天经地义的事儿么。斐洛说,欧老呀,这鸡毛小事儿怎劳您烦心,早备下了。面包,橄榄油,葡萄酒,肉脯早预好了。

还有一事,斐洛沉吟,据二位大神讲,欧老的《几何原本》,是在1000多年后的文艺复兴才为世人所见。中间的一两千年杳无音信,说什么黑暗中世纪,耶稣基督默罕默德我佛如来,感觉都扯淡不是根因。这千多年您的书,也就是您还没写完的《几何原本》到底怎么回事没人说得清,我他妈也不想知道。我想知道的是怎么给传过去,以什么形式。说到形式我至少知道您的纸莎草纸肯定不灵。羊皮纸也不知道行不行。二位大神,羊皮纸到底行不行哪?

Till说羊皮纸可能行。但羊皮纸贵,也保不齐能扛过千年。Alain,这样你看行不行?斐洛你想办法搞羊皮纸,尽快誊写。我们给带到文艺复兴发现《几何原本》的图书馆。笛前辈在历史长河中等着看呢还。欧说我还没写完呢嘿。Alain说没事儿,本来历史里记载的也不完整,有些意思吧,意思意思就行了,但意思不到就没意思了;斐洛!有一件事我们得再说一遍,你可能忘记:我们就是从文艺复兴前图书馆那时空来的,翻遍图书馆,没见欧老的书。另外历史中记载《几何原本》是羊皮书,而且不是手抄本,里面的插图,尤其不是手绘。

斐洛说我没忘,我已经通知欧老学 TikZ ,纸莎草纸已经过时。欧老学会 TikZ 没啥难度。但我没搞明白的是, TikZ 运行在大神的硅基生命体内,如何搬运到羊皮纸上?Alain说你要问原理那我可就不懂了,Till你懂吗?Till说我怎么可能懂。2035年硅基大神征服了程序员,程序员集体成智能体饲养员了。同时征服了最聪明的人类数学家,数学家成了硅基大神的天使。比如我们俩也就算小天使吧,满时空飞为硅基大神打杂。有大天使组团抵抗过几年,硅基大神看都没看一眼,就自己瓦解了。所有的数学猜想已获证明,包括黎曼猜想,所有的数学定理也已发现,包括时间力学。羊皮纸搬运这两台硅基终端可以做到。数学原理支撑是超时空打印定理,这定理由硅基大神首次发现并证明。证明过程有80亿行,全时空数学家没一个能完整看懂。Alain你能看懂吗?

Alain说我哪懂,我都不算个数学家,我也就是个乡村教师。但显然这定理正确的,不然我们俩也到不了此时此地。欧老,今天给您讲的不好,实在是能力有限,不是不卖力气那。欧老说那好吧,好多事我也是不敢想,一想脑袋疼,咱也不敢问,一问眼发黑。斐说,没事儿没事儿,多伟大的人也是碳基呐,咱碳基就不能啥都想明白,不能啥都懂。不过胆小怕死是咱碳基的优势嘛。我斐洛别的不敢说,羊的事可以包在我身上,欧老,看来咱得且吃好些时候的羊肉了,皮留着写书。欧说羊肉好呀,二位神想必也爱吃。Till Alain说爱吃爱吃,烤的,炖的,红烧,羊头羊蹄都好吃,不过最好吃还是涮羊肉。斐洛说涮羊肉办不了,没碳没火,没碳没铜,没铜没锅,再说俺们这芝麻酱韭菜花也没个着落啊。众人说说笑笑,度过深秋美丽的下午。