Skip to content
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

Lazy Jacobian multiplication #81

Closed
gdalle opened this issue Apr 27, 2023 · 7 comments
Closed

Lazy Jacobian multiplication #81

gdalle opened this issue Apr 27, 2023 · 7 comments

Comments

@gdalle
Copy link
Member

gdalle commented Apr 27, 2023

I had to write this code recently for ImplicitDifferentiation.jl, and @mohamed82008 suggested it might feel at home here. Any opinions?

"""
   LazyJacobianMul!{M,N}

Callable structure wrapping a lazy Jacobian operator with `N`-dimensional inputs into an in-place multiplication for vectors.
# Fields
- `J::M`: the lazy Jacobian of the function
- `input_size::NTuple{N,Int}`: the array size of the function input
"""
struct LazyJacobianMul!{M<:LazyJacobian,N}
    J::M
    input_size::NTuple{N,Int}
end

"""
    LazyJacobianTransposeMul!{M,N}

Callable structure wrapping a lazy Jacobian operator with `N`-dimensional outputs into an in-place multiplication for vectors.
# Fields
- `J::M`: the lazy Jacobian of the function
- `output_size::NTuple{N,Int}`: the array size of the function output
"""
struct LazyJacobianTransposeMul!{M<:LazyJacobian,N}
    J::M
    output_size::NTuple{N,Int}
end

function (ljm::LazyJacobianMul!)(res::Vector, δinput_vec::Vector)
    (; J, input_size) = ljm
    δinput = reshape(δinput_vec, input_size)
    δoutput = only(J * δinput)
    return res .= vec(δoutput)
end

function (ljtm::LazyJacobianTransposeMul!)(res::Vector, δoutput_vec::Vector)
    (; J, output_size) = ljtm
    δoutput = reshape(δoutput_vec, output_size)
    δinput = only(δoutput' * J)
    return res .= vec(δinput)
end
@devmotion
Copy link
Member

Can you explain the motivation for it? I assumed that typically the main idea is to not construct the Jacobian at all but directly compute Jacobian-vector products. But here you just store the Jacobian?

@devmotion
Copy link
Member

Oh wait, it's actually a lazy operator that is stored? Then you could just define mul!, couldn't you?

@gdalle
Copy link
Member Author

gdalle commented May 24, 2023

The motivation was to use this lazy Jacobian as a LinearOperator (in the sense of LinearOperators.jl) in our package ImplicitDifferentiation.jl. It's easier to define mul! on a struct, and I needed to know the array order statically in order to write type-stable code

@gdalle
Copy link
Member Author

gdalle commented May 24, 2023

But I eventually gave up because of #83

@oxinabox
Copy link
Member

Isn't this what our lazy_jacobian function already returns?

@gdalle
Copy link
Member Author

gdalle commented Jul 26, 2023

Maybe but I needed the additional flattening step and the existence of a mul! method because of the Krylov solver we were using.

@gdalle
Copy link
Member Author

gdalle commented Oct 5, 2023

Closing in favor of #114

@gdalle gdalle closed this as completed Oct 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants