-
Notifications
You must be signed in to change notification settings - Fork 3
src: add AutoSparseDI option for jacobian based on DI #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0116b4f
7e0bd01
65e26f2
78c58bc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| module SparseDIExt | ||
|
|
||
| using SparseConnectivityTracer, SparseMatrixColorings | ||
| import DifferentiationInterface as DI | ||
| import DDEBifurcationKit as DDEBK | ||
| import BifurcationKit as BK | ||
|
|
||
| coll_residual_for_di!(result, u, coll, pars) = BK.residual!(coll, result, u, pars) | ||
|
|
||
| function DDEBK.BK._generate_jacobian(coll::BK.PeriodicOrbitOCollProblem{Tprob}, | ||
| ::DDEBK.AutoSparseDI, | ||
| orbitguess, | ||
| pars; | ||
| k...) where {Tprob <: DDEBK.AbstractDDEBifurcationProblem} | ||
| backend = DI.AutoForwardDiff() | ||
| sparse_forward_backend = DI.AutoSparse( | ||
| backend; | ||
| # we use the following instead of TracerSparsityDetector | ||
| # because of searchsortedfirst in POSolution | ||
| # sparsity_detector = TracerLocalSparsityDetector(), | ||
| sparsity_detector = DI.DenseSparsityDetector(backend, atol = 1e-8), | ||
|
Comment on lines
+18
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that this makes the sparsity pattern dependent on the actual values inside the vector, which may not be a good idea?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am mostly trying to get this to work for now. Nothing of the above works... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you paste the error messages you get?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds like you're trying to detect sparsity through another differentiation operation?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, the function is not. And for ERROR: TypeError: non-boolean (SparseConnectivityTracer.GradientTracer{Int64, BitSet}) used in boolean context
Stacktrace:
[1] searchsortedfirst
@ ./sort.jl:177 [inlined]
[2] searchsortedfirst
@ ./sort.jl:290 [inlined]
[3] searchsortedfirst
@ ./sort.jl:292 [inlined]
[4] __interpolate_posolution(coll::PeriodicOrbitOCollProblem{…}, t0::SparseConnectivityTracer.GradientTracer{…}, x::Vector{…}, period::Int64)
@ BifurcationKit ~/work/prog_gd/julia/dev/dev1/bkorg/BifurcationKitGITHUB/src/periodicorbit/PeriodicOrbitCollocation.jl:1173
[5] functional_coll!(coll::PeriodicOrbitOCollProblem{…}, outc::Base.ReshapedArray{…}, uc::Base.ReshapedArray{…}, period::SparseConnectivityTracer.GradientTracer{…}, ::Tuple{…}, pars::@NamedTuple{…}, u::Vector{…})
@ DDEBifurcationKit ~/work/prog_gd/julia/dev/dev1/bkorg/DDEBifurcationKit.jl/src/periodicorbit/PeriodicOrbitCollocation.jl:70
[6] residual!(coll::PeriodicOrbitOCollProblem{…}, result::Vector{…}, u::Vector{…}, pars::@NamedTuple{…})
@ DDEBifurcationKit ~/work/prog_gd/julia/dev/dev1/bkorg/DDEBifurcationKit.jl/src/periodicorbit/PeriodicOrbitCollocation.jl:10
[7] coll_residual_for_di!
@ ~/work/prog_gd/julia/dev/dev1/bkorg/DDEBifurcationKit.jl/ext/SparseDIExt.jl:8 [inlined]There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @adrhill this is for you There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| coloring_algorithm = GreedyColoringAlgorithm(), | ||
| ) | ||
| out = copy(orbitguess) | ||
|
|
||
| jac_prep_sparse_nonallocating = DI.prepare_jacobian(coll_residual_for_di!, | ||
| out, | ||
| sparse_forward_backend, | ||
| orbitguess, | ||
| DI.Constant(coll), | ||
| DI.Constant(pars), | ||
| # strict = Val(false) | ||
| ) | ||
|
|
||
| jac_buffer = similar(sparsity_pattern(jac_prep_sparse_nonallocating), eltype(ones(length(out)))) | ||
| L1 = copy(jac_buffer) | ||
| return (DDEBK.AutoSparseDI(), | ||
| L1, | ||
| out, | ||
| jac_prep_sparse_nonallocating, | ||
| sparse_forward_backend) | ||
| end | ||
|
|
||
| function BK.jacobian(coll::BK.PeriodicOrbitOCollProblem, | ||
| J::Tuple{DDEBK.AutoSparseDI, T1, T2, T3, T4}, | ||
| x, | ||
| p) where {T1, T2, T3, T4} | ||
| L1 = J[2] | ||
| out = J[3] | ||
| jac_prep_sparse_nonallocating = J[4] | ||
| sparse_forward_backend = J[5] | ||
| DI.jacobian!(coll_residual_for_di!, | ||
| out, | ||
| L1, | ||
| jac_prep_sparse_nonallocating, | ||
| sparse_forward_backend, | ||
| x, | ||
| DI.Constant(p)) | ||
| return L1 | ||
| end | ||
|
|
||
| end # module | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| # TODO use getter from BK | ||
| _get_gauss_nodes(coll) = coll.mesh_cache.gauss_nodes | ||
|
|
||
| @views function BK.residual!(coll::PeriodicOrbitOCollProblem{Tprob}, | ||
|
|
@@ -67,7 +66,8 @@ end | |
| end | ||
| # udj = VectorOfArray([interp(mod(τ * period - d, period)) for d in _delays]) | ||
| for (ind, d) in enumerate(_delays) | ||
| udj.u[ind] .= interp(τ * period - d) | ||
| # udj.u[ind] .= interp(τ * period - d) | ||
| udj.u[ind] .= BK.__interpolate_posolution(coll, τ - d/period, u, 1) | ||
| end | ||
| __po_coll_bc!(coll, outc[:, rg[l]], ∂gj[:, l], gj[:, l], udj, pars, period * dτj, outc[:, end]) | ||
| end | ||
|
|
@@ -92,7 +92,14 @@ function BK.jacobian(coll::PeriodicOrbitOCollProblem{Tprob}, | |
| return analytical_jacobian_dde_cst(coll, x, p) | ||
| end | ||
|
|
||
| # analytical jacobian for constant DDE | ||
| """ | ||
| using DifferentiationInterface to automatically derive the sparse jacobian. | ||
| """ | ||
| struct AutoSparseDI <: BK.AbstractJacobianSparseMatrix end | ||
|
|
||
| function BK._generate_jacobian(coll::PeriodicOrbitOCollProblem{Tprob}, ::AutoSparseDI, orbitguess, pars; k...) where {Tprob <: AbstractDDEBifurcationProblem} | ||
| error("You need to import `DifferentiationInterface, SparseConnectivityTracer, SparseMatrixColorings` in order to use this jacobian") | ||
| end | ||
|
Comment on lines
+100
to
+102
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find it more idiomatic to throw a |
||
| ######################################################################################## | ||
| # analytical jacobians for constant DDE | ||
| for (fname, floquet) in ((:analytical_jacobian_dde_cst, false), | ||
|
|
@@ -171,8 +178,8 @@ for (fname, floquet) in ((:analytical_jacobian_dde_cst, false), | |
| (ρD * ∂L[l2, l] - α * L[l2, l] * ρI) * In | ||
| for (idelay, d) in enumerate(delays_v) | ||
| # find interval where t-τ/period belongs | ||
| t0 = τ * period - d | ||
| τd = mod(t0, period) / period | ||
| t0 = τ - d/period | ||
| τd = mod(t0, 1) / 1 | ||
| index_t = searchsortedfirst(mesh, τd) - 1 | ||
| @assert 1 <= index_t <= Ntst "We have index_t = $index_t, which is out of bounds for mesh of size $(length(mesh)) and τd = $τd. Please open an issue on the website of BifurcationKit.jl" | ||
|
|
||
|
|
@@ -184,6 +191,9 @@ for (fname, floquet) in ((:analytical_jacobian_dde_cst, false), | |
| Jd[idelay][_rgX, rgNy_delay .+ (l2-1)*n] .+= -α .* JacDDE.Jd[idelay] .* β | ||
| elseif ($(fname == :analytical_jacobian_dde_cst_floquetcoll) && t0 < 0) | ||
| rgNy_delay = UnitRange(1, n) .+ ((m * n) * (index_t - 1)) | ||
| # fullmesh = coll.mesh_cache.full_mesh | ||
| # index_tau = searchsortedlast(fullmesh, τd)- 2 | ||
| # rgNy_delay = UnitRange(1, n) .+ index_tau * n | ||
| Jd[_rgX, rgNy_delay .+ (l2-1)*n] .+= -α .* JacDDE.Jd[idelay] .* β | ||
| else # case analytical_jacobian_dde_cst | ||
| J[_rgX, rgNy_delay .+ (l2-1)*n] .+= -α .* JacDDE.Jd[idelay] .* β | ||
|
|
@@ -213,4 +223,4 @@ for (fname, floquet) in ((:analytical_jacobian_dde_cst, false), | |
| end # function end | ||
|
|
||
| end # begin | ||
| end # for-loop end | ||
| end # for-loop end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| using DDEBifurcationKit, LinearAlgebra, SparseArrays | ||
| using BifurcationKit | ||
| const BK = BifurcationKit | ||
| const DDEBK = DDEBifurcationKit | ||
|
|
||
| function Hutchinson(u, ud, p) | ||
| (;a,d,Δ) = p | ||
| d .* (Δ*u) .- a .* ud.u[1] .* (1 .+ u) | ||
| end | ||
|
|
||
| delaysF(par) = [1.] | ||
|
|
||
| # discretisation | ||
| Nx = 100; Lx = pi/2; | ||
| X = -Lx .+ 2Lx/Nx*(0:Nx-1) |> collect | ||
| h = 2Lx/Nx | ||
| Δ = spdiagm(0 => -2ones(Nx), 1 => ones(Nx-1), -1 => ones(Nx-1) ) / h^2; Δ[1,1]=Δ[end,end]=-1/h^2 | ||
|
|
||
| pars = (a = 0.5, d = 1, τ = 1.0, Δ = Δ, N = Nx) | ||
| x0 = zeros(Nx) | ||
|
|
||
| ################################################################################ | ||
| # case where we specify the jacobian | ||
| function JacHutchinson(u, p) | ||
| (;a,d,Δ) = p | ||
| # we compute the jacobian at the steady state | ||
| J0 = d * Δ .- a .* Diagonal(u) | ||
| J1 = -a .* Diagonal(1 .+ u) | ||
| return J0, [J1] | ||
| end | ||
|
|
||
| prob = ConstantDDEBifProblem(Hutchinson, delaysF, x0, pars, (@optic _.a); J = JacHutchinson) | ||
| optn = NewtonPar(verbose = true, eigsolver = DDE_DefaultEig()) | ||
| opts = ContinuationPar(p_max = 10., p_min = 0., newton_options = optn, ds = 0.01, detect_bifurcation = 3, nev = 5, dsmax = 0.2, n_inversion = 4) | ||
| br = continuation(prob, PALC(), opts; verbosity = 1, plot = false, normC = norminf) | ||
| ################################################################################ | ||
| # periodic orbits | ||
| using DifferentiationInterface, SparseConnectivityTracer, SparseMatrixColorings | ||
|
|
||
| br_pocoll = @time continuation( | ||
| br, 3, ContinuationPar(br.contparams; detect_bifurcation = 0, max_steps = 3, newton_options = NewtonPar(eigsolver = DDE_DefaultEig(), verbose = true), plot_every_step = 1), | ||
| PeriodicOrbitOCollProblem(20, 4; jacobian = DDEBK.AutoSparseDI()); | ||
| verbosity = 2, | ||
| # plot = true, | ||
| normC = norminf, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Compat bounds are missing