艾巴生活网

您现在的位置是:主页>科技 >内容

科技

线性代数是什么(存在的意义是什么)

2024-11-10 23:34:47科技帅气的蚂蚁
什么是线性代数?在大学数学中,线性代数是最抽象的课程,从初等数学到线性代数的思维跨度远大于微积分和概率统计。很多人研究过之后,停留

线性代数是什么(存在的意义是什么)

什么是线性代数?

在大学数学中,线性代数是最抽象的课程,从初等数学到线性代数的思维跨度远大于微积分和概率统计。很多人研究过之后,停留在知道为什么的阶段。经过几年接触图形编程或机器学习等领域,他们发现线性代数的应用无处不在,却苦于无法很好的理解和掌握。的确,大多数人都能轻松理解初等数学的概念。函数、方程、数列都是那么自然,但一旦进入线性代数的世界,就像来到了另一个陌生的世界,迷失在各种陌生的符号和运算中。

刚接触线性代数的时候,我单纯的觉得这是一门天外飞的学科。一个问题浮现在我的脑海里:

线性代数是客观自然规律还是人为设计?

如果看到这个问题,你的反应是“不用说,数学当然是客观自然规律”。我一点也不觉得奇怪。我自己也这么认为。从中学的初等数学和初等物理一路走来,很少有人怀疑一门数学学科是不是自然规律。我学微积分和概率统计的时候,从来没有怀疑过。只有线性代数让我产生了怀疑,因为它的各种符号和运算规则太过抽象和陌生,根本无法对应生活经验。所以,我真的要感谢线性代数,让我思考一门数学学科的本质。其实不仅仅是学生,包括很多数学老师都不知道线性代数到底是什么,有什么用,不仅在国内,在国外也是如此。中国的孟雁写了《理解矩阵》,国外的谢尔登埃克斯勒教授写了《线性代数应该这样学》,但都没有从根本上解释线性代数的来龙去脉。对我自己来说,大学的时候没有学过线性代数,后来从编程的角度理解了。很多人说数学好对编程有帮助,而我恰恰相反。理解程序帮助我理解数学。

电脑里有汇编、C/C、Java、Python等通用语言,也有Makefile、CSS、SQL等DSL。这些语言是客观自然规律还是人为设计?

你为什么问这么愚蠢的问题?因为它的答案是显而易见的,大家对日常使用的编程语言的理解一定比抽象的线性代数要好。显然,编程语言虽然包含内部逻辑,但本质上都是人工设计。所有编程语言的共同点是都建立了一套模型,定义了一套语法,并将每种语法映射到特定的语义。遵守程序员和语言实现者之间的语言契约:程序员保证代码符合语言的语法,编译器/解释器保证代码执行的结果符合语法对应的语义。比如C规定对象A要用新的A()语法在堆上构造。如果这样写C,必须保证相应的执行效果,在堆上分配内存并调用A的构造函数,否则编译器就违反了语言契约。

从应用的角度来看,可以把线性代数看作一门编程语言吗?答案是肯定的,我们可以以语言契约为标准来尝试。假设你有一个图像,你想把它旋转60度,然后沿着X轴拉伸2倍;线性代数告诉你,“好!你按照我的语法构造一个矩阵,然后按照矩阵乘法规则把你的图像相乘。我保证结果是你想要的”。

其实线性代数和SQL一样和DSL很像。以下是一些类比:

和模型语义:SQL是基于一种底层语言的关系模型,其核心语义是关系和关系操作;线性代数在初等数学上建立向量模型,其核心语义是向量和线性变换。

语法:SQL为每种语义定义了相应的语法,比如select、where、join等。线性代数还定义了向量、矩阵、矩阵乘法等语义概念的相应语法。

编译/解释:SQL可以编译/解释为C语言;线性代数相关的概念和运算规则,可以用初等数学来解释。

实现:我们可以在MySQL、Oracle等关系数据库上编程SQL我们也可以在MATLAB,Mathematica等数学软件上编程线性代数。

因此,从应用的角度来看,线性代数是一种人工设计的领域特定语言(DSL),它建立一套模型,通过一个符号系统完成语法和语义的映射。其实向量、矩阵、运算规则的语法、语义都是人为设计的,和一门语言中的各种概念有着相同的性质。是一种创造,但前提是必须满足语言契约。

为什么要有线性代数?

有些人可能对将线性代数作为DSL感到不安。如果我给你一个矩阵,你将把我的图旋转60度,沿着X轴拉伸2倍。我总是没有安全感。我都不知道你是怎么做到“底层”的!其实就像有些程序员对高级语言不实用,以为底层才是程序的本质,总想知道这句话编译成汇编是什么感觉。该操作分配了多少内存?别人直接在Shell里输入一个wget命令就能拿下一个网页,而他要花上几十分钟用C语言写一堆代码才能实用。其实所谓的底和顶只是习惯性的说法,并不是谁比谁更本质。程序的编译和解释本质上是不同模型之间的语义映射。通常,高级语言被映射到低级语言,但是方向可以完全颠倒。法布里斯贝拉用JavaScript写了一个虚拟机,在JavaScript虚拟机上运行Linux,就是把机器模型映射到JavaScript模型。

新模型的建立肯定依赖于现有的模型,但这是建模的手段而不是目的。任何新模型的目的都是为了更简单地分析和解决某种问题。线性代数建立的时候,它的概念和运算规则依赖于初等数学的知识,但是一旦建立了这种抽象模型,我们就要习惯于直接使用高级抽象模型来分析和解决问题。

说到线性代数,它比初等数学更容易分析和解决问题。这里有一个实际感受它的好处的例子:

给定三角形的顶点(x1,y1)、(x2,y2)、(x3,y3)和(x3,y3),求三角形的面积。

初等数学中计算三角形面积最著名的公式是面积=1/2 *底*高。当三角形的一边恰好在坐标轴上时,我们就可以很容易地计算出它的面积。但是如果我们旋转同一个三角形的坐标轴,使得它的边不在坐标轴上呢?我们还能得到它的底部和高度吗?答案肯定是肯定的,但是显然比较复杂,有很多情况需要单独讨论。

相反,如果我们用线性代数的知识来解决这个问题,就非常容易了。线性代数中,两个向量A,B的叉积是方向垂直于A,B的向量,其大小等于A,B形成的平行四边形的面积:

我们可以把三角形的边想象成向量,所以三角形的面积等于两个边向量的叉积除以二的绝对值:

area=abs(1/2 *叉积((x2 - x1,y2 - y1),(x3 - x1,y3 - y1)))

注:abs表示绝对值,cross_product表示两个向量的叉积。

这么难的初等数学问题,线性代数就能瞬间解决!可能有人会说,你直接基于叉积做很容易,但是叉积本身不是挺复杂的吗?你为什么不试试呢?没错,模型的作用就是将部分复杂性隐藏在模型中,让模型的使用者更简单地解决问题。曾经有人质疑C太复杂。C的父亲比雅尼斯特劳斯特鲁普是这样回答的:

复杂性总会存在:如果不是语言,那么就是应用程序代码。

在特定的环境下,问题的复杂程度是由其本质决定的。为了使应用程序更简单,c语言在语言和标准库中加入了一些复杂性。当然,C并不是在所有情况下都让问题变得更简单,但原则上,C的复杂度是合理的。除了C,Java,SQL,CSS等语言和框架都是最好的。想象一下,如果不使用数据库,自己存储和管理数据是多么复杂!这样我们就不难理解为什么线性代数会把这么奇怪的运算定义为叉积了。C在STL中融入了很多常用的算法和容器也是同样的道理。类似地,您甚至可以在线性代数中定义您想要的操作,以便重用。所以,数学一点也不死板,它像程序一样活泼,你了解它的来龙去脉,就能驾驭自如。说到这里,我们就顺便回答一个很常见的问题:

线性代数的点积、叉积、矩阵运算都很奇怪。为什么要定义这些操作?为什么他们的定义是这样的?

其实线性代数和程序复用一样,定义了点积、叉积、矩阵运算,是因为它们应用广泛,复用价值大,可以作为我们分析和解决问题的基础。比如很多问题都涉及到一个向量到另一个向量的投影或者两个向量之间的夹角,所以我们会考虑定义点积:

点产品的概念属于设计,有创意的空间。设计一旦定型,具体的公式就不能随意使用,一定要有逻辑性,保证其映射到初等数学模型的正确性。就像一门高级语言可以定义很多概念,比如高阶函数、闭包等。但它必须确保映射到底层实现时产生的效果符合其定义的规范。

线性代数有什么好?

如上所述,线性代数是一个高级抽象模型,我们可以通过学习一门编程语言来学习它的语法和语义。但是这种理解不仅仅是针对线性代数,而是针对每一门数学学科,可能有人会有疑问。

微积分和概率论也是高级抽象,那么线性代数有什么特点呢?

这就把我们带到了线性代数的核心:向量模型。我们在初等数学中学习的坐标系属于笛卡尔提出的解析模型。这个模型很有用,但是也有很大的缺点。坐标系是人为添加的虚拟参考系,但我们需要解决的问题,如面积计算、图形旋转、拉伸等应用,都与坐标系无关。建立虚拟坐标系通常无助于解决问题。刚才三角形面积的例子是这样的。

矢量模型克服了解析模型的缺点。如果说解析模型代表了某种“绝对”的世界观,那么向量模型则代表了某种“相对”的世界观。我建议把向量模型和解析模型看成是两个对立的模型。

矢量模型中定义了矢量和标量的概念。向量有大小和方向,满足线性组合规则;标量是只有大小没有方向的量(注:标量的另一个更深层次的定义是在坐标变换中保持不变的量)。矢量模型的一个优点是其坐标系独立性,即相对性。它在定义矢量和运算规则时,从一开始就抛弃了坐标系的约束。不管你的坐标轴怎么转,我都能适应。向量的线性组合、内积、叉积、线性变换等运算都是坐标系无关的。注意,所谓坐标系独立,并不是说没有坐标系,而是有。刚才三角形例子的顶点是用坐标表示的,但是坐标系不同不会影响问题的解决。打个比喻,Java声称是平台无关的。并不是说Java是空中楼阁,而是说你用Java编程,底层是Linux还是Windows对你来说并不重要。

向量模型有什么好处?除了刚才举的三角形面积问题为例,我再举另一个几何例子:

给定三维坐标系中的一个点(x0,y0,z0)和一个平面a*x b*y c*z d=0,求该点到平面的垂直距离?

如果要从解析几何的角度解决这个问题,几乎太过复杂,无从下手,除非是平面刚好与坐标轴相交的特殊情况,但如果从矢量模型考虑,就很简单:根据平面方程,平面的法向量为v=(a,b,c),从平面上的任意一点(x,y,z)到(x0,y0,z0)设定。然后用内积dot_product(w,V)计算W到V的投影向量P,其大小为(x0,y0,z0)到平面a*x b*y c*z d=0的垂直距离。这里用到向量模型的基本概念:法向量、投影向量、内积,整个解题过程简洁明了。

这里再给你做一个类似的练习(熟悉机器学习的朋友可能会发现这就是线性代数在线性分类中的应用):

给定两点(a1,a2,安),(b1,b2,bn)和超平面c1*x1 c2*x2.cn*xn d=0在N维空间中,请判断两点是在超平面的同侧还是不同侧?

离开向量,我们来邀请线性代数的另一个主角:矩阵。

线性代数定义了矩阵和向量,矩阵和矩阵乘法。操作规则很复杂,不清楚该怎么做。很多初学者理解不好。可以说矩阵是学好线性代数的障碍。遇到复杂的事情,往往要避免先陷入细节,先从整体上把握。其实从程序的角度来说,形式再奇怪,也无非是一种语法,语法必须对应语义,所以理解矩阵的关键点就是理解它的语义。一个矩阵的语义不止一个,在不同的环境下有不同的语义,在同一环境下可以有不同的解释。最常见的包括:1)表示线性变换;2)表示一组列向量或行向量;3)表示一组子矩阵。

矩阵整体上对应线性变换的语义:W是矩阵A乘以一个向量V得到的,矩阵A代表V到W的线性变换,比如你想把向量v0逆时针旋转60度得到V’,你只需要把v0乘以旋转矩阵。

除了旋转变换,拉伸变换也是一种常见的变换。比如我们可以通过一个拉伸矩阵将向量沿X轴拉伸2倍(请自己尝试给出拉伸矩阵的形式)。更重要的是,矩阵乘法有一个很好的性质:它满足组合率。这意味着线性变换可以叠加。比如我们可以将“逆时针旋转60度”的矩阵M和“沿X轴拉伸2倍”的矩阵N相乘,得到一个新的表示“逆时针旋转60度,沿X轴拉伸2倍”的矩阵T。这是否非常类似于在我们的Shell中通过管道堆叠多个命令?

以上重点介绍矢量模型的坐标系独立性。此外,矢量模型的另一个优点是线性,因此可以用来表达线性关系。让我们看一个熟悉的斐波那契数列的例子:

斐波那契数列定义为:f (n)=f (n-1) f (n-2),f (0)=0,f(1)=1;问题:输入n,请给出求f(n)的时间复杂度不超过O(logn)的算法。

首先我们构造两个向量v1=(f(n ^ 1),f(n))和v2=(f(n ^ 2),f(n ^ 1))。根据斐波那契数列的性质,我们可以得到从v1到v2的递归变换矩阵:

并进一步得到:

这样就把线性递归问题转化为矩阵的n次方的经典问题,并且可以在O(log n)的时间复杂度内求解。除了线性递归序列,初等数学中著名的N元线性方程组问题也可以转化为矩阵和向量相乘,比较容易解决。这个例子的目的是为了说明所有满足线性关系的系统对于向量模型都是有用的,我们往往可以将其转化为线性代数来得到简洁高效的解。

总之,我的经验是向量模型是整个线性代数的核心,向量的概念、性质、关系、变换是掌握和应用线性代数的关键点。

摘要

本文提出一个观点:从应用的角度来看,可以把线性代数看作是一种特定领域的编程语言。线性代数建立了基于初等数学的向量模型,定义了一套语法和语义,符合编程语言的语言契约。矢量模型独立于坐标系,是线性的。它是整个线性代数的核心,是解决线性空间问题的最佳模型。