gpt4 book ai didi

julia - 是否有一个函数可以让我控制 var args 的数量?

转载 作者:行者123 更新时间:2023-12-02 20:20:02 26 4
gpt4 key购买 nike

我有以下代码:

circ(x) = x./sqrt(sum(x .* x))

x -> cat(circ(x), circ(x); dims = 1)

但我希望能够创建一个函数,在其中输入一个数字并将该数量的 circ(x) 连接起来。

例如:

function Ncircs(n)
#some way to make cat() have as its parameter circ n number of times
end

我可以调用Ncircs(2)并得到x -> cat(circ(x), circ(x); dims = 1)Ncircs(3) 并获取x -> cat(circ(x), circ(x), circ(x); dims = 1)Ncircs(4) 并获取x -> cat(circ(x), circ(x), circ(x), circ(x); dims = 1)

等等

有办法做到这一点吗?我必须使用宏吗?

最佳答案

你可以写:

Ncircs(n) = x -> cat(Iterators.repeated(circ(x), n)...; dims = 1)

如果您知道您将始终执行dims=1,则将cat替换为vcatreduce

Ncircs(n) = x -> reduce(vcat, Iterators.repeated(circ(x), n))

对于较大的n来说效率会更高。

附带说明:使用另一个选项 (vcat) 将产生类型稳定的结果,而第一个选项则不是类型稳定的。

编辑

为什么不允许减少空集合?

一般来说,原因是你无法判断减少的结果应该是什么。如果您想允许空集合,您应该添加 init 关键字参数。这是一个例子:

julia> reduce(vcat, [])
ERROR: ArgumentError: reducing over an empty collection is not allowed

julia> reduce(vcat, [], init = [1])
1-element Array{Int64,1}:
1

julia> reduce(vcat, [[2,3], [4,5]], init = [1])
5-element Array{Int64,1}:
1
2
3
4
5

结果类型稳定是什么意思

这意味着 Julia 能够在编译时(执行代码之前)判断函数返回值的类型。类型稳定的代码通常运行得更快(尽管这是一个广泛的主题 - 我建议您阅读 Julia 手册以详细了解它)。您可以使用 @code_warntypeTest.@inferred 检查函数是否类型稳定。

在这里,让我根据您的具体情况给您一个解释(我截断了一些输出以缩短答案)。

julia> x = [1,2,3]
3-element Array{Int64,1}:
1
2
3

julia> y = [4,5,6]
3-element Array{Int64,1}:
4
5
6

julia> @code_warntype vcat(x,y)
Body::Array{Int64,1}
...

julia> @code_warntype cat(x,y, dims=1)
Body::Any
...

julia> using Test

julia> @inferred vcat(x,y)
6-element Array{Int64,1}:
1
2
3
4
5
6

julia> @inferred cat(x,y, dims=1)
ERROR: return type Array{Int64,1} does not match inferred return type Any
上面的

Any 意味着编译器不知道答案的类型是什么。原因是在这种情况下,该类型取决于 dims 参数。如果是 1 则为向量,如果为 2 则为矩阵。

我怎么知道对于大的n会更有效

您可以运行@which宏:

julia> @which reduce(vcat, [[1,2,3], [4,5,6]])
reduce(::typeof(vcat), A::AbstractArray{#s72,1} where #s72<:(Union{AbstractArray{T,2}, AbstractArray{T,1}} where T)) in Base at abstractarray.jl:1321

您会看到 vcat 有一个专门的 reduce 方法。

现在如果你运行:

@edit reduce(vcat, [[1,2,3], [4,5,6]])

编辑器将打开,您会看到它调用了一个内部函数 _typed_vcat,该函数针对 vcat 优化了许多数组。引入此优化是因为使用像这样的 splatting vcat([[1,2,3], [4,5,6]]...) 在结果中是等效的,但你必须进行 splatting(...),其本身具有一些成本,可以使用 reduce 版本来避免。

为了确保我说的是真的,您可以执行以下基准测试:

julia> using BenchmarkTools

julia> y = [[i] for i in 1:10000];

julia> @benchmark vcat($y...)
BenchmarkTools.Trial:
memory estimate: 156.45 KiB
allocs estimate: 3
--------------
minimum time: 67.200 μs (0.00% GC)
median time: 77.800 μs (0.00% GC)
mean time: 102.804 μs (8.50% GC)
maximum time: 35.179 ms (99.47% GC)
--------------
samples: 10000
evals/sample: 1

julia> @benchmark reduce(vcat, $y)
BenchmarkTools.Trial:
memory estimate: 78.20 KiB
allocs estimate: 2
--------------
minimum time: 67.700 μs (0.00% GC)
median time: 69.700 μs (0.00% GC)
mean time: 82.442 μs (6.39% GC)
maximum time: 32.719 ms (99.58% GC)
--------------
samples: 10000
evals/sample: 1

julia> @benchmark cat($y..., dims=1)
ERROR: StackOverflowError:

并且您会看到 reduce 版本比 vcat 的 splatting 版本稍快,而 cat 对于非常大的 n 会失败(对于较小的n,它可以工作,但速度会更慢)。

关于julia - 是否有一个函数可以让我控制 var args 的数量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56781020/

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