- 原文地址:Linear Algebra: Linear Transformation, Matrix
- 原文做者:Rodion Chachura
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:lsvih
- 校对者:Mcskiller, Baddyo
本文是“JavaScript 线性代数”教程的一部分。javascript
矩阵是一种由 m 行 n 列实数组成的“矩形”数组。好比,一个 3x2 的矩阵以下所示:前端
Matrix 类的构造器(constructor)接收若干行元素做为参数。咱们能够经过指定行号取出矩阵中的一行,而后再经过指定列号取出一个特定的元素。下面直接看代码:java
class Matrix {
constructor(...rows) {
this.rows = rows
}
}
const matrix = new Matrix(
[0, 1],
[2, 3],
[4, 5]
)
console.log(matrix)
// Matrix { rows: [ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ] ] }
console.log(matrix.rows[1])
// [ 2, 3 ]
console.log(matrix.rows[1][1])
// 3
复制代码
矩阵与向量的乘法 —— 会将矩阵
的列进行系数为
的线性组合。好比,一个
的矩阵 A 与一个 2D 向量
的乘积将获得一个 3D 向量,这个计算记为:
。android
假设有一组向量 ,另外一个向量
是
和
的线性组合:
。其中,
就是这个线性组合的系数。ios
为了更好地学习线性组合,咱们特意为此定义了矩阵向量乘法。咱们能够将前面所说的线性组合记为如下矩阵向量乘法的形式:。矩阵
有
、
两列。矩阵的维数是
,其中
是向量
、
与
的维数。git
下图展现了将向量 表示为向量
和向量
的线性组合:github
const i = new Vector(1, 0)
const j = new Vector(0, 1)
const firstCoeff = 2
const secondCoeff = 5
const linearCombination = i.scaleBy(firstCoeff).add(j.scaleBy(secondCoeff))
console.log(linearCombination)
// Vector { components: [ 2, 5 ] }
复制代码
矩阵与向量的乘法是线性变换的抽象概念,这是学习线性代数中的关键概念之一。向量与矩阵的乘法能够视为对向量进行线性变换:将 n 维向量做为输入,并输出 m 维向量。也能够说,矩阵是定义好的某种空间变换。后端
咱们能够经过一个示例来更清楚地理解线性变换。首先须要给 Matrix 类加上一个方法,用于返回矩阵的列:数组
class Matrix {
constructor(...rows) {
this.rows = rows
}
columns() {
return this.rows[0].map((_, i) => this.rows.map(r => r[i]))
}
}
const matrix = new Matrix(
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
)
console.log(matrix.columns())
// [ [ 1, 4, 7 ], [ 2, 5, 8 ], [ 3, 6, 9 ] ]
复制代码
乘法获得的向量的维数将与矩阵的行数相同。若是咱们将一个 2D 向量和一个 3x2 矩阵相乘,将获得一个 3D 的向量;若是将一个 3D 向量和一个 2x3 矩阵相乘,将获得一个 2D 的向量;若是在作乘法时,矩阵的列数和向量的维数不相同,将报错。在下面的代码中,你能够看到几种不一样的向量与矩阵相乘的形式:学习
const sum = arr => arr.reduce((acc, value) => acc + value, 0)
class Vector {
// ...
transform(matrix) {
const columns = matrix.columns()
if(columns.length !== this.components.length) {
throw new Error('Matrix columns length should be equal to vector components length.')
}
const multiplied = columns
.map((column, i) => column.map(c => c * this.components[i]))
const newComponents = multiplied[0].map((_, i) => sum(multiplied.map(column => column[i])))
return new Vector(...newComponents)
}
}
const vector2D = new Vector(3, 5)
const vector3D = new Vector(3, 5, 2)
const matrix2x2D = new Matrix(
[1, 2],
[3, 4]
)
const matrix2x3D = new Matrix(
[1, 2, 3],
[4, 5, 6]
)
const matrix3x2D = new Matrix(
[1, 2],
[3, 4],
[5, 6]
)
// 2D => 2D
console.log(vector2D.transform(matrix2x2D))
// Vector { components: [ 13, 29 ] }
// 3D => 2D
console.log(vector3D.transform(matrix2x3D))
// Vector { components: [ 19, 49 ] }
// 2D => 3D
console.log(vector2D.transform(matrix3x2D))
// Vector { components: [ 13, 29, 45 ] }
console.log(vector2D.transform(matrix2x3D))
// Error: Matrix columns length should be equal to vector components length.
复制代码
如今,咱们将尝试对二维的对象应用线性变换。首先,须要建立一个新的 Contour(轮廓)类,它在 constructor 中接收一系列的向量(在 2D 平面中造成一个轮廓),而后用惟一的方法 —— transform 对轮廓中的全部向量坐标进行变换,最后返回一个新的轮廓。
class Contour {
constructor(vectors) {
this.vectors = vectors
}
transform(matrix) {
const newVectors = this.vectors.map(v => v.transform(matrix))
return new Contour(newVectors)
}
}
const contour = new Contour([
new Vector(0, 0),
new Vector(0, 4),
new Vector(4, 4),
new Vector(4, 0)
])
复制代码
如今,请在 linear-algebra-demo 项目中试试各类转换矩阵。红色方块是初始化的轮廓,蓝色形状是应用变换矩阵后的轮廓。
经过下面的方式,咱们能够构建一个矩阵,用于将给定的向量旋转指定的角度。
const angle = toRadians(45)
const matrix = new Matrix(
[Math.cos(angle), -Math.sin(angle)],
[Math.sin(angle), Math.cos(angle)]
)
复制代码
对 3D 空间内的对象进行变换也与此相似。你能够在下图中看到一个红色方块变换成一个蓝色的平行六边形的动画。
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。