Julia中二维向量数组的Perculiar行为

Julia中二维向量数组的Perculiar行为,julia,Julia,我想创建二维向量的二维数组(表示向量场) 我的代码是这样的 N=10 dx=1/(N-1) dy=1/(N-1) #initial data U=fill(zeros(2), (N, N)) for i=1:1:N for j=1:1:N U[i,j][1]=(i-1)*dx U[i,j][2]=(j-1)*dy end end print(U[5, 7]) N=10 dx=1/(N-1) dy=1/(N-1) #initial data

我想创建二维向量的二维数组(表示向量场)

我的代码是这样的

N=10
dx=1/(N-1)
dy=1/(N-1)

#initial data
U=fill(zeros(2), (N, N))

for i=1:1:N
    for j=1:1:N
        U[i,j][1]=(i-1)*dx
        U[i,j][2]=(j-1)*dy
    end
end

print(U[5, 7])
N=10
dx=1/(N-1)
dy=1/(N-1)

#initial data
U=fill(zeros(2), (N, N))

for i=1:1:N
    for j=1:1:N
        U[i,j]=[(i-1)*dx, (i-1)*dx]
    end
end

print(U[5, 7])
结果是[1.0,1.0],这不是我想要的。我不知道为什么。但是,如果我把代码改成这样

N=10
dx=1/(N-1)
dy=1/(N-1)

#initial data
U=fill(zeros(2), (N, N))

for i=1:1:N
    for j=1:1:N
        U[i,j][1]=(i-1)*dx
        U[i,j][2]=(j-1)*dy
    end
end

print(U[5, 7])
N=10
dx=1/(N-1)
dy=1/(N-1)

#initial data
U=fill(zeros(2), (N, N))

for i=1:1:N
    for j=1:1:N
        U[i,j]=[(i-1)*dx, (i-1)*dx]
    end
end

print(U[5, 7])

然后打印出正确的结果,即[0.4444444444,0.66666666]。那么,到底发生了什么?

这种行为是意料之中的。注意以下几点:

julia> x = fill(zeros(1), 2)
2-element Array{Array{Float64,1},1}:
 [0.0]
 [0.0]

julia> x[1][1] = 5.0
5.0

julia> x[2][1]
5.0
我通过改变
x[1][1]
就成功地改变了
x[2][1]
。在这一点上,你大概可以猜出问题所在。您正在使用相同的向量填充矩阵的所有元素。因此,当你变异一个,你就是在变异所有

要获得您想要的行为,您可以构建如下初始矩阵:

x = [ zeros(2) for n in 1:N, m in 1:N ]

这里的关键点是考虑到你的<代码>的第一个参数是否填充< /COD>调用是,或者包含,一个可变的。如果没有,那么它将像您预期的那样工作,例如

fill(0.0,2)
。但是如果它确实包含一个可变对象,那么
fill
的输出将包含指向单个可变对象的指针,您将获得上面遇到的行为

请注意,我在这里使用“contains”一词很重要,因为包含可变对象的不可变对象仍然会导致指向单个可变对象的指针,从而导致您遇到的行为。例如:

struct T1 ; x::Vector{Float64} ; end
T1() = T1(zeros(1))
x = fill(T1(), 2)
x[1].x[1] = 5.0
x[2].x[1]

仍然变异
x的第二个元素

问题是
填充(零(2)、(N,N))
指向单个2元素向量。因此,如果更改其中一个的内容,它们都会更改:

julia> U = fill(ones(2), 2)
2-element Vector{Vector{Float64}}:
 [1.0, 1.0]
 [1.0, 1.0]

julia> U[1][1] = 2
2

julia> U
2-element Vector{Vector{Float64}}:
 [2.0, 1.0]
 [2.0, 1.0]
因此,在第一个代码片段中,您只需更改unique2元素向量的内容。检查您的
U
,它应该用
[1.0,1.0]
填充

然而,在第二个代码片段中,您在
U
的每个条目中分配了新的向量,因此您没有这个问题

一个解决方案是以不同的方式预先分配。你可以试试,例如

U = Array{Vector{Float64}}(undef, (N, N))

谢谢你的评论,但U实际上是用N^2向量[1.0,1.0]填充的,这正是我说的
U
一次又一次地被相同的
[1.0,1.0]
向量填充。噢,嗨,贝诺特,对不起,我误解了你。太好了。非常感谢。@Chunnguyen我刚把最后一段改成了一个较长的解释,因为我意识到我写的东西可能会被错误地解释。一个不相关的评论是,一般来说,
Matrix{Vector{Float64}}
将是低效的,也就是说,它会很慢,占用比需要的更多内存,并且可能会导致严重的GC延迟。最好在矩阵中存储一些不可变的结构,例如
元组{Float64,Float64}
。当然,在像您这样的小示例中,它可能不会有多大影响。为了补充Bogumil的评论,还有一个固定大小的arraya实现,名为StaticArrays.jl中的
SVector
s