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

Adding GTPSA.jl to the interface #316

Open
mattsignorelli opened this issue Jun 10, 2024 · 15 comments · May be fixed by #329
Open

Adding GTPSA.jl to the interface #316

mattsignorelli opened this issue Jun 10, 2024 · 15 comments · May be fixed by #329
Labels
backend Related to one or more autodiff backends

Comments

@mattsignorelli
Copy link

I'll use this issue for questions I have for implementing this interface into GTPSA.jl. I've done some reading of the documentation and those AD packages in ext, and here are some of my first questions

  1. As long as I also overload value_and_gradient, value_and_jacobian, etc, is it safe to assume pushforward, value_and_pushforward only receive single variable functions?
  2. Should I basically plan to overload all of the functions here?
@gdalle
Copy link
Member

gdalle commented Jun 11, 2024

Thanks for contributing!
The documentation on writing extensions is basically non-existent, sorry for that. The reason is that I wrote all of the extensions myself, and they're not the kind of thing many people will try to touch. I'll write some more docs today and ping you.

@adrhill
Copy link
Collaborator

adrhill commented Jun 11, 2024

As long as I also overload value_and_gradient, value_and_jacobian, etc, is it safe to assume pushforward, value_and_pushforward only receive single variable functions?

For forward-mode AD, it's technically enough to only implement pushforward.
However, we recommend calling backend operators whenever possible:

While it is possible to define every operator using just pushforward and pullback, some backends have more efficient implementations of high-level operators. When they are available, we always call these backend-specific overloads.

Traits are used to indicate support for two-argument functions f!(y, x)

You might want to take a look at how overloads are handled on other backends: https://docs.juliahub.com/General/DifferentiationInterface/stable/overloads/

@gdalle
Copy link
Member

gdalle commented Jun 11, 2024

I have written a detailed dev guide in #317

@gdalle
Copy link
Member

gdalle commented Jun 11, 2024

@mattsignorelli
Copy link
Author

mattsignorelli commented Jun 14, 2024

So are the arguments x, dx, y, and dy, in pushforward always mutable structs (vectors), or can they also be scalars? I guess I need to check if the output of f is also a vector or scalar in pushforward? So there's several checks for if x isa Number etc?

@gdalle gdalle added the backend Related to one or more autodiff backends label Jun 14, 2024
@gdalle
Copy link
Member

gdalle commented Jun 14, 2024

DifferentiationInterface supports functions that take either a scalar or an array as input, and return either a scalar or an array. For some operators, like the Jacobian, there's only one possible combination (array to array). But for the pushforward, there are 4 different combinations, which you must all handle. This can be done either with checks inside the function or with multiple dispatch.

https://gdalle.github.io/DifferentiationInterface.jl/DifferentiationInterface/dev/operators/#List-of-operators

@gdalle
Copy link
Member

gdalle commented Jun 14, 2024

Note that you don't need to define the mutable version pushforward! when the output y is a number, because dy won't be mutable

@mattsignorelli
Copy link
Author

For pushforward where y=f(x) is some vector result, presumably it should return the Jacobian. However I am having trouble using similar to do so, since both x and y are vectors. If someone is using StaticArrays for example, then to produce a SizedMatrix result I would need to do

similar(y, GTPSA.numtype(eltype(y)), Size(length(y),length(x))

But Size is in StaticArrays, not in Base, and I see StaticArrays isn't a dependency of DifferentiationInterface. How should I handle this?

@gdalle
Copy link
Member

gdalle commented Jun 18, 2024

For pushforward where y=f(x) is some vector result, presumably it should return the Jacobian.

No, the pushforward is the product of the Jacobian with a given vector, also called JVP. The whole point is to avoid materializing the full matrix if you can.

If someone is using StaticArrays for example

Each operator has an in-place and an out-of-place version, so we only expect the out-of-place version to work with StaticArrays. The test package DifferentiationInterfaceTest contains a list of static_scenarios() with which you can test a backend implementation for StaticArrays compatibility. But indeed, we don't want StaticArrays as a dependency.

Perhaps I could lend a hand if you point me to your code draft?

@mattsignorelli
Copy link
Author

No, the pushforward is the product of the Jacobian with a given vector, also called JVP. The whole point is to avoid materializing the full matrix if you can.

Ah I see now, my understanding was completely wrong

Perhaps I could lend a hand if you point me to your code draft?

Sure! Here is the fork I'm working on. I have derivative, second_derivate, gradient, jacobian, hessian all implemented for onearg

@gdalle
Copy link
Member

gdalle commented Jun 18, 2024

I strongly recommend adding a test file as outlined in the docs, and running the Single/GPTSA tests regularly. That's how you're gonna catch the bugs

@mattsignorelli
Copy link
Author

Yes I will soon, I just haven't had enough time to work on this yet

@mattsignorelli
Copy link
Author

mattsignorelli commented Jun 24, 2024

OK I am having a bit of trouble and could use some help. I'm not the most familiar with how to work with extensions.

First I tried defining the AutoGTPSA type in the module in ext, but then ran into problems because exporting AutoGTPSA from DifferentiationInterface leaves AutoGTPSA undefined and weird things happened

Then I also dev-ed out ADTypes, and defined AutoGTPSA there following the other backends. This solved the first problem but now I still cannot load AutoGTPSA:

If you dev my DifferentiationInterface fork (note branch is called addgtpsa) and my ADTypes fork (branch also called addgtpsa), and then in Julia do:

julia> using DifferentiationInterface

julia> import GTPSA

julia> DifferentiationInterface.check_available(AutoGTPSA())
false

Any help is much appreciated!

@gdalle
Copy link
Member

gdalle commented Jun 24, 2024

Can you open a PR to the present repo so that I may modify it?

@mattsignorelli mattsignorelli linked a pull request Jun 24, 2024 that will close this issue
@mattsignorelli
Copy link
Author

PR opened

Here's the definition for the AutoGTPSA type:

"""
    AutoGTPSA{D}

Struct used to select the [GTPSA.jl](https://github.com/bmad-sim/GTPSA.jl) backend for automatic differentiation.

# Constructors

    AutoGTPSA(; descriptor=nothing)

# Fields

  - `descriptor::D`: can be either

      + a GTPSA `Descriptor` specifying the number of variables/parameters, parameter 
        order, individual variable/parameter truncation orders, and maximum order. See 
        [here](https://bmad-sim.github.io/GTPSA.jl/stable/man/c_descriptor/) for more details.
      + `nothing` to automatically use a `Descriptor` given the context
      
"""
Base.@kwdef struct AutoGTPSA{D} <: AbstractADType 
  descriptor::D = nothing
end

mode(::AutoGTPSA) = ForwardMode()

@gdalle gdalle linked a pull request Jun 25, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend Related to one or more autodiff backends
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants