Loren在Matlab的艺术上

将思想转化为MATLAB

MATLAB算法在R2016b中展开

我很荣幸地介绍今天的客座博主,我的同事,史蒂夫·埃丁.他已经大量参与了我们的工具中的图像处理能力,最近还有很大贡献,以便为Matlab语言设计添加和改进。

今年夏天早些时候,我在写一些颜色空间转换代码。在代码中,我有一个Px3矩阵RGB.,它包含p颜色,每行一个。我还有一个1x3矢量,V..我需要乘以每列RGB.通过相应的元素V., 像这样:

RGB_c = [RGB (: 1) * v (1) RGB (:, 2) * v (2) RGB (:, 3) * v (3)];

但由于我正在使用Matlab R2016的内部开发人员构建(9月14日发布),我没有键入上面的代码。相反,我键入了这个:

RGB_c = RGB .* v;

在R2016a和更老的MATLAB版本中,这一行代码产生了一个错误:

* v .* v .* v .* v .*错误使用.*矩阵的维数必须一致。

在新的版本中,MATLAB隐式地扩大向量V.和矩阵的大小一样RGB.然后进行元素相乘。我说“隐式”是因为MATLAB实际上没有在内存中生成扩展向量的副本。

今天我想解释这个新的MATLAB算术算子(和一些函数)的隐式展开行为。我会讲到它是如何工作的以及我们为什么这样做。在讨论的下一部分中,我将使用一个例子,几乎所有MathWorks的人在讨论这个主题时都会使用这个例子:从矩阵中减去列的意思。

内容

减去柱式意味着:十年十年

假设你有一个矩阵一种

兰德(3、3)=
A = 0.48976 0.70936 0.6797 0.44559 0.75469 0.6551 0.6551 0.6551 0.64631 0.27603 0.16261

假设你想修改。的每一列一种通过减去列的平均值。这的意思是功能方便地为您提供每个列的方法:

ma =平均值(a)
MA = 0.52722 0.58003 0.49914

但自不是同号的吗一种而不是标量,你不能只减去一种直接地。相反,你必须扩大和…一样大小一种然后做减法。

在MATLAB的前十年,专家用户通常使用一种索引技术称为托尼的伎俩做扩张。

ma_expanded = ma(3,1),:)
Ma_expanded = 0.52722 0.558003 0.49914 0.52722 0.558003 0.49914 0.52722 0.558003 0.49914
A - ma_expanded
Ans = -0.037457 0.12934 0.18057 -0.081635 0.17466 0.15596 0.11909 -0.304 -0.33653

在MATLAB的第二个十年(粗略地说),大多数人开始使用一个名为repmat(“复制矩阵”的缩写)来做扩展。

ma_expansion = repmat(ma,3,1)
Ma_expansion = 0.52722 0.558003 0.49914 0.52722 0.558003 0.49914 0.52722 0.558003 0.49914

使用函数repmat比使用《托尼的把戏》更具可读性,但它仍然在内存中创建了扩展矩阵。对于真正大的问题,额外的内存分配和内存复制可能会显著降低计算速度,甚至导致内存不足错误。

在MATLAB的第三个十年里,我们引入了一个新函数BSXFUN.这样就可以直接做减法运算,而不用在内存中展开向量。你这样称呼它:

Bsxfun(@减去,a,ma)
Ans = -0.037457 0.12934 0.18057 -0.081635 0.17466 0.15596 0.11909 -0.304 -0.33653

函数名称中的“BSX”是指“二进制单例扩展”,其中术语“二进制”中的术语“二进制”是指采用两个输入的运算符。(不,这不是任何人最喜欢的功能名称。)

这个函数工作并且已经被使用了很多次。一年前,大约有1800种用途BSXFUN.在740个文件中。

但也有人抱怨BSXFUN.

bsxfun痛苦

除了这个尴尬的名字,还有其他与之相关的可用性和性能问题BSXFUN.

  • 知道这个函数的人并不多。这一点也不明显,一个人应该去寻找帮助时,减法。
  • 使用BSXFUN.需要某种编程抽象级别(调用一个函数将另一个函数应用到一组输入),这似乎与应用程序不匹配(基本算术)。
  • 使用BSXFUN.需要相对先进的MATLAB编程知识。您必须理解函数句柄,您必须知道MATLAB算术运算符的功能等效(例如+-,Rdivide.)。
  • 这是比较困难的MATLAB执行引擎生成器生成与基本算术代码一样高效的代码。
  • 代码使用BSXFUN.不出现数学。(有些人甚至说它很丑。)

14年后克里尔最初提出这样做,我们已经改变了MATLAB的双输入算术运算符、逻辑运算符、关系运算符和几个双输入函数来做BSXFUN.样式隐式展开只要输入有兼容的大小

兼容的大小

