【问题标题】:Multiple matrices in matlab without recursionmatlab中的多个矩阵没有递归
【发布时间】:2009-05-10 14:03:44
【问题描述】:

我必须编写一个执行此操作的 Matlab 脚本:

输入是 2 个矩阵,A(m x n) 和 D(m x 1)。输出是一个矩阵 C (m x n)。 C 是这样计算的:

function c = scanrow(a,d)
[rows columns] = size(d);
for i=1:columns
a(i,:) = a(i,:).*d(i);   
end
c = a;
end

要求不使用递归。我不知道要解决这个问题。很高兴您能提供帮助。 谢谢你。

【问题讨论】:

  • 我无法查看代码/问题的哪一部分是递归的。也许你可以澄清一下。
  • 您的意思可能是没有循环而不是没有递归。 (使用matlab中的“向量化”实现)

标签: matlab matrix


【解决方案1】:

正如仅供参考 - bsxfun + 函数句柄是对至少一个矩阵维度与一个向量维度匹配的矩阵和向量执行操作的新热点。这避免了显式的 rempat,这可能会很慢而且很浪费:

a = 1:5; b = 魔法(5); c = bsxfun(@times,a,b);

但要小心 - 这仅在相对较新的 MATLAB 版本中可用。 -皮特

【讨论】:

【解决方案2】:

如果问题是“将 A 的每一行中的每个元素与 D 的相应行中的相应元素相乘”,那么我建议如下:

dd = repmat(d, 1, size(a, 2))
c = a.*dd

例子:

>> a = [1 2; 3 4; 5 6];
>> d = [1 2 3]';
>> dd = dd = repmat(d, 1, size(a, 2))
dd = 
     1   1
     2   2
     3   3
>> a.*dd
ans =
     1   2
     6   8
     15  18

【讨论】:

    【解决方案3】:

    (我会回答,尽管这是家庭作业。我认为很多人不理解为什么创建 bsxfun。)

    乘法还有其他解决方案。典型的方法是使用 repmat、使用循环或乘以对角矩阵。如果将对角矩阵设为稀疏矩阵,则更好。但是,bsxfun 绝对是正确的解决方案。它是为解决此类问题而编写的。问题是当你做类似的事情时

    A = magic(3) + 5
    

    MATLAB 知道它必须将 5 加到 magic(3) 的每个元素上。同样,当你这样做时

    A = magic(4).*2
    

    同样,MATLAB 理解乘法将扩展到所有元素。实质上,MATLAB 在加法或乘法中将标量隐式扩展为与其伙伴大小相同的数组,然后执行运算。这是 repmat 求解器明确完成的。

    显式标量扩展的问题在于,进行该扩展需要时间和内存。所以 times 和 plus 足够聪明,可以识别出标量扩展是合适的,但实际上并没有执行显式的内存占用操作。当您尝试时,MATLAB 不知道该怎么做

    A = magic(3).*rand(1,3)
    

    过去,解决方案是使用 repmat。但是,当您使用 repmat 将向量显式扩展为矩阵时,您会占用大量内存来以向量化方式解决问题。是的,向量化在 MATLAB 中用内存换取时间是很常见的,但如果您的内存已经有限,并且您正在处理一个大问题,这可能是一件坏事。在没有必要的情况下,强制 MATLAB(和您的操作系统)移入虚拟内存是一个非常糟糕的主意。 (对于一个小问题,任何解决方案都是可以接受的。)

    因此,当您尝试将诸如 magic(3) 之类的数组乘以行向量或列向量时,MATLAB 是否应该理解它应该将向量隐式扩展为数组?或者 MATLAB 是否应该假设您犯了一个错误,并将其标记为这样?这个被称为单例维度扩展的问题就是问题所在。 (在向量中找到一个单一维度,其中一个维度是 1。)返回错误消息对许多用户来说是一个好主意,因为这通常表明发现了一个错误,一个错误。简单、自动地扩展所有单件维度以适应手头的问题似乎很危险。事实上,有很多关于如何做的讨论。例如,MATLAB 是否应该创建一个首选项,用户可以在其 MATLAB 版本中启用单例维度的扩展?这将是一个糟糕的主意,因为它会使代码无法跨系统移植。

    此外,如果将基本 MATLAB 运算符修改为始终扩展所有单例维度,则 MATLAB 代码将无法移植回旧版本。

    我们甚至讨论过创建一组全新的 MATLAB 运算符,例如 .* 与 * 并行存在,以便在扩展单例维度的同时进行运算。这也是一个糟糕的主意,应该避免。

    解决方案是创建 BSXFUN(二进制标量扩展函数),以便在需要时有效地完成此操作。在文件交换中发现了一个 bsxfun,它允许旧版本的用户获得这种行为,因此尽可能地保持可移植性。 BSXFUN 允许您对任何一对参数进行操作,在它们之间应用用户提供的函数。所以它允许你做这样的事情:

    A = rand(5,1);
    B = rand(1,3);
    C = bsxfun(@plus,A,B);
    

    创建一个由A和B中元素之和组成的5x3矩阵。您也可以使用任何函数作为第一个操作数,因此BSXFUN非常强大。

    最后,另一种看待 BSXFUN 的方式是作为外部产品的变体。因此,MATLAB 中的这个操作是完美定义的:

    A = rand(5,1);
    B = rand(1,3);
    C = A*B;
    

    但是,这些操作中的任何一个

    D = A-B;
    E = A^B;
    

    会产生错误。 BSXFUN 允许您高效地完成它们,而不会占用内存的单例维度扩展。

    D = bsxfun(@minus,A,B);
    E = bsxfun(@power,A,B);
    

    【讨论】:

    • "创建一组全新的 MATLAB 运算符,例如 .* 与 * 并行存在,以便在扩展单例维度的同时进行运算。这也是一个糟糕的主意,应该避免":我想知道为什么这是一个“糟糕”的想法
    【解决方案4】:

    也许vectorize() 是你想要的 -> Code Vectorization Guide

    【讨论】:

      【解决方案5】:

      您确定问题中包含的代码是正确的吗?这似乎是这样做的:

      我假设输入 ad 代表矩阵 A(大小 m×n)和 D你提到的strong>(大小m×1)。由于您将 d 定义为始终具有 1 列,因此 for 循环是不必要的,因为它只会循环一次。单次循环将简单地将 a 的第一行中的值乘以 d 中的第一个值。因此,问题中的整段代码可以替换为以下内容:

      c = a;
      c(1,:) = c(1,:).*d(1);
      

      【讨论】:

        猜你喜欢
        • 2016-06-13
        • 2011-12-28
        • 2018-02-13
        • 1970-01-01
        • 1970-01-01
        • 2013-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多