【问题标题】:1-element Array to scalar in Julia在 Julia 中标量的 1 元素数组
【发布时间】:2016-12-28 23:58:11
【问题描述】:

将行向量和列向量相乘,我期望结果是标量,但它是一维、一元素数组:

julia> [1 2 3] * [4; 5; 6]
1-element Array{Int64,1}:
 32

问题 1:这背后的基本原理是什么?

问题 2:接受这是 Julia 的一个怪癖,我想将 1 元素数组转换为标量。使用 [1] 获取第一个元素是一种选择,但可读性不强。这样做的特殊方法是什么?

【问题讨论】:

  • [1 2 3] 是一个 1x3 2D 数组。因此,将 2D 数组乘以 1D 数组会得到 1D 数组,就像矩阵乘以向量一样。正如@Chris Rackauckas 提到的,使用dot() 给出了一个标量。
  • \cdot<TAB> 将生成点运算符,它是dot(...) 的简写。因此,OP 中的表达式可以写成:vec([1 2 3])⋅[4;5;6]。注意[1 2 3] 仍然需要转为一维向量。
  • @DanGetz:你说得对,它一个二维数组......所以数组输出是有意义的。我不想使用dot,因为它需要向量,所以第一个参数需要转换,如你所说。所以高效的版本还是取矩阵乘法的第一个元素。
  • 因为我们是从美学的角度探索选项,所以通过切片创建矢量也是一种选择:[1 2 3][:]⋅[1;2;3]

标签: vector julia matrix-multiplication


【解决方案1】:

每个表达式都可以作用,所以你可以使用

([1 2 3] * [4; 5; 6])[1]

获得第一个(也是唯一的价值)。

这有几个主要的性能原因:类型稳定性。基本上,在编译语言中,如果不进行大量转换,您就无法更改类型。 Julia 更聪明一些,但如果你进行大量转换,那么你的代码会变慢,因为编译器必须保留很多“kruft”,以防万一你有错误的类型。因此,通过确保类型稳定性,编译器可以提前知道类型将是什么,并进行更多优化。这是performance tips 之一。确实,Julia 速度很快并且达到了 C 速度,因为多重调度和类型稳定性,因此应该受到尊重。

Array * Array 给出一个数组。为了使其类型稳定,它必须始终给出一个数组。否则编译器需要添加额外的代码来检查该变量是否是一个数组......在每个使用输出的地方!因此,您应该将 * 与数组一起使用以获取数组。如果你想得到一个标量,简单的答案是使用dot 函数:

dot([1;2;3],[4;5;6])

当然我可以这么说,但最好知道“为什么”,因为类型稳定性对于高性能代码来说是如此重要。

【讨论】:

  • 谢谢,这回答了问题 1。至于 Q2,我知道我可以只取第一个元素,它看起来很尴尬,所以我希望对此有一些特殊的约定。
  • dot 函数不正是那个“特殊约定”吗?它没有内联运算符,但它可以满足您的需求。如果您需要在转置向量上使用它,您可以滚动自己的函数(只是一个循环)(尽管如果 Base.dot 无法处理这个我会感到惊讶?)。请记住,在 Julia 中,循环对性能来说并不坏,因此您始终可以使用循环滚动您自己的函数。
  • 是和否 - 使用dot 我仍然需要将“行向量”转换为向量。 vec 可能没有太多开销,但它看起来仍然是多余的......我想这就是速度的代价:)
  • 我更喜欢使用[],这反过来又提醒我这是一个单元素数组。
  • FWIW,编写 dot 方法将是最快的,因为您无需分配数组即可完成。 *[1] 将分配一个大小为 1 的数组和一个数字,并且在求和时必须继续取消引用。所以我宁愿只写一个带有for循环的dot函数(因为普通点需要两个向量)(如果实际矩阵足够大,你也可以轻松地进行多线程或并行化)。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-17
  • 1970-01-01
  • 1970-01-01
  • 2019-02-19
  • 1970-01-01
相关资源
最近更新 更多