表达方式A - B工作时间一种B.兼容的大小.如果输入的每个维度都相同,或者其中一个维度为1,那么两个数组的大小是兼容的。在最简单的情况下,如果两个数组大小完全相同,或者其中一个是标量,那么它们是兼容的。

这里有一些不同情况下兼容尺寸的插图。

  • 两个输入的大小完全相同。

  • 一个输入是标量。

  • 一个输入是一个矩阵,另一个是具有相同行数的列向量。

  • 一个输入是列向量,另一个输入是行向量。请注意,在这种情况下,两个输入都被隐式扩展,每个输入均在不同方向上。

  • 一个输入是矩阵,另一个输入是具有相同数量的行和列的3-D阵列。注意矩阵的大小一种在第三维度中隐式地认为是1,所以一种可以在第三维中扩展到尺寸相同B.

  • 一个输入是矩阵,另一个是三维数组。它们的维数都是相同的,或者其中一个是1。注意,这是两种输入都隐式展开的另一种情况。

金宝app支持的运营商和功能

这里是MATLAB算子和函数的初始集合,它们现在具有隐式展开行为。

+  - 。* ./。\。^ <<<=>> = ==〜= |&xor bitor bitrxor min max mod rem hymot atan2

我预计随着时间的推移,其他功能也会被添加到这个集合中。

反对

对MATLAB算法的这种改变在MathWorks上并非没有争议。有些人担心,用户编写的代码可能在某种程度上依赖于这些操作符,从而在某些情况下产生错误。但是在检查了我们自己的代码库,并预览了R2016a和R2016b预发布版中的更改之后,我们并没有看到在实践中出现重大的兼容性问题。

另一些人认为新的算子行为并不完全基于线性代数符号。然而,与其将MATLAB看作一个纯粹的线性代数符号,不如将MATLAB看作一个矩阵和数组计算符号更为准确。从这个意义上说,MATLAB在发明被广泛接受的符号方面有很长的历史,包括反斜杠、冒号和各种形式的下标。

最后,有些人担心当用户尝试添加两个向量时会发生什么,而不意识到一个是列,另一个是一排。在早期版本的Matlab中,这会产生错误。在R2016B中,它产生矩阵。(我喜欢称这个矩阵外和两个向量)但我们相信,这个问题很快就会被注意到,并很容易得到纠正。事实上,我认为比起错误地使用*操作符,而不是.*操作符。此外,在MATLAB中对数组大小的相对新的保护限制(Preferences -> MATLAB -> Workspace -> MATLAB数组大小限制)防止MATLAB试图形成一个可能导致内存不足的超大矩阵。

实践中的隐性扩张

在决定做这个改变之前,作为研究的一部分,我们回顾了人们的使用方式BSXFUN..我将通过展示一些最常见的用法来结束这篇文章BSXFUN.就像你在R2016b中用隐式展开重写它们一样。

给真彩色图像添加蒙版。

% mask: 480x6640 % rgb: 480x640x3
% OLD rgb2 = bsxfun(@times,rgb,mask);
% NEW rgb2 = rgb .*掩码;

归一化矩阵列(减去均值并通过偏差除以)。

%x:1000x4 mu =均值(x);sigma = std(x);
%旧y = bsxfun(@ rdivide,bsxfun(@ minus,x,mu),sigma);
% NEW Y = (X - mu) ./;

计算成对距离矩阵。

对于两组向量,计算每个向量对之间的欧氏距离。

%x:4x2(4个载体)%y:3x2(3 vectors)x = Reshape(x,[4 1 2]);Y = RESHAPE(Y,[1 3 2]);
% OLD m = bsxfun(@minus,X,Y);D =函数(m (:,: 1), m (:,: 2));
% NEW m = X - Y;D =函数(m (:,: 1), m (:,: 2));

计算外总和。

这个例子来自实施托普利兹函数。看到我2008年2月25日关于邻居索引的文章另一个应用程序。

cidx = (0: m - 1);ridx = p: 1:1;
% OLD ij = bsxfun(@plus,cidx,ridx);
%新IJ = CIDX + RIDX;

找到彼此倍数的整数。

此示例是从Redheffer矩阵的计算画廊函数。它说明了与运算符相反的函数中的隐式展开行为。

我= 1:n;
%旧的a = bsxfun(@ rem,i,i')== 0;
% NEW A = rem(i,i') == 0;

你自找的

最后,我想对所有多年来要求过这种行为的MATLAB用户喊一声。文件交换的贡献当他把这条评论包含在他的实施中时,我代表你们所有人说的提交

%我们到处都需要完整的单身扩展。为什么%% [1 2] + [0 1]''== [1 2; 2 3]?%%bsxfun()是一个全汉攻击,污染%每个人的代码。

尤瓦尔,这是给你的。

读者,你用过BSXFUN.过吗?你会使用新的算术行为吗?让我们知道在这里




发布与MATLAB®R2016B

|

评论

请点击留下评论在这里登录到你的MathWorks帐户或创建一个新的。