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

MilesCranmer / SymbolicRegression.jl / 11204590927

06 Oct 2024 07:29PM UTC coverage: 95.808% (+1.2%) from 94.617%
11204590927

Pull #326

github

web-flow
Merge e2b369ea7 into 8f67533b9
Pull Request #326: BREAKING: Change expression types to `DynamicExpressions.Expression` (from `DynamicExpressions.Node`)

466 of 482 new or added lines in 24 files covered. (96.68%)

1 existing line in 1 file now uncovered.

2651 of 2767 relevant lines covered (95.81%)

73863189.31 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: AbstractExpression, AbstractExpressionNode, string_tree
5
using ..CoreModule: Options, Dataset, DATA_TYPE, LOSS_TYPE, create_expression
6
import ..ComplexityModule: compute_complexity
7
using ..UtilsModule: get_birth_order
8
using ..LossFunctionsModule: score_func
9

10
# Define a member of population by equation, score, and age
11
mutable struct PopMember{T<:DATA_TYPE,L<:LOSS_TYPE,N<:AbstractExpression{T}}
12
    tree::N
99,316,238✔
13
    score::L  # Inludes complexity penalty, normalization
14
    loss::L  # Raw loss
15
    birth::Int
16
    complexity::Int
17

18
    # For recording history:
19
    ref::Int
20
    parent::Int
21
end
22
function Base.setproperty!(member::PopMember, field::Symbol, value)
6,696,350✔
23
    field == :complexity && throw(
6,860,151✔
24
        error("Don't set `.complexity` directly. Use `recompute_complexity!` instead.")
25
    )
26
    field == :tree && setfield!(member, :complexity, -1)
6,859,480✔
27
    return setfield!(member, field, value)
6,876,795✔
28
end
29
@unstable @inline function Base.getproperty(member::PopMember, field::Symbol)
4,862,765,976✔
30
    field == :complexity && throw(
5,517,052,263✔
31
        error("Don't access `.complexity` directly. Use `compute_complexity` instead.")
32
    )
33
    return getfield(member, field)
7,048,007,031✔
34
end
35
function Base.show(io::IO, p::PopMember{T,L,N}) where {T,L,N}
18✔
36
    shower(x) = sprint(show, x)
54✔
37
    print(io, "PopMember(")
18✔
38
    print(io, "tree = (", string_tree(p.tree), "), ")
27✔
39
    print(io, "loss = ", shower(p.loss), ", ")
18✔
40
    print(io, "score = ", shower(p.score))
18✔
41
    print(io, ")")
18✔
42
    return nothing
18✔
43
end
44

45
generate_reference() = abs(rand(Int))
94,859,412✔
46

47
"""
48
    PopMember(t::AbstractExpression{T}, score::L, loss::L)
49

50
Create a population member with a birth date at the current time.
51
The type of the `Node` may be different from the type of the score
52
and loss.
53

54
# Arguments
55

56
- `t::AbstractExpression{T}`: The tree for the population member.
57
- `score::L`: The score (normalized to a baseline, and offset by a complexity penalty)
58
- `loss::L`: The raw loss to assign.
59
"""
60
function PopMember(
174,407,196✔
61
    t::AbstractExpression{T},
62
    score::L,
63
    loss::L,
64
    options::Union{Options,Nothing}=nothing,
65
    complexity::Union{Int,Nothing}=nothing;
66
    ref::Int=-1,
67
    parent::Int=-1,
68
    deterministic=nothing,
69
) where {T<:DATA_TYPE,L<:LOSS_TYPE}
70
    if ref == -1
105,473,481✔
71
        ref = generate_reference()
92,934,906✔
72
    end
73
    if !(deterministic isa Bool)
93,129,085✔
NEW
74
        throw(
×
75
            ArgumentError(
76
                "You must declare `deterministic` as `true` or `false`, it cannot be left undefined.",
77
            ),
78
        )
79
    end
80
    complexity = complexity === nothing ? -1 : complexity
93,055,606✔
81
    return PopMember{T,L,typeof(t)}(
93,124,855✔
82
        t,
83
        score,
84
        loss,
85
        get_birth_order(; deterministic=deterministic),
86
        complexity,
87
        ref,
88
        parent,
89
    )
90
end
91

92
"""
93
    PopMember(
94
        dataset::Dataset{T,L},
95
        t::AbstractExpression{T},
96
        options::Options
97
    )
98

99
Create a population member with a birth date at the current time.
100
Automatically compute the score for this tree.
101

102
# Arguments
103

104
- `dataset::Dataset{T,L}`: The dataset to evaluate the tree on.
105
- `t::AbstractExpression{T}`: The tree for the population member.
106
- `options::Options`: What options to use.
107
"""
108
function PopMember(
996,595✔
109
    dataset::Dataset{T,L},
110
    tree::Union{AbstractExpressionNode{T},AbstractExpression{T}},
111
    options::Options,
112
    complexity::Union{Int,Nothing}=nothing;
113
    ref::Int=-1,
114
    parent::Int=-1,
115
    deterministic=nothing,
116
) where {T<:DATA_TYPE,L<:LOSS_TYPE}
117
    ex = create_expression(tree, options, dataset)
667,502✔
118
    set_complexity = complexity === nothing ? compute_complexity(ex, options) : complexity
572,681✔
119
    @assert set_complexity != -1
497,802✔
120
    score, loss = score_func(dataset, ex, options; complexity=set_complexity)
748,734✔
121
    return PopMember(
497,718✔
122
        ex,
123
        score,
124
        loss,
125
        options,
126
        set_complexity;
127
        ref=ref,
128
        parent=parent,
129
        deterministic=deterministic,
130
    )
131
end
132

133
function Base.copy(p::P) where {P<:PopMember}
5,154,865✔
134
    tree = copy(p.tree)
9,370,093✔
135
    score = copy(p.score)
6,180,567✔
136
    loss = copy(p.loss)
6,179,433✔
137
    birth = copy(p.birth)
6,180,664✔
138
    complexity = copy(getfield(p, :complexity))
6,181,764✔
139
    ref = copy(p.ref)
6,182,297✔
140
    parent = copy(p.parent)
6,182,627✔
141
    return P(tree, score, loss, birth, complexity, ref, parent)
6,183,013✔
142
end
143

144
function reset_birth!(p::PopMember; deterministic::Bool)
111,620✔
145
    p.birth = get_birth_order(; deterministic)
126,970✔
146
    return p
56,026✔
147
end
148

149
# Can read off complexity directly from pop members
150
function compute_complexity(
4,602,296,893✔
151
    member::PopMember, options::Options; break_sharing=Val(false)
152
)::Int
153
    complexity = getfield(member, :complexity)
4,846,469,040✔
154
    complexity == -1 && return recompute_complexity!(member, options; break_sharing)
4,216,873,791✔
155
    # TODO: Turn this into a warning, and then return normal compute_complexity instead.
156
    return complexity
4,213,111,357✔
157
end
158
function recompute_complexity!(
5,307,484✔
159
    member::PopMember, options::Options; break_sharing=Val(false)
160
)::Int
161
    complexity = compute_complexity(member.tree, options; break_sharing)
3,765,945✔
162
    setfield!(member, :complexity, complexity)
2,902,362✔
163
    return complexity
2,894,644✔
164
end
165

166
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