前 言

看到本书的标题《程序员的数学3:线性代数》时,不同的读者应该会有不同的印象吧。我们根据读者可能会产生的第一印象,为读者设定了“快捷方式”。

“又是程序员的数学系列啊”!→(a)

“肯定有好多公式,推理也会很烦,念起来应该很吃力吧”! →(b)

“想必会解释得细致入微,但讲解的深度应该很有限吧”! →(c)

“这作者是干嘛的”! →(d)

“我也不编程啊”! →(e)

(a)致想到“又是程序员的数学系列啊”的读者

本书面向的主要读者群体包括与计算机相关的所有专业与非专业人士。作为一本线性代数的参考书,本书的一大特色是,针对以上这些读者,在讲解时使用了易于他们理解的表述方式,并运用了大量的示例和比喻。我们的目标是向非数学专业的读者讲述线性代数的本质。正因为如此,这不是一本单单讲解“如何进行线性代数相关的编程”的书。读者只要阅读一下前言的(c)部分,就可以对本书的风格有个大概的了解了。我们把本书特别推荐给以下读者。

想要从事信号处理、数据分析等方面的工作或研究,在阅读相关专业书籍的过程中遇到了线性代数,面对这些问题怎么也搞不明白,因此希望学习(或者补充)一下相关知识。但是能找到的参考书中,不是充斥着数学证明的教科书,就是看过之后似懂非懂的入门书

正在学校学习线性代数,而且不仅仅满足于通过考试,而是希望切切实实地掌握相关知识,以便在以后的工作中熟练使用

因为本书面向的读者主要是非数学专业的,所以我们不会为了数学而讲数学,而是更加强调“这些知识在哪里会有用”。虽然理工科中有众多不同的专业,每个专业所研究的对象也是各种各样,但是其中涉及的数学问题却总有着这样那样的共通之处。在本书中,我们首先会提炼出这类问题,接着在挑战这些问题的过程中导入线性代数的概念。这就是本书的风格。这样做不仅是为了讲解数学理论,更是为了使读者学会线性代数的“用法”。

(b)致想到“肯定有好多公式,推理也会很烦,念起来应该很吃力吧”的读者

为了让读者尽可能透彻地理解线性代数的本质含义,本书中在说明时穿插了很多直观的示意图。试想,如果学完了线性代数,却只懂得行列式的计算,而对行列式的意义一无所知,那这种学习有什么用呢?无论是笔算还是用计算机算,如果只是求出了“迷一般”的行列式的值,那没有任何意义。为了避免这种徒劳无功的学习,本书会着重对原理、推导过程进行细致的解释。

但是,就算再完美、再严密的理论体系,(对非数学专业的人来说)也总会在少数地方存在一些麻烦的东西。在学习比入门书难度稍大一点的参考书时,想必很多读者都在一些无关痛痒的难点处栽了跟头。在本书中,我们会重点关注真正重要的地方,为读者讲解思路和方法,使读者不只是学会计算步骤,还能达到更高的层次。关于数学公式,在必要的时候当然会使用,但是为了避免读者产生恐惧心理,我们尽量避免了那些往往会吓到外行的一本正经的表述①。

另外,针对读者不同层次的需求,本书采用了可以进行跳跃式阅读的结构(更加细致的章节结构请参考目录)。

第一层次

在阅读那些以线性代数为工具的资料时,比如信号处理、数据分析等领域的参考书,希望能够明白其中的数学公式等的意义

→阅读第1 章(跳过标有▽ 和▽▽ 的章节②)

① 比如,不写成enter image description here的形式,而是采用 的记法。对于涉及变量、下标等的地方,我们会采用更加具体直观的写法。

② 标有▽ 的章节的主要内容是如何进行笔算(以及相关知识),标有▽▽ 的章节的主要内容是如何使用计算机进行计算以及相关的算法分析。那些只是草草学过一遍线性代数的读者,在阅读过第1 章之后,也会有不少新的发现和启发。

第二层次

在阅读以线性代数为工具的参考书时,希望理解书中的内容

→阅读全书(跳过标有▽和▽▽ 的章节)

第三层次

希望能够自己进行计算

→阅读全书(跳过标有▽▽ 的章节)

第四层次

希望踏入大规模矩阵计算的世界

→阅读全书,包括标有▽▽ 的章节

那些不期望自己成为专家的读者,把目标定在第二层次如何?如果有时间学习“逆矩阵的笔算法”的话,记住“如果映射带来了压缩扁平化变换,则不存在逆矩阵”这一本质特性是非常有意义的。哪怕是为了计算而学,比起死记硬背笔算法的步骤,“能够区分xxT 是矩阵,xTx 是数”“能够用分块矩阵来表示Ax + b”这些技能①在后续的学习和工作中会更有用。好了,以上是笔者对读者的一些建议。

(c)致想到“想必会解释得细致入微,但讲解的深度应该很有限吧”的读者

