Stream: helpdesk (published)

Topic: Advice on signaling which part of struct to solve for?


view this post on Zulip Alec (Jun 13 2023 at 03:18):

In a rewrite of a package, part of what I'm trying to do is to define a generic interface that looks like fit(type_of_struct_to_solve_for,data) and then I use multiple dispatch to define the different logic for different combinations of arguments.

I'm trying to design for the case where type_of_struct_to_solve_for looks like:

struct Params{A,B,C}
   a::A
   b::B
  c::C
end

and C is an abstract type with three subtypes X, Y, and Z.

What I am thinking about is that fitting this object would look like:

fit(Params(1.,1.,X),data) where X is the type X instead of an initialized X(...)

I'm curious if anyone has thoughts or advice on the matter?

view this post on Zulip Michael Fiano (Jun 13 2023 at 03:40):

Alec said:

and C is an abstract type

Then Params can never be statically known in size, and performance may be an issue in some cases. Otherwise, seems fine?

view this post on Zulip Alec (Jun 13 2023 at 03:56):

Hmm, after fitting I would want to use Params in high performance contexts. After fitting I would return aParams where C is concrete for further use. Does that avoid the performance problems downstream? Or is the point you are making that fit will have to sacrifice performance as a result?

view this post on Zulip Daniel González (Jun 13 2023 at 08:14):

For performance, write

struct Params{A,B,C<:AbstractC}
    a::A
    b::B
    c::C
end

So that the type is parameterized by the concrete subtype X, Y or Z (assuming the abstract type is named AbstractC and C is just the placeholder). As for the fit function, you can dispatch on a type (with ::Type{T} where T or ::Type{Params{A, B, C} where {A, B, C}), but you can't mix values and subtypes in an instance in that way directly. I'd suggest passing a, b and C as arguments to fit and build Params there or defining an initializer structure, eg

struct ParamsInitializer{C, A, B}
    a::A
    b::B
    ParamsInitializer{C}(a::A, b::B) where {A, B, C} = new{C, A, B}(a, b)
end

and then fetch the specific subtypes in the dispatch.

view this post on Zulip Alexander (Jun 13 2023 at 08:44):

I admit I don't fully understand the usecase, but sounds generally similar to what Accessors.jl do. See AccessibleOptimization as a recent example of how it allows specifying parts of a struct to vary in fitting.

view this post on Zulip Alec (Jun 14 2023 at 14:20):

@Alexander AccessibleOptimizaiton looks awesome! I think it will provide the functionality I'm looking to expose in my package. I'm experimenting with it and have a question about nonbounded solvers. I created an issue on the repo with a MWE.


Last updated: Oct 02 2023 at 04:34 UTC