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

MilesCranmer / SymbolicRegression.jl / 13476209157

22 Feb 2025 08:12PM UTC coverage: 94.846% (-0.03%) from 94.874%
13476209157

push

github

web-flow
chore: bump version

3386 of 3570 relevant lines covered (94.85%)

30803614.18 hits per line

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

98.08
/src/RegularizedEvolution.jl
1
module RegularizedEvolutionModule
2

3
using DynamicExpressions: string_tree
4
using ..CoreModule: AbstractOptions, Dataset, RecordType, DATA_TYPE, LOSS_TYPE
5
using ..PopulationModule: Population, best_of_sample
6
using ..AdaptiveParsimonyModule: RunningSearchStatistics
7
using ..MutateModule: next_generation, crossover_generation
8
using ..RecorderModule: @recorder
9
using ..UtilsModule: argmin_fast
10

11
# Pass through the population several times, replacing the oldest
12
# with the fittest of a small subsample
13
function reg_evol_cycle(
15,677,221✔
14
    dataset::Dataset{T,L},
15
    pop::P,
16
    temperature,
17
    curmaxsize::Int,
18
    running_search_statistics::RunningSearchStatistics,
19
    options::AbstractOptions,
20
    record::RecordType,
21
)::Tuple{P,Float64} where {T<:DATA_TYPE,L<:LOSS_TYPE,P<:Population{T,L}}
22
    num_evals = 0.0
15,676,093✔
23
    n_evol_cycles = ceil(Int, pop.n / options.tournament_selection_n)
15,676,136✔
24

25
    for i in 1:n_evol_cycles
15,675,258✔
26
        if rand() > options.crossover_probability
39,166,916✔
27
            allstar = best_of_sample(pop, running_search_statistics, options)
72,110,883✔
28
            mutation_recorder = RecordType()
38,294,614✔
29
            baby, mutation_accepted, tmp_num_evals = next_generation(
38,259,084✔
30
                dataset,
31
                allstar,
32
                temperature,
33
                curmaxsize,
34
                running_search_statistics,
35
                options;
36
                tmp_recorder=mutation_recorder,
37
            )
38
            num_evals += tmp_num_evals
38,300,311✔
39

40
            if !mutation_accepted && options.skip_mutation_failures
38,300,158✔
41
                # Skip this mutation rather than replacing oldest member with unchanged member
42
                continue
13,039,174✔
43
            end
44

45
            oldest = argmin_fast([pop.members[member].birth for member in 1:(pop.n)])
25,259,470✔
46

47
            @recorder begin
25,288,217✔
48
                if !haskey(record, "mutations")
71,600✔
49
                    record["mutations"] = RecordType()
44✔
50
                end
51
                for member in [allstar, baby, pop.members[oldest]]
106,290✔
52
                    if !haskey(record["mutations"], "$(member.ref)")
214,639✔
53
                        record["mutations"]["$(member.ref)"] = RecordType(
94,010✔
54
                            "events" => Vector{RecordType}(),
55
                            "tree" => string_tree(member.tree, options),
56
                            "cost" => member.cost,
57
                            "loss" => member.loss,
58
                            "parent" => member.parent,
59
                        )
60
                    end
61
                end
214,601✔
62
                mutate_event = RecordType(
71,582✔
63
                    "type" => "mutate",
64
                    "time" => time(),
65
                    "child" => baby.ref,
66
                    "mutation" => mutation_recorder,
67
                )
68
                death_event = RecordType("type" => "death", "time" => time())
71,602✔
69

70
                # Put in random key rather than vector; otherwise there are collisions!
71
                push!(record["mutations"]["$(allstar.ref)"]["events"], mutate_event)
71,600✔
72
                push!(
71,580✔
73
                    record["mutations"]["$(pop.members[oldest].ref)"]["events"], death_event
74
                )
75
            end
76

77
            pop.members[oldest] = baby
25,269,519✔
78

79
        else # Crossover
80
            allstar1 = best_of_sample(pop, running_search_statistics, options)
1,615,378✔
81
            allstar2 = best_of_sample(pop, running_search_statistics, options)
1,615,369✔
82

83
            crossover_recorder = RecordType()
867,656✔
84
            baby1, baby2, crossover_accepted, tmp_num_evals = crossover_generation(
1,049,861✔
85
                allstar1,
86
                allstar2,
87
                dataset,
88
                curmaxsize,
89
                options;
90
                recorder=crossover_recorder,
91
            )
92
            num_evals += tmp_num_evals
867,647✔
93

94
            if !crossover_accepted && options.skip_mutation_failures
867,650✔
95
                continue
7,033✔
96
            end
97

98
            # Find the oldest members to replace:
99
            oldest1 = argmin_fast([pop.members[member].birth for member in 1:(pop.n)])
860,612✔
100
            BT = typeof(first(pop.members).birth)
860,622✔
101
            oldest2 = argmin_fast([
860,625✔
102
                i == oldest1 ? typemax(BT) : pop.members[i].birth for i in 1:(pop.n)
103
            ])
104

105
            @recorder begin
860,622✔
106
                if !haskey(record, "mutations")
3,003✔
107
                    record["mutations"] = RecordType()
×
108
                end
109
                for member in [
14,083✔
110
                    allstar1,
111
                    allstar2,
112
                    baby1,
113
                    baby2,
114
                    pop.members[oldest1],
115
                    pop.members[oldest2],
116
                ]
117
                    if !haskey(record["mutations"], "$(member.ref)")
18,018✔
118
                        record["mutations"]["$(member.ref)"] = RecordType(
6,284✔
119
                            "events" => Vector{RecordType}(),
120
                            "tree" => string_tree(member.tree, options),
121
                            "cost" => member.cost,
122
                            "loss" => member.loss,
123
                            "parent" => member.parent,
124
                        )
125
                    end
126
                end
18,014✔
127
                crossover_event = RecordType(
3,003✔
128
                    "type" => "crossover",
129
                    "time" => time(),
130
                    "parent1" => allstar1.ref,
131
                    "parent2" => allstar2.ref,
132
                    "child1" => baby1.ref,
133
                    "child2" => baby2.ref,
134
                    "details" => crossover_recorder,
135
                )
136
                death_event1 = RecordType("type" => "death", "time" => time())
3,003✔
137
                death_event2 = RecordType("type" => "death", "time" => time())
3,003✔
138

139
                push!(record["mutations"]["$(allstar1.ref)"]["events"], crossover_event)
3,003✔
140
                push!(record["mutations"]["$(allstar2.ref)"]["events"], crossover_event)
3,003✔
141
                push!(
3,003✔
142
                    record["mutations"]["$(pop.members[oldest1].ref)"]["events"],
143
                    death_event1,
144
                )
145
                push!(
3,003✔
146
                    record["mutations"]["$(pop.members[oldest2].ref)"]["events"],
147
                    death_event2,
148
                )
149
            end
150

151
            # Replace old members with new ones:
152
            pop.members[oldest1] = baby1
860,615✔
153
            pop.members[oldest2] = baby2
860,606✔
154
        end
155
    end
62,658,604✔
156

157
    return (pop, num_evals)
15,676,509✔
158
end
159

160
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

© 2026 Coveralls, Inc