2626
2727export krylov_workspace, krylov_solve, krylov_solve!
2828
29+ export solution, nsolution, statistics, issolved, issolved_primal, issolved_dual
30+ export niterations, Aprod, Atprod, Bprod, warm_start!, krylov_elapsed_time
31+
32+ import Base. size
33+
2934"""
3035 workspace = krylov_workspace(Val(method), args...; kwargs...)
3136
@@ -50,6 +55,79 @@ The argument `workspace` must be a subtype of [`KrylovWorkspace`](@ref) or [`Blo
5055"""
5156function krylov_solve! end
5257
58+ """
59+ solution(workspace)
60+
61+ Return the solution(s) stored in the `workspace`.
62+ Optionally you can specify which solution you want to recover,
63+ `solution(workspace, 1)` returns `x` and `solution(workspace, 2)` returns `y`.
64+ """
65+ function solution end
66+
67+ """
68+ nsolution(workspace)
69+
70+ Return the number of outputs of `solution(workspace)`.
71+ """
72+ function nsolution end
73+
74+ """
75+ statistics(workspace)
76+
77+ Return the statistics stored in the `workspace`.
78+ """
79+ function statistics end
80+
81+ """
82+ issolved(workspace)
83+
84+ Return a boolean that determines whether the Krylov method associated to `workspace` succeeded.
85+ """
86+ function issolved end
87+
88+ """
89+ niterations(workspace)
90+
91+ Return the number of iterations performed by the Krylov method associated to `workspace`.
92+ """
93+ function niterations end
94+
95+ """
96+ Aprod(workspace)
97+
98+ Return the number of operator-vector products with `A` performed by the Krylov method associated to `workspace`.
99+ """
100+ function Aprod end
101+
102+ """
103+ Atprod(workspace)
104+
105+ Return the number of operator-vector products with `A'` performed by the Krylov method associated to `workspace`.
106+ """
107+ function Atprod end
108+
109+ """
110+ krylov_elapsed_time(workspace)
111+
112+ Return the time elapsed (in seconds) during the last call to the Krylov solver associated with `workspace`.
113+ """
114+ function krylov_elapsed_time end
115+
116+ """
117+ results(workspace)
118+
119+ Return a tuple containing the solution(s) and the statistics associated with the `workspace`.
120+ Allows retrieving the output arguments of an out-of-place method from the in-place method.
121+
122+ For example, instead of `x, stats = cg(A, b)`, you can use:
123+ ```julia
124+ workspace = CgWorkspace(A, b)
125+ cg!(workspace, A, b)
126+ x, stats = results(workspace)
127+ ```
128+ """
129+ function results end
130+
53131# Krylov methods
54132for (workspace, krylov, args, def_args, optargs, def_optargs, kwargs, def_kwargs) in [
55133 (:LsmrWorkspace , :lsmr , args_lsmr , def_args_lsmr , () , () , kwargs_lsmr , def_kwargs_lsmr )
@@ -333,3 +411,129 @@ for (workspace, krylov, args, def_args, optargs, def_optargs, kwargs, def_kwargs
333411 end
334412 end
335413end
414+
415+ for (KS, fun, nsol, nA, nAt, warm_start) in [
416+ (:CarWorkspace , :car! , 1 , 1 , 0 , true )
417+ (:LsmrWorkspace , :lsmr! , 1 , 1 , 1 , false )
418+ (:CgsWorkspace , :cgs! , 1 , 2 , 0 , true )
419+ (:UsymlqWorkspace , :usymlq! , 1 , 1 , 1 , true )
420+ (:LnlqWorkspace , :lnlq! , 2 , 1 , 1 , false )
421+ (:BicgstabWorkspace , :bicgstab! , 1 , 2 , 0 , true )
422+ (:CrlsWorkspace , :crls! , 1 , 1 , 1 , false )
423+ (:LsqrWorkspace , :lsqr! , 1 , 1 , 1 , false )
424+ (:MinresWorkspace , :minres! , 1 , 1 , 0 , true )
425+ (:MinaresWorkspace , :minares! , 1 , 1 , 0 , true )
426+ (:CgneWorkspace , :cgne! , 1 , 1 , 1 , false )
427+ (:DqgmresWorkspace , :dqgmres! , 1 , 1 , 0 , true )
428+ (:SymmlqWorkspace , :symmlq! , 1 , 1 , 0 , true )
429+ (:TrimrWorkspace , :trimr! , 2 , 1 , 1 , true )
430+ (:UsymqrWorkspace , :usymqr! , 1 , 1 , 1 , true )
431+ (:BilqrWorkspace , :bilqr! , 2 , 1 , 1 , true )
432+ (:CrWorkspace , :cr! , 1 , 1 , 0 , true )
433+ (:CraigmrWorkspace , :craigmr! , 2 , 1 , 1 , false )
434+ (:TricgWorkspace , :tricg! , 2 , 1 , 1 , true )
435+ (:CraigWorkspace , :craig! , 2 , 1 , 1 , false )
436+ (:DiomWorkspace , :diom! , 1 , 1 , 0 , true )
437+ (:LslqWorkspace , :lslq! , 1 , 1 , 1 , false )
438+ (:TrilqrWorkspace , :trilqr! , 2 , 1 , 1 , true )
439+ (:CrmrWorkspace , :crmr! , 1 , 1 , 1 , false )
440+ (:CgWorkspace , :cg! , 1 , 1 , 0 , true )
441+ (:CglsWorkspace , :cgls! , 1 , 1 , 1 , false )
442+ (:CgLanczosWorkspace , :cg_lanczos! , 1 , 1 , 0 , true )
443+ (:BilqWorkspace , :bilq! , 1 , 1 , 1 , true )
444+ (:MinresQlpWorkspace , :minres_qlp! , 1 , 1 , 0 , true )
445+ (:QmrWorkspace , :qmr! , 1 , 1 , 1 , true )
446+ (:GmresWorkspace , :gmres! , 1 , 1 , 0 , true )
447+ (:FgmresWorkspace , :fgmres! , 1 , 1 , 0 , true )
448+ (:FomWorkspace , :fom! , 1 , 1 , 0 , true )
449+ (:GpmrWorkspace , :gpmr! , 2 , 1 , 0 , true )
450+ (:CgLanczosShiftWorkspace , :cg_lanczos_shift! , 1 , 1 , 0 , false )
451+ (:CglsLanczosShiftWorkspace , :cgls_lanczos_shift! , 1 , 1 , 1 , false )
452+ ]
453+ @eval begin
454+ krylov_elapsed_time (workspace :: $KS ) = workspace. stats. timer
455+ size (workspace :: $KS ) = workspace. m, workspace. n
456+ statistics (workspace :: $KS ) = workspace. stats
457+ niterations (workspace :: $KS ) = workspace. stats. niter
458+ Aprod (workspace :: $KS ) = $ nA * workspace. stats. niter
459+ Atprod (workspace :: $KS ) = $ nAt * workspace. stats. niter
460+ if $ KS == GpmrWorkspace
461+ Bprod (workspace :: $KS ) = workspace. stats. niter
462+ end
463+ nsolution (workspace :: $KS ) = $ nsol
464+ if $ nsol == 1
465+ solution (workspace :: $KS ) = workspace. x
466+ solution (workspace :: $KS , p :: Integer ) = (p == 1 ) ? solution (workspace) : error (" solution(workspace) has only one output." )
467+ results (workspace :: $KS ) = (workspace. x, workspace. stats)
468+ end
469+ if $ nsol == 2
470+ solution (workspace :: $KS ) = (workspace. x, workspace. y)
471+ solution (workspace :: $KS , p :: Integer ) = (1 ≤ p ≤ 2 ) ? solution (workspace)[p] : error (" solution(workspace) has only two outputs." )
472+ results (workspace :: $KS ) = (workspace. x, workspace. y, workspace. stats)
473+ end
474+ if $ KS ∈ (BilqrWorkspace, TrilqrWorkspace)
475+ issolved_primal (workspace :: $KS ) = workspace. stats. solved_primal
476+ issolved_dual (workspace :: $KS ) = workspace. stats. solved_dual
477+ issolved (workspace :: $KS ) = issolved_primal (workspace) && issolved_dual (workspace)
478+ else
479+ issolved (workspace :: $KS ) = workspace. stats. solved
480+ end
481+ if $ warm_start
482+ if $ KS in (BilqrWorkspace, TrilqrWorkspace, TricgWorkspace, TrimrWorkspace, GpmrWorkspace)
483+ function warm_start! (workspace :: $KS , x0, y0)
484+ length (x0) == workspace. n || error (" x0 should have size $n " )
485+ length (y0) == workspace. m || error (" y0 should have size $m " )
486+ S = typeof (workspace. x)
487+ allocate_if (true , workspace, :Δx , S, workspace. x) # The length of Δx is n
488+ allocate_if (true , workspace, :Δy , S, workspace. y) # The length of Δy is m
489+ kcopy! (workspace. n, workspace. Δx, x0)
490+ kcopy! (workspace. m, workspace. Δy, y0)
491+ workspace. warm_start = true
492+ return workspace
493+ end
494+ else
495+ function warm_start! (workspace :: $KS , x0)
496+ S = typeof (workspace. x)
497+ length (x0) == workspace. n || error (" x0 should have size $n " )
498+ allocate_if (true , workspace, :Δx , S, workspace. x) # The length of Δx is n
499+ kcopy! (workspace. n, workspace. Δx, x0)
500+ workspace. warm_start = true
501+ return workspace
502+ end
503+ end
504+ end
505+ end
506+ end
507+
508+ for (KS, fun, nsol, nA, nAt, warm_start) in [
509+ (:BlockMinresWorkspace , :block_minres! , 1 , 1 , 0 , true )
510+ (:BlockGmresWorkspace , :block_gmres! , 1 , 1 , 0 , true )
511+ ]
512+ @eval begin
513+ krylov_elapsed_time (workspace :: $KS ) = workspace. stats. timer
514+ size (workspace :: $KS ) = workspace. m, workspace. n
515+ nrhs (workspace :: $KS ) = workspace. p
516+ statistics (workspace :: $KS ) = workspace. stats
517+ niterations (workspace :: $KS ) = workspace. stats. niter
518+ Aprod (workspace :: $KS ) = $ nA * workspace. stats. niter
519+ Atprod (workspace :: $KS ) = $ nAt * workspace. stats. niter
520+ nsolution (workspace :: $KS ) = $ nsol
521+ if $ nsol == 1
522+ solution (workspace :: $KS ) = workspace. X
523+ solution (workspace :: $KS , p :: Integer ) = (p == 1 ) ? solution (workspace) : error (" solution(workspace) has only one output." )
524+ results (workspace :: $KS ) = (workspace. X, workspace. stats)
525+ end
526+ issolved (workspace :: $KS ) = workspace. stats. solved
527+ if $ warm_start
528+ function warm_start! (workspace :: $KS , X0)
529+ n2, p2 = size (X0)
530+ SM = typeof (workspace. X)
531+ (workspace. n == n2 && workspace. p == p2) || error (" X0 should have size ($n , $p )" )
532+ allocate_if (true , workspace, :ΔX , SM, workspace. n, workspace. p)
533+ copyto! (workspace. ΔX, X0)
534+ workspace. warm_start = true
535+ return workspace
536+ end
537+ end
538+ end
539+ end
0 commit comments