Skip to content

feat: add ParameterIndexingProxy #26

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

Merged
merged 1 commit into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ parameter_values
set_parameter!
getp
setp
ParameterIndexingProxy
```

### State indexing
Expand Down
29 changes: 29 additions & 0 deletions docs/src/complete_sii.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,35 @@ function SymbolicIndexingInterface.set_state!(integrator::ExampleIntegrator, val
end
```

# The `ParameterIndexingProxy`

[`ParameterIndexingProxy`](@ref) is a wrapper around another type which implements the
interface and allows using [`getp`](@ref) and [`setp`](@ref) to get and set parameter
values. This allows for a cleaner interface for parameter indexing. Consider the
following example for `ExampleIntegrator`:

```julia
function Base.getproperty(obj::ExampleIntegrator, sym::Symbol)
if sym === :ps
return ParameterIndexingProxy(obj)
else
return getfield(obj, sym)
end
end
```

This enables the following API:

```julia
integrator = ExampleIntegrator([1.0, 2.0, 3.0], [4.0, 5.0], 6.0, Dict(:x => 1, :y => 2, :z => 3), Dict(:a => 1, :b => 2), :t)

integrator.ps[:a] # 4.0
getp(integrator, :a)(integrator) # functionally the same as above

integrator.ps[:b] = 3.0
setp(integrator, :b)(integrator, 3.0) # functionally the same as above
```

# Implementing the `SymbolicTypeTrait` for a type

The `SymbolicTypeTrait` is used to identify values that can act as symbolic variables. It
Expand Down
2 changes: 2 additions & 0 deletions src/SymbolicIndexingInterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ export Timeseries,
NotTimeseries, is_timeseries, state_values, set_state!, current_time, getu, setu
include("state_indexing.jl")

export ParameterIndexingProxy
include("parameter_indexing_proxy.jl")
end
19 changes: 19 additions & 0 deletions src/parameter_indexing_proxy.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""
struct ParameterIndexingProxy

This struct wraps any struct implementing the symbolic indexing interface. It allows
`getindex` and `setindex!` operations to get/set parameter values. Requires that the
wrapped type support [`getp`](@ref) and [`setp`](@ref) for getting and setting
parameter values respectively.
"""
struct ParameterIndexingProxy{T}
wrapped::T
end

function Base.getindex(p::ParameterIndexingProxy, idx)
return getp(p.wrapped, idx)(p.wrapped)
end

function Base.setindex!(p::ParameterIndexingProxy, val, idx)
return setp(p.wrapped, idx)(p.wrapped, val)
end
4 changes: 2 additions & 2 deletions test/parameter_indexing_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ for (i, sym) in [(1, :a), (2, :b), ([1, 2], [:a, :b]), ((1, 2), (:a, :b))]
get = getp(sys, sym)
set! = setp(sys, sym)
true_value = i isa Tuple ? getindex.((p,), i) : p[i]
@test get(fi) == true_value
@test get(fi) == ParameterIndexingProxy(fi)[sym] == true_value
set!(fi, 0.5 .* i)
@test get(fi) == 0.5 .* i
@test get(fi) == ParameterIndexingProxy(fi)[sym] == 0.5 .* i
set!(fi, true_value)
end