ParameterSet, parameters as named tuples and constraints
Opened this issue · 1 comments
femtotrader commented
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 commented
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?