为什么加号运算符在Julia中被矢量化而不是除法运算符?
我对 Julia 很陌生,我对 Julia 中的矢量化操作很好奇。
例子:
x = [2 3 4]
y = [3 4 5]
如果我运行上面的:
x + y
我得到:
1×3 Array{Int64,2}:
5 7 9
但如果我这样做:
x/y
我得到:
1×1 Array{Float64,2}:
0.7600000000000002
我无法理解,经过一些研究,我发现 x./y 是进行矢量化操作的正确方法,但我想知道加号是如何工作的。
以下是我的问题:
这背后的直觉是什么(使加号矢量化而不是除法运算符)?
当我做 x/y 时会发生什么?为什么 .76000 会作为答案出现。
我希望这不是重复的,如果是请告诉我。我要把它去掉。首先十分感谢。请帮忙。
回答
AFAICT+操作符不会自动广播:
julia> 1 + [2, 3]
ERROR: MethodError: no method matching +(::Int64, ::Array{Int64,1})
For element-wise addition, use broadcasting with dot syntax: scalar .+ array
julia> [1 2] + [3, 4]
ERROR: DimensionMismatch("dimensions must match: a has dims (Base.OneTo(1), Base.OneTo(2)), b has dims (Base.OneTo(2),), mismatch at 1")
你必须分别写:
julia> 1 .+ [2, 3]
2-element Array{Int64,1}:
3
4
julia> [1 2] .+ [3, 4]
2×2 Array{Int64,2}:
4 5
5 6
然而,重要的是,+对于完全相同维度的数组,这是一个有效的操作(在数学意义上),这就是为什么它有效:
julia> [2 3 4] + [3 4 5]
1×3 Array{Int64,2}:
5 7 9
请注意,这不是广播,而只是线性代数。
现在关于x / y您可以检查它是否定义为:
help?> x / y
/(x, y)
Right division operator: multiplication of x by the inverse of y on the right.
所以你有了:
julia> using LinearAlgebra
julia> x * pinv(y)
1×1 Array{Float64,2}:
0.7600000000000005
(实际的实现有点不同——我在这里使用了一种简化的方法)
回答
+在任何数组上下文中都是明确的。它按元素运行,没有其他常见的解释。如果数组不是通用大小,则会引发错误。
*在矩阵上下文(二维数组)中是明确的。它指的是矩阵乘法。第一个输入的第二个维度的长度必须与第二个输入的第一个维度的长度匹配,否则会抛出错误。
但是,对于一般数组,*是不明确的。例如,如果x和y是数字向量(一维数组),那么是什么x*y意思?也许您想按元素执行操作,或者您想要内积?还是张量积?因此,*如果使用两个向量作为输入调用,则会抛出错误。请注意,这.*是明确的,因为根据广播的定义,它仅意味着逐元素乘法。
这与 有/什么关系?请注意,/是右除法运算符,即乘以x的逆或伪逆y(其中y是 的右侧x)。所以*这里的语义适用,附加约束y必须能够反转(或者,至少,Moore-Penrose 反转)。如果满足这些约束,则/是明确的并因此定义。如果他们不满意,那么/将抛出一个错误(至少,它应该):-)
此操作绝对不是按元素进行的,这就是为什么与两个向量的情况./不同的原因/。
现在,记住所有这些,以您的示例为例。首先,请注意您实际上并没有定义向量。定义了一个向量[1,2]。但是你正在做[1 2]这实际上是一个矩阵。所以操作[1 2] / [3 4]等价于[1 2] * pinv([3 4]). 伪逆在此处定义,由于[1 2]是 1x2 和pinv([3 4])2x1,结果将是 1x2 x 2x1 数组,即 1x1 矩阵,这正是您得到的。
请注意,[1,2] / [3,4]返回一个 2x2 矩阵。这也是有道理的,因为[1,2]隐式是 2x1,而pinv([3,4])1x2,所以输出将是 2x1 x 1x2 或更确切地说,是一个 2x2 矩阵。