gpt4 book ai didi

arrays - 在嵌套函数中更新静态数组而不创建临时数组? < Julia >

转载 作者:行者123 更新时间:2023-12-04 12:17:29 25 4
gpt4 key购买 nike

我一直在用头撞墙,试图在 julia 中使用静态数组。

https://github.com/JuliaArrays/StaticArrays.jl

它们很快,但更新它们很痛苦。这并不奇怪,它们本来就是不可变的!

但是我一直建议我使用静态数组,即使我必须更新它们。就我而言,静态数组很小,只有 3 个长度,我有一个向量,但我一次只更新 1 个长度为 3 的 SVector。

选项 1

有一个非常简洁的包叫 Setfield这允许您在 Julia 中对 SVector 进行就地更新。

https://github.com/jw3126/Setfield.jl

问题...它更新了本地副本。因此,如果您在嵌套函数中,它会更新本地副本。因此它带有一些簿记,因为您必须就地更新本地副本,然后 return复制并更新感兴趣的实际数组。您无法传入所需的数组并就地更新它,至少,我无法弄清楚!现在,我不介意簿记,但我觉得更新本地副本,然后返回值,更新另一个本地副本,然后返回值并最终更新实际数组必须伴随速度损失。我可能是错的。

选项 2

让我感到困扰的是,为了更新静态数组,我必须
exampleSVector::SVector{3,Float64} <-- 只是为了说明它的类型和大小
exampleSVector = [value1, value2, value3]
即使它在函数内部,这也会更新所需的数组,这是很好的目标,但是如果您在函数内部执行此操作,则会创建一个临时数组。这让我很伤心,因为我的函数处于一个被调用 4+ 百万次的循环中,所以这会产生大量的分配并减慢速度。

我如何更新 SVector对于不创建临时数组的选项 2 场景?

对于选项 1 方案,我可以更新感兴趣的实际数组而不是本地副本吗?

如果这需要一个简单的示例代码,请在评论中说明,我会制作一个。我的想法是没有一个是可以回答的,但如果需要我会做一个。

编辑:

MCVE 代码 - 选项 1 有效,选项 2 无效。

using Setfield
using StaticArrays

struct Keep
dreaming::Vector{SVector{3,Float64}}
end

function INNER!(vec::SVector{3,Float64},pre::SVector{3,Float64})
# pretend series of calculations
for i = 1:3 # illustrate use of Setfield (used in real code for this)
pre = @set pre[i] = rand() * i * 1000
end

# more pretend calculations
x = 25.0 # assume more calculations equals x
################## OPTION 1 ########################
vec = @set vec = x * [ pre[1], pre[2], pre[3] ] # UNCOMMENT FOR FOR OPTION 1
return vec # UNCOMMENT FOR FOR OPTION 1

################## OPTION 2 ########################
#vec = x * [ pre[1], pre[2], pre[3] ] # UNCOMMENT FOR FOR OPTION 2
#nothing # UNCOMMENT FOR FOR OPTION 2

end

function OUTER!(always::Keep)
preAllocate = SVector{3}(0.0,0.0,0.0)

for i=1:length(always.dreaming)

always.dreaming[i] = INNER!(always.dreaming[i], preAllocate) # UNCOMMENT FOR FOR OPTION 1
#INNER!(always.dreaming[i], preAllocate) # UNCOMMENT FOR FOR OPTION 2
end
end
code = Keep([zero(SVector{3}) for i=1:5])

OUTER!(code)
println(code.dreaming)

最佳答案

我希望我已经正确理解了你的问题。像这样的 MWE 有点困难,它做了很多大部分是多余的和有点困惑的事情。

这里似乎有两种替代解释:要么你真的需要更新('变异')SVector ,但您的 MWE 未能证明原因。或者,您已经说服自己需要变异,但实际上并没有。

我决定专注于备选方案 2:你真的不需要“变异”。从这个角度重写你的代码可以大大简化它。

我找不到任何理由让你在这里改变任何静态向量,所以我只是删除了它。 INNER!的行为输入功能非常困惑。您提供了两个输入但不使用其中任何一个,因此我删除了这些输入。

function inner()
pre = @SVector [rand() * 1000i for i in 1:3]
x = 25
return pre .* x
end

function outer!(always::Keep)
always.dreaming .= inner.() # notice the dot in inner.()
end

code = Keep([zero(SVector{3}) for i in 1:5])
outer!(code)
display(code.dreaming)

这运行得很快并且零分配。通常对于 StaticArrays,不要尝试改变事物,只需创建新实例。

尽管您的 MWE 不清楚,但您可能想要“变异” SVector 的原因可能有一些合理的原因。 .在这种情况下,您可以使用 setindex StaticArrays 的方法,你不需要 Setfield.jl:
julia> v = rand(SVector{3})
3-element SArray{Tuple{3},Float64,1,3}:
0.4730258499237898
0.23658547518737905
0.9140206579322541

julia> v = setindex(v, -3.1, 2)
3-element SArray{Tuple{3},Float64,1,3}:
0.4730258499237898
-3.1
0.9140206579322541

澄清: setindex (没有 ! )不会改变它的输入,而是创建一个改变了一个索引值的新实例。

如果您确实需要“变异”,也许您可​​以制作一个新的 MWE 来显示这一点。我建议你尝试简化一下,因为它现在很困惑。例如,包含类型 Keep似乎完全没有必要和分心。只需做一个 VectorSVector s 并显示您想用它做什么。

编辑:这是基于以下评论的尝试。据我现在了解,问题是关于修改 SVector 的向量。 s。你不能真正改变 SVector s,但您可以使用方便的语法替换它们, setindex ,您可以在其中保留一些元素并更改其他一些元素:
oldvec = [zero(SVector{3}) for _ in 1:5]
replacevec = [rand(SVector{3}) for _ in 1:5]

现在我们替换 oldvec的每个元素的第二个元素与 replacevec 中的对应一个.首先是单线:
oldvec .= setindex.(oldvec, getindex.(replacevec, 2), 2)

然后是一个更快的循环:
for i in eachindex(oldvec, replacevec)
@inbounds oldvec[i] = setindex(oldvec[i], replacevec[i][2], 2)
end

关于arrays - 在嵌套函数中更新静态数组而不创建临时数组? < Julia >,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54726967/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com