• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MilesCranmer / SymbolicRegression.jl / 9686354911

26 Jun 2024 08:31PM UTC coverage: 93.22% (-1.4%) from 94.617%
9686354911

Pull #326

github

web-flow
Merge 6f8229c9f into ceddaa424
Pull Request #326: BREAKING: Change expression types to `DynamicExpressions.Expression` (from `DynamicExpressions.Node`)

275 of 296 new or added lines in 17 files covered. (92.91%)

34 existing lines in 5 files now uncovered.

2530 of 2714 relevant lines covered (93.22%)

32081968.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.0
/src/PopMember.jl
1
module PopMemberModule
2

3
using DispatchDoctor: @unstable
4
using DynamicExpressions:
5
    AbstractExpression,
6
    AbstractExpressionNode,
7
    copy_node,
8
    count_nodes,
9
    parse_expression,
10
    string_tree
11
using ..CoreModule: Options, Dataset, DATA_TYPE, LOSS_TYPE, create_expression
12
import ..ComplexityModule: compute_complexity
13
using ..UtilsModule: get_birth_order
14
using ..LossFunctionsModule: score_func
15

16
# Define a member of population by equation, score, and age
17
mutable struct PopMember{T<:DATA_TYPE,L<:LOSS_TYPE,N<:AbstractExpression{T}}
18
    tree::N
72,009,455✔
19
    score::L  # Inludes complexity penalty, normalization
20
    loss::L  # Raw loss
21
    birth::Int
22
    complexity::Int
23

24
    # For recording history:
25
    ref::Int
26
    parent::Int
27
end
28
function Base.setproperty!(member::PopMember, field::Symbol, value)
7,428,815✔
29
    field == :complexity && throw(
7,851,036✔
30
        error("Don't set `.complexity` directly. Use `recompute_complexity!` instead.")
31
    )
32
    field == :tree && setfield!(member, :complexity, -1)
7,850,487✔
33
    return setfield!(member, field, value)
7,877,378✔
34
end
35
@unstable @inline function Base.getproperty(member::PopMember, field::Symbol)
5,124,926,278✔
36
    field == :complexity && throw(
5,840,974,012✔
37
        error("Don't access `.complexity` directly. Use `compute_complexity` instead.")
38
    )
39
    return getfield(member, field)
7,019,862,328✔
40
end
41
function Base.show(io::IO, p::PopMember{T,L,N}) where {T,L,N}
12✔
42
    shower(x) = sprint(show, x)
36✔
43
    print(io, "PopMember(")
12✔
44
    print(io, "tree = (", string_tree(p.tree), "), ")
18✔
45
    print(io, "loss = ", shower(p.loss), ", ")
12✔
46
    print(io, "score = ", shower(p.score))
12✔
47
    print(io, ")")
12✔
48
    return nothing
12✔
49
end
50

51
generate_reference() = abs(rand(Int))
68,990,291✔
52

53
"""
54
    PopMember(t::AbstractExpression{T}, score::L, loss::L)
55

56
Create a population member with a birth date at the current time.
57
The type of the `Node` may be different from the type of the score
58
and loss.
59

60
# Arguments
61

62
- `t::AbstractExpression{T}`: The tree for the population member.
63
- `score::L`: The score (normalized to a baseline, and offset by a complexity penalty)
64
- `loss::L`: The raw loss to assign.
65
"""
66
function PopMember(
122,091,650✔
67
    t::AbstractExpression{T},
68
    score::L,
69
    loss::L,
70
    options::Union{Options,Nothing}=nothing,
71
    complexity::Union{Int,Nothing}=nothing;
72
    ref::Int=-1,
73
    parent::Int=-1,
74
    deterministic=nothing,
75
) where {T<:DATA_TYPE,L<:LOSS_TYPE}
76
    if ref == -1
79,749,648✔
77
        ref = generate_reference()
67,087,940✔
78
    end
79
    if !(deterministic isa Bool)
67,208,771✔
NEW
80
        throw(
×
81
            ArgumentError(
82
                "You must declare `deterministic` as `true` or `false`, it cannot be left undefined.",
83
            ),
84
        )
85
    end
86
    complexity = complexity === nothing ? -1 : complexity
67,138,468✔
87
    return PopMember{T,L,typeof(t)}(
67,207,117✔
88
        t,
89
        score,
90
        loss,
91
        get_birth_order(; deterministic=deterministic),
92
        complexity,
93
        ref,
94
        parent,
95
    )
96
end
97

98
"""
99
    PopMember(
100
        dataset::Dataset{T,L},
101
        t::AbstractExpression{T},
102
        options::Options
103
    )
104

105
Create a population member with a birth date at the current time.
106
Automatically compute the score for this tree.
107

108
# Arguments
109

110
- `dataset::Dataset{T,L}`: The dataset to evaluate the tree on.
111
- `t::AbstractExpression{T}`: The tree for the population member.
112
- `options::Options`: What options to use.
113
"""
114
function PopMember(
1,020,752✔
115
    dataset::Dataset{T,L},
116
    tree::Union{AbstractExpressionNode{T},AbstractExpression{T}},
117
    options::Options,
118
    complexity::Union{Int,Nothing}=nothing;
119
    ref::Int=-1,
120
    parent::Int=-1,
121
    deterministic=nothing,
122
) where {T<:DATA_TYPE,L<:LOSS_TYPE}
123
    ex = create_expression(tree, options, dataset)
933,186✔
124
    set_complexity = complexity === nothing ? compute_complexity(ex, options) : complexity
596,284✔
125
    @assert set_complexity != -1
509,881✔
126
    score, loss = score_func(dataset, ex, options; complexity=set_complexity)
760,522✔
127
    return PopMember(
509,756✔
128
        ex,
129
        score,
130
        loss,
131
        options,
132
        set_complexity;
133
        ref=ref,
134
        parent=parent,
135
        deterministic=deterministic,
136
    )
137
end
138

139
function Base.copy(p::P) where {P<:PopMember}
3,432,551✔
140
    tree = copy(p.tree)
7,192,443✔
141
    score = copy(p.score)
4,795,622✔
142
    loss = copy(p.loss)
4,792,647✔
143
    birth = copy(p.birth)
4,795,533✔
144
    complexity = copy(getfield(p, :complexity))
4,798,283✔
145
    ref = copy(p.ref)
4,799,868✔
146
    parent = copy(p.parent)
4,799,250✔
147
    return P(tree, score, loss, birth, complexity, ref, parent)
4,800,837✔
148
end
149

150
function reset_birth!(p::PopMember; deterministic::Bool)
122,621✔
151
    p.birth = get_birth_order(; deterministic)
157,790✔
152
    return p
67,332✔
153
end
154

155
# Can read off complexity directly from pop members
156
function compute_complexity(
2,297,459,257✔
157
    member::PopMember, options::Options; break_sharing=Val(false)
158
)::Int
159
    complexity = getfield(member, :complexity)
1,735,210,226✔
160
    complexity == -1 && return recompute_complexity!(member, options; break_sharing)
1,273,929,719✔
161
    # TODO: Turn this into a warning, and then return normal compute_complexity instead.
162
    return complexity
1,267,303,057✔
163
end
164
function recompute_complexity!(
7,345,864✔
165
    member::PopMember, options::Options; break_sharing=Val(false)
166
)::Int
167
    complexity = compute_complexity(member.tree, options; break_sharing)
5,527,305✔
168
    setfield!(member, :complexity, complexity)
4,045,726✔
169
    return complexity
4,038,032✔
170
end
171

172
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc