19.2广播

广播是指当Octave二进制运算符和函数的矩阵或数组操作数或自变量大小不同时,它们的行为方式。自3.6.0版本以来,Octave现在在使用元素二进制运算符和函数时自动广播向量、矩阵和数组。从广义上讲,较小的数组在较大的数组中“广播”,直到它们具有兼容的形状。规则是,相应的雷维度必须

  1. 相等,或
  2. 其中一个必须是1。

在所有维度相等的情况下,不发生广播,并通过元素算术进行排序。对于较高维度的数组,如果维度的数量不相同,则丢失的尾部维度将被视为1。当其中一个维度为1时,具有该奇异维度的数组将沿着该维度进行复制,直到它与另一个数组的维度匹配。例如,考虑

x = [1 2 3;
     4 5 6;
     7 8 9];

y = [10 20 30];

x + y

在没有广播的情况下,x + y这将是一个错误,因为尺寸不一致。然而,在广播中,似乎执行了以下操作:

x = [1 2 3
     4 5 6
     7 8 9];

y = [10 20 30
     10 20 30
     10 20 30];

x + y
⇒    11   22   33
      14   25   36
      17   28   39

也就是说,较小的数组大小[1 3]沿ngleton维度(行数)复制,直到[3 3]。然而,没有实际的复制发生。内部实现沿着必要的维度重用元素,以便在不复制内存的情况下实现所需的效果。

两个数组都可以在彼此之间广播,例如,向量的元素与其自身的所有成对差异:

y - y'
⇒    0   10   20
    -10    0   10
    -20  -10    0

这里是大小的向量[1 3][3 1]两者都获取广播到大小的矩阵中[3 3]在普通的矩阵分解发生之前。

可能熟悉的广播的一个特殊情况是,当正在广播的数组的所有维度都是1时,即,数组是向量。因此,例如,像这样的操作x - 42max (x, 2)是广播的基本例子。

对于更高维的示例,假设img是大小的RGB图像[m n 3]我们希望将每种颜色乘以一个不同的标量。以下代码通过广播来实现这一点,

img .*= permute ([0.8, 0.9, 1.2], [1, 3, 2]);

请注意使用permute来匹配的尺寸[0.8, 0.9, 1.2]向量带有img.

对于没有用广播语义编写的函数,bsxfun可以用于强制他们进行广播。

 
: C = bsxfun (f, A, B)

应用二进制函数f按元素到两个数组参数AB,根据需要扩展任一输入参数中的奇异维度。

f是一个函数句柄、内联函数或字符串,其中包含要计算的函数的名称。函数f必须能够接受两个相等长度的列向量参数,或者一个标量列向量参数。

的尺寸AB必须相等或为singleton。数组的单个维度将扩展到与其他数组相同的维度。

详见: arrayfun, cellfun.

广告

只有当两个广播条件中的任何一个成立时,才应用广播。然而,与往常一样,当两个维度不同且都不是1:

x = [1 2 3
     4 5 6];
y = [10 20
     30 40];
x + y

这将返回关于不一致参数的错误。

除了常见的算术运算外,两个自变量的几个函数也会广播。广播的函数和运算符的完整列表

      plus      +
      minus     -
      times     .*
      rdivide   ./
      ldivide   .\
      power     .^
      lt        <
      le        <=
      eq        ==
      gt        >
      ge        >=
      ne        !=  ~=
      and       &
      or        |
      atan2
      hypot
      max
      min
      mod
      rem
      xor

      +=  -=  .*=  ./=  .\=  .^=  &=  |=

这是广播力量的一个真实例子。Floyd-Warshall算法用于计算图中每对顶点之间的最短路径长度。序图邻接矩阵的一个简单实现n可能看起来是这样的:

for k = 1:n
  for i = 1:n
    for j = 1:n
      dist(i,j) = min (dist(i,j), dist(i,k) + dist(k,j));
    endfor
  endfor
endfor

对最里面的循环进行向量化后,它可能看起来像这样:

for k = 1:n
  for i = 1:n
    dist(i,:) = min (dist(i,:), dist(i,k) + dist(k,:));
  endfor
endfor

使用双向广播,看起来是这样的:

for k = 1:n
  dist = min (dist, dist(:,k) + dist(k,:));
endfor

对于具有100个顶点的给定图,这三种技术的相对时间性能对于初始代码为7.3秒,对于向量化代码为87毫秒,对于完全广播代码为1.3毫秒。对于一个有1000个顶点的图,向量化需要11.7秒,而广播只需要1.15秒。因此,一般来说,编写具有广播语义的代码以提高性能是值得的。

然而,如果一个更简单的操作就足够了,请注意不要求助于广播。对于矩阵ab,请考虑以下内容:

c = sum (permute (a, [1, 3, 2]) .* permute (b, [3, 2, 1]), 3);

该操作在按元素相乘期间广播具有排列维度的两个矩阵,以获得更大的三维数组,然后沿第三维度对该数组求和。只要想一想,就会证明这个运算就是最简单的普通矩阵乘法,c = a*b;.

术语注释:“广播”是Numpy数值环境在Python编程语言中推广的术语。在其他编程语言和环境中,广播也可能是已知的二进制奇异展开(BSX,在MATLAB,以及的名称的起源bsxfun作用回收(R编程语言),单指令多数据(SIMD),或复制.

19.2.1广播和遗留代码

新的广播语义几乎从不影响Octave以前版本中的代码。因此,从继承的所有代码MATLAB在之前版本的Octave中有效的应该仍然有效,而不会更改Octave。唯一的例外是以下代码

try
  c = a.*b;
catch
  c = a.*a;
end_try_catch

这可能依赖于返回误差的不同大小的矩阵。因为这样的操作现在是有效的Octave语法,所以这不会再导致错误。相反,应使用以下代码:

if (isequal (size (a), size (b)))
  c = a .* b;
else
  c = a .* a;
endif

版权所有 © 2024-2025 Octave中文网

ICP备案/许可证号:黑ICP备2024030411号-2