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

ParameterSet, parameters as named tuples and constraints #29

Open
femtotrader opened this issue Nov 19, 2022 · 1 comment
Open

ParameterSet, parameters as named tuples and constraints #29

femtotrader opened this issue Nov 19, 2022 · 1 comment

Comments

@femtotrader
Copy link
Collaborator

femtotrader commented Nov 19, 2022

Hello,

ParameterSet currently doesn't support constraints among parameters.

Here is a short implementation

import Base: show

const TABWIDTH = 4
const TAB = ' ' ^ TABWIDTH

mutable struct ParameterSet
    arg_names::Vector{Symbol}
    arg_defaults::Vector
    arg_ranges::Vector
    arg_types::Vector{<:Type}
    n_args::Int
    constraints::Vector
    #TODO: refactor out the arg_ prefix (its redundant if they all start with it)
    function ParameterSet(arg_names::Vector{Symbol},
                          arg_defaults::Vector,
                          arg_ranges::Vector=[x:x for x in arg_defaults];
                          constraints::Vector = [p -> true])
        @assert length(arg_names) == length(arg_defaults) == length(arg_ranges)
        @assert eltype.(arg_defaults) == eltype.(arg_ranges)
        arg_types::Vector{<:Type} = eltype.(arg_defaults)
        return new(arg_names, arg_defaults, arg_ranges, arg_types, length(arg_names), constraints)
    end
end

function generate_nt_combinations(ps::ParameterSet)
    itr = Iterators.product(ps.arg_ranges...)
    itr = Iterators.map(t -> (; zip(ps.arg_names, t)...), itr)
    for constraint in ps.constraints
        itr = Iterators.filter(constraint, itr)
    end
    collect(itr)
end

Usage:

arg_names     = [:fastlimit, :slowlimit, :x]
arg_defaults  = [0.5, 0.05, 0.01]
arg_ranges    = [0.01:0.01:1.00, 0.01:0.01:1.00, 0.01:0.01:1.00]
constraints   = [p -> p.fastlimit < p.slowlimit]
paramset      = ParameterSet(arg_names, arg_defaults, arg_ranges, constraints=constraints)
params = generate_nt_combinations(paramset)
params

returns

495000-element Vector{NamedTuple{(:fastlimit, :slowlimit, :x), Tuple{Float64, Float64, Float64}}}:
 (fastlimit = 0.01, slowlimit = 0.02, x = 0.01)
 (fastlimit = 0.01, slowlimit = 0.03, x = 0.01)
 (fastlimit = 0.02, slowlimit = 0.03, x = 0.01)
 (fastlimit = 0.01, slowlimit = 0.04, x = 0.01)
 (fastlimit = 0.02, slowlimit = 0.04, x = 0.01)
 ...
 (fastlimit = 0.96, slowlimit = 1.0, x = 1.0)
 (fastlimit = 0.97, slowlimit = 1.0, x = 1.0)
 (fastlimit = 0.98, slowlimit = 1.0, x = 1.0)
 (fastlimit = 0.99, slowlimit = 1.0, x = 1.0)

which can easily be transformed as DataFrame:

using DataFrame
DataFrame(params)

which returns

495000×3 DataFrame
    Row │ fastlimit  slowlimit  x
        │ Float64    Float64    Float64
────────┼───────────────────────────────
      1 │      0.01       0.02     0.01
      2 │      0.01       0.03     0.01
      3 │      0.02       0.03     0.01
      4 │      0.01       0.04     0.01
      5 │      0.02       0.04     0.01
      6 │      0.03       0.04     0.01
      7 │      0.01       0.05     0.01
      8 │      0.02       0.05     0.01
      9 │      0.03       0.05     0.01
     10 │      0.04       0.05     0.01
     11 │      0.01       0.06     0.01
   ⋮    │     ⋮          ⋮         ⋮
 494991 │      0.9        1.0      1.0
 494992 │      0.91       1.0      1.0
 494993 │      0.92       1.0      1.0
 494994 │      0.93       1.0      1.0
 494995 │      0.94       1.0      1.0
 494996 │      0.95       1.0      1.0
 494997 │      0.96       1.0      1.0
 494998 │      0.97       1.0      1.0
 494999 │      0.98       1.0      1.0
 495000 │      0.99       1.0      1.0
                     494979 rows omitted

Maybe it can help.

Kind regards

PS: see also #8

@dysonance
Copy link
Owner

Hey @femtotrader I think this kind of functionality does offer a lot of utility. Definitely appreciate you prototyping out an implementation. Would you mind opening a pull request integrating your proposed implementation into the package so that we can review it more holistically with test cases and examples and such?

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

2 participants