F#与数学(II) – 在图形算法中使用矩阵(PartII)

翻译 2012年03月21日 15:47:02

使用矩阵

Matrix是一种可变类型,因此它可以在创建后被修改。当你必须要修改矩阵式,最好的方法就是一次性的修改,修改后将之视为不可变的(例如:当矩阵作为函数结果被返回时,而此函数是使用可变性来实现的)。这样的话,你会在构造是得到好的性能,同时你可以保持代码的其余部分透明地引用它。

 

用序号访问矩阵元素

下面的代码展示了直接创建一个4x4的邻接矩阵的方法,此邻接矩阵来自于本文介绍部分所讨论的表示图的两个矩阵(尽管后面我们会看到一种更简单的方法来作这个):

 1: let m = Matrix.zero 4 4
 2: val m : matrix = matrix [ ... ]
 3:
 4: m.[0, 0] <- m1.[0, 0]
 5: val it : unit = ()
 6:
 7: for i in 0 .. 2 do
 8:   for j in 0 .. 2 do
 9:     m.[i+1, j+1] <- m2.[i, j]
 10: val it : unit = ()
 11:
 12: m
 13: val it : matrix = matrix [ [1.0; 0.0; 0.0; 0.0]
 14:                            [0.0; 0.0; 1.0; 1.0]
 15:                            [0.0; 1.0; 0.0; 0.0]
 16:                            [0.0; 1.0; 0.0; 1.0] ]

第一行代码创建了一个4x4大小的矩阵,矩阵的元素初始化为0.0。接下来,我们复制了矩阵m1m2(前面段落中定义的)中的内容.矩阵m1只包含了一个元素,因此我们直接赋值了。在复制m2中的元素时,我们需要使用两个嵌套的for循环。元素一旦被复制完,我们就使用F# Interactive m的值打印出来。就像你看到的一样,创建好的矩阵和在介绍部分创建的矩阵是一样的。

 

来看看另一个与直接操作矩阵元素有关的示例,让我们写些代码来返回代表此图边的一个List。这个可以通过搜索矩阵中值为1.0来完成。注意:我们只需要搜索位于对角线下方的三角形即可(包括对角线),因为此矩阵是对称的:

 1: [ for i in 0 .. 3 do
 2:     for j in 0 .. i do
 3:       if (m.[i, j] = 1.0) then
 4:         yield i, j ]
 5: val it : (int * int) list = [(0, 0); (2, 1); (3, 1); (3, 3)]

嵌套循环的上界被限制在变量i当前的值,如此我们就可以从矩阵的左边搜索到对角线。如果矩阵中的一个元素包含1.0,我们就返回指定此边的两个顶点。

在前面章节中用来复制元素而使用的嵌套循环,其实没必要这么复杂的。下面的部分展示了切割法,此方法提供了一个用来解决此问题的一个更好的方法。

 

使用切割法访问矩阵的各部分

切割法相当于目录搜索,但是却不是指定某个单独的元素,它允许我们指定一个范围。其结果是包含原矩阵部分元素的矩阵。切割法不仅仅可以被使用在读取部分矩阵上,同样也可以用来用一个矩阵来代替此矩阵的部分。

例如,删除原图中的标号为4的边,我们可以只拿原矩阵的前三列和前三行即可实现:

 1: m.[0 .. 2, 0 .. 2]
 2: val it : Matrix<float> = matrix [ [1.0; 0.0; 0.0]
 3:                                   [0.0; 0.0; 1.0]
 4:                                   [0.0; 1.0; 0.0] ]

使用切割法的语法和使用目录法来获取矩阵元素相似。唯一的区别在于需要提供一个范围,如:0 .. 2,而不是仅仅一个序号。获取切片后的结果会是一个有此切割法得到的指定的矩阵。如果我们仔细看看其结果,我们可以看到一个拥有3个顶点2条边的图,此图是通过删除原图的第四条边得到的(一条边由顶点1到顶点1,另一条则是连接顶点23)。

 

切割法同样可以被使用在修改矩阵上。下面的例子展示了一种为整副图构造邻接矩阵的一种更优雅地方式,此邻接矩阵来自此图的两个不相连的邻接矩阵。

 1: let m = Matrix.zero 4 4
 2: m.[0 .. 0, 0 .. 0] <- m1
 3: m.[1 .. 3, 1 .. 3] <- m2

在第一个赋值运算中,这个范围描述了一个大小为1x1的矩阵,在第二个赋值运算中,我们重写了这个矩阵,将之赋为3x3的大小。如果给定的范围超出了矩阵的大小,我们会得到一个异常.同时,我们也要注意m.[0,0]m.[0..0,0..0]之间有很大的区别。在第一种写法中,我们只能获取一个元素,因此这个表达式的类型是float。在第二种写法中,我们可以获取矩阵的一部分元素,这里只是碰巧只包含一个元素罢了。不过此表达式的类型仍然是matrix(矩阵)

 

矩阵之间的运算

接下来,我们会看看一些在F# PowerPack中可用的矩阵间的标准运算操作。就像创建矩阵函数一样,这里我们将要讨论的操作均位于Matrix模块中。下面的代码演示了最开始的两个操作:

 1: m = Matrix.transpose m
 2: val it : bool = true
 3:
 4: Matrix.trace m
 5: val it : float = 2.0

第一个命令测试了矩阵m的转置是否合原矩阵相同。其结果是true,因为此矩阵是对称的(至少对于无向图来说都是对称的,意思是从顶点12的边与从顶点21的边是相同的).

第二条命令用来计算所谓的矩阵的迹,即对角线上元素的和.当计算邻接矩阵时,它返回既是起点又是终点的顶点个数。在这里,其结果为2,由于在序号为[00][33]上有一个值为1.0,这就相当于有边分别从顶点11和顶点33

 

下面的例子用来计算矩阵中边的条数。如果矩阵式对称的,那就意味着一些边会出现两次。要得到不重复边的条数,我们需要计算仅位于矩阵对角线下方(或者上方)的三角形中的元素,包含对角线。下面的例子展示了如何使用标准库中的函数来实现它:

 1: m |> Matrix.mapi (fun i j value ->
 2:     if i > j then 0.0 else value)
 3:   |> Matrix.sum
 4: val it : float = 4.0

函数Matrix.mpi根据元素在矩阵中的序号以及其原始值来计算得出新值。如同其他与矩阵相关的标准函数一样,此函数将一个新创建的矩阵作为值返回。在上面的例子中,我们将位于对角线以下的元素全部替换为0。在接下来的处理步骤中,我们将新创建的矩阵中的元素全部求和,最后得到边的条数。

 接下章

原文链接:http://tomasp.net/blog/powerpack-matrix.aspx

相关文章推荐

F#与数学(II) – 在图形算法中使用矩阵(PartIII)

其他矩阵操作 我们将简单的介绍一些F# PowerPack中提供的关于矩阵的有用的函数与操作符用来总结这部分内容。下面的列表给出了一组相似函数的使用示例。 逐点操作 Matrix...

F#与数学(III) – 自定义数字类型(PartII)

交互地测试数字类型 下一步,我们将用F#交互来验证我们所写的代码到目前为止是按预期工作的。在这一点上,我们甚至没有生成库。我们仅仅写了一些F#的源代码,想不生成库来测试这些源代码。我们将使用在F#脚...

F#与数学(I) – PowerPack中的数字类型

在这篇文章中,我们将简单地看看F# PowerPack中可用的两种数字类型。Complex类型代表由实数部分和虚数部分组成的复数。两部分数字都是以浮点型数据存储的。类型BigRational表示由任意...

F#与数学(III) – 自定义数字类型(PartIII)

用全局关联来支持矩阵 我们的数字类型可以被用在一些标准的库函数如List.sum中,因为它们实现一些被List.sum必需的静态成员约束的成员。然而,这种方法对复杂的数据类型如泛型矩阵不工作。如果我...

Math.Inc 分型图形库数学函数头文件 数字函数+向量和矩阵函数+仿射变换

转自:http://www.4oa.com/Article/html/6/31/446/2005/15505.html /*分型图形库数学函数头文件*/ /*Math.Inc*/ #defi...

数学之美:平方根倒数速算法中的神奇数字 0x5f3759df

http://blog.jobbole.com/105295/?ref=myread 本文由 伯乐在线 - JLee 翻译,黄利民 校稿 英文出处:Christian ...

计算机图形学 – 椭圆的中点生成算法

对于一般位置的椭圆, 例如, 可将中心平移到坐标原点, 确定好中心在原点的标准位置的椭圆像素点集后,再平移到位置,将问题转变为标准位置的椭圆的绘制问题。    如果椭圆的长轴和短轴方向不与坐标轴x 和...

F1V3.0-图形-自动成图-系统图算法介绍

系统图自动成图

F5隐写算法中矩阵编码详解

最近一段时间都在看隐写算法,F5算法算法比较经典的一个了,花了不少时间来琢磨,对于其中的矩阵编码方法终究是难以理解,找了很多资料,基本就是说了一下公式,不胜详略,难有一个能比较说的清楚的,这里分享一下...
  • ahafg
  • ahafg
  • 2015-11-03 11:44
  • 2834
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)