Julia 中 A\b 的就地版本是什么?
What is the inplace version of A\b in Julia?
长话短说,A\b效果不错,就是太占内存了。什么是就地选项?有就地选项吗?
我需要解决 A\b 很多问题,分配的数量给我带来了内存问题。我试过 gmres 和类似的求解器,但我没有得到准确的解决方案。我试过使用相对容差,但我的解决方案效果不佳。请注意,A 是线性运算符...如果 A 的条件不太差,并且它相当稀疏。
终于找到了。线性代数包:ldiv!
人们会认为这会更容易出现在 google 搜索中。
LinearSolve.jl is an interface over the linear solvers of the Julia ecosystem. Its interface internally uses the mutating forms (which are not just ldiv!
, but also lu!
etc. as well, which are not compatible with sparse matrices, etc.) for performance as much as possible. It connects with multiple sparse solvers, so not just the default UMFPACK, but also others like KLU and Krylov methods. It will also do other tricks that are required if you're solving a lot, like caching the symbolic factorizations, which are not necessarily well-documented. It does all of this for you by default if you use the caching interface,而这在所有具有最高性能的稀疏场景中所需要的细节基本上只需查看源代码即可得到最好的描述。所以直接用吧,或者看代码。
Using LinearSolve.jl 这种方式相当简单。例如,您只需定义并求解一个 LinearProblem:
using LinearSolve
n = 4
A = rand(n,n)
b1 = rand(n); b2 = rand(n)
prob = LinearProblem(A, b1)
linsolve = init(prob)
sol1 = solve(linsolve)
#=
4-element Vector{Float64}:
-0.9247817429364165
-0.0972021708185121
0.6839050402960025
1.8385599677530706
=#
然后你可以替换 b:
linsolve = LinearSolve.set_b(sol1.cache,b2)
sol2 = solve(linsolve)
sol2.u
#=
4-element Vector{Float64}:
1.0321556637762768
0.49724400693338083
-1.1696540870182406
-0.4998342686003478
=#
或替换A并求解:
A2 = rand(n,n)
linsolve = LinearSolve.set_A(sol2.cache,A2)
sol3 = solve(linsolve)
sol3.u
#=
4-element Vector{Float64}:
-6.793605395935224
2.8673042300837466
1.1665136934977371
-0.4097250749016653
=#
并且它会做正确的事情,即在求解这 3 个方程时它会进行两次因式分解(仅在 A
更改后进行重构)。使用 alias_A
和 alias_b
等参数可以发送以确保分配 0 内存(请参阅 common solver options)。当这是稀疏矩阵时,如果 A
保留相同的稀疏模式,则此示例将只执行一次符号分解、2 次数值分解和 3 次求解。等你明白了。
请注意,用于接口的结构是不可变的,因此在函数中,Julia 通常会使用过程间优化和逃逸分析来确定不需要它们,并将它们从生成的代码中完全消除。
长话短说,A\b效果不错,就是太占内存了。什么是就地选项?有就地选项吗?
我需要解决 A\b 很多问题,分配的数量给我带来了内存问题。我试过 gmres 和类似的求解器,但我没有得到准确的解决方案。我试过使用相对容差,但我的解决方案效果不佳。请注意,A 是线性运算符...如果 A 的条件不太差,并且它相当稀疏。
终于找到了。线性代数包:ldiv!
人们会认为这会更容易出现在 google 搜索中。
LinearSolve.jl is an interface over the linear solvers of the Julia ecosystem. Its interface internally uses the mutating forms (which are not just ldiv!
, but also lu!
etc. as well, which are not compatible with sparse matrices, etc.) for performance as much as possible. It connects with multiple sparse solvers, so not just the default UMFPACK, but also others like KLU and Krylov methods. It will also do other tricks that are required if you're solving a lot, like caching the symbolic factorizations, which are not necessarily well-documented. It does all of this for you by default if you use the caching interface,而这在所有具有最高性能的稀疏场景中所需要的细节基本上只需查看源代码即可得到最好的描述。所以直接用吧,或者看代码。
Using LinearSolve.jl 这种方式相当简单。例如,您只需定义并求解一个 LinearProblem:
using LinearSolve
n = 4
A = rand(n,n)
b1 = rand(n); b2 = rand(n)
prob = LinearProblem(A, b1)
linsolve = init(prob)
sol1 = solve(linsolve)
#=
4-element Vector{Float64}:
-0.9247817429364165
-0.0972021708185121
0.6839050402960025
1.8385599677530706
=#
然后你可以替换 b:
linsolve = LinearSolve.set_b(sol1.cache,b2)
sol2 = solve(linsolve)
sol2.u
#=
4-element Vector{Float64}:
1.0321556637762768
0.49724400693338083
-1.1696540870182406
-0.4998342686003478
=#
或替换A并求解:
A2 = rand(n,n)
linsolve = LinearSolve.set_A(sol2.cache,A2)
sol3 = solve(linsolve)
sol3.u
#=
4-element Vector{Float64}:
-6.793605395935224
2.8673042300837466
1.1665136934977371
-0.4097250749016653
=#
并且它会做正确的事情,即在求解这 3 个方程时它会进行两次因式分解(仅在 A
更改后进行重构)。使用 alias_A
和 alias_b
等参数可以发送以确保分配 0 内存(请参阅 common solver options)。当这是稀疏矩阵时,如果 A
保留相同的稀疏模式,则此示例将只执行一次符号分解、2 次数值分解和 3 次求解。等你明白了。
请注意,用于接口的结构是不可变的,因此在函数中,Julia 通常会使用过程间优化和逃逸分析来确定不需要它们,并将它们从生成的代码中完全消除。