生硬的数学书就好比是缺少注释的源代码。虽然有些程序执行效率非常高,也很优雅,但是从可读性的角度来讲,要想理解代码的含义,就需要付出一定的努力、具有一定的素养,以及对程序有感觉(夸张地讲,可能还需要一些逆向工程的知识)。另一方面,入门书一不小心就会出现类似于“只有注释而没有代码”“虽然有代码段,但是没办法将其作为完整的程序来执行”的情况。本书属于“既给出能够执行的完整代码②,又附带充足的注释”那种类型。我们的注释,不会是如下这种风格。

① 这些将在1.2.13 节和1.2.9 节中进行说明。

② 对于无论如何都无法避免繁杂操作的部分,在少数地方我们会利用现成的工具包、类库进行封装处理。

.

# 给p 增加1
p = p + 1

这种注释有没有都一样。我们的风格是这样的。

# 前奏已经足够了,转到下一页
p = p + 1

注释只有说明了指令的意图,才是有意义的。我们一方面通过注释帮助代码把“内心的真实想法”传达给读者,同时也写出了本身就“不乏风味”的代码。这也是本书的一大亮点。

另外,“不乏风味”还有一层含义,那就是不单单让读者学会解题,还要学到一种看待问题的新方式。比如,“学了秩的概念之后,一下子就能判断出能否由结果推出原因了”“学了特征值、特征向量的概念之后,很快就能了解系统是否有失控危险了”,像这样,如果读者能够感到自己的思路被打开,最后体会到了“一览众山小”的快乐,那么我们的目的就达到了。为此,如果仅仅是简单介绍秩的概念,或者简单讲解计算方法,那是远远不够的。只有充分理解了其本质含义,才能从问题的根源出发,从而轻而易举地理解“不满秩则矩阵的逆不存在”等问题。出于这种考虑,本书遵循以下原则。

要讲就要讲到本质,否则就没有意义了
用浅显的语言逐步解释,让读者打心底里认为“推出这样的结果是理所当然的”

最后要达到的层次绝对不算低。本书涉及了很多线性代数教科书中通常不会提及的数值分析的内容。这一点大家看看目录就会发现。

另外,本书作为“基础篇”,基本上不考虑带有度量的问题,而是以无度量的问题为中心。以后如果有机会的话,我们也许会以某种方式发布“应用篇”,届时再讨论带有度量的实际问题。

(d)致想到“这作者是干嘛的”的读者

笔者是从事应用数学、工程数学研究的科研工作者。在诸如模式识别、神经网络、非线性动力系统、统计数据分析等领域,本书涉及的内容作为“常识”,每天都在发挥着关键作用。就算是进入了非线性理论的世界,线性代数作为基本的工具也是必不可少的。无论是在理论上还是在应用上,笔者都将尽可能地展现出数学真正有用的一面。另外,本书中也用心地选取了合适的题材和恰当的切入点,使得在实际问题中线性代数的“使用”不显得突兀。

(e)致想到“我也不编程啊”的读者

读过前言的(a)部分就会了解到,本书并不以“如何进行线性代数的相关编程”为主要内容。现在不管在任何领域,多多少少都要与计算机打交道,而本书就是着眼于在众多领域中都发挥作用的线性代数,对其内涵进行剖析。与计算机打交道的核心就是“(编)程序”,而本书就是为编程序的人,即程序员而写的,这就是本书书名的由来。

在第3 章“计算机上的计算”中,我们也提供了可在实际应用中用于矩阵计算的例程。

另外,为了让读者切身体会到矩阵是如何表示映射的,我们也准备了简单的程序供读者在自己的计算机上使用。读者可以从图灵社区的网站上下载源代码①,请一定要体验一下!

还有一点要说明,本书中给出的源代码全部采用Ruby 语言编写。之所以选择Ruby,首先,我们希望选择一种高级语言,从而在代码中避开那些与算法本身关系不大的繁杂部分。其次,我们希望程序语言的语法比较接近自然语言,从而减少不必要的理解错误。最后一个非常重要的原因是,相比伪代码,我们更希望呈现给大家能实际运行的源代码。这也正是我们采用Ruby 的初衷。

致认为本书是讲解如何用Ruby 进行线性代数编程的读者

不好意思,真不是这样的。书中的代码不会有浓浓的“Ruby 风”,为了使人人都可以轻松理解,笔者在写代码时参照了伪代码的写法。

致一听到Ruby 就想把书合起来的读者

如前所述,只要读者接触过其他主流的程序设计语言,就可以在没有任何Ruby 基础的情况下顺利地阅读本书中的源代码。最后,有一点请读者千万不要误解,真正的Ruby 语言,可不是只能做做这些简单死板的工作而已,敬请广大读者周知。

① 打开http://www.ituring.com.cn/book/1239,点击“随书下载”。

目录

  • 前 言
  • 译 者 序
  • 第0章:动机
  • 第1章 用空间的语言表达向量、矩阵和行列式
  • 第2章 秩、逆矩阵、线性方程组——溯因推理
  • 第3章 计算机上的计算(1)——LU 分解
  • 第4章 特征值、对角化、Jordan标准型——判断是否有失控的危险
  • 第5章 计算机上的计算(2)——特征值算法
  • 参考文献