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

MilesCranmer / SymbolicRegression.jl / 14803983044

02 May 2025 09:53PM UTC coverage: 95.49% (-0.03%) from 95.518%
14803983044

push

github

web-flow
ci: run docs when examples change

3409 of 3570 relevant lines covered (95.49%)

32450124.3 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(
18,410,098✔
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
18,407,889✔
23
    n_evol_cycles = ceil(Int, pop.n / options.tournament_selection_n)
18,407,914✔
24

25
    for i in 1:n_evol_cycles
18,407,429✔
26
        if rand() > options.crossover_probability
44,661,743✔
27
            allstar = best_of_sample(pop, running_search_statistics, options)
82,725,499✔
28
            mutation_recorder = RecordType()
43,646,944✔
29
            baby, mutation_accepted, tmp_num_evals = next_generation(
43,610,767✔
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
43,655,262✔
39

40
            if !mutation_accepted && options.skip_mutation_failures
43,655,068✔
41
                # Skip this mutation rather than replacing oldest member with unchanged member
42
                continue
13,340,179✔
43
            end
44

45
            oldest = argmin_fast([pop.members[member].birth for member in 1:(pop.n)])
30,316,657✔
46

47
            @recorder begin
30,345,720✔
48
                if !haskey(record, "mutations")
75,227✔
49
                    record["mutations"] = RecordType()
44✔
50
                end
51
                for member in [allstar, baby, pop.members[oldest]]
112,368✔
52
                    if !haskey(record["mutations"], "$(member.ref)")
225,495✔
53
                        record["mutations"]["$(member.ref)"] = RecordType(
98,878✔
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
225,501✔
62
                mutate_event = RecordType(
75,227✔
63
                    "type" => "mutate",
64
                    "time" => time(),
65
                    "child" => baby.ref,
66
                    "mutation" => mutation_recorder,
67
                )
68
                death_event = RecordType("type" => "death", "time" => time())
75,230✔
69

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

77
            pop.members[oldest] = baby
30,325,968✔
78

79
        else # Crossover
80
            allstar1 = best_of_sample(pop, running_search_statistics, options)
1,891,886✔
81
            allstar2 = best_of_sample(pop, running_search_statistics, options)
1,891,875✔
82

83
            crossover_recorder = RecordType()
1,006,915✔
84
            baby1, baby2, crossover_accepted, tmp_num_evals = crossover_generation(
1,251,395✔
85
                allstar1,
86
                allstar2,
87
                dataset,
88
                curmaxsize,
89
                options;
90
                recorder=crossover_recorder,
91
            )
92
            num_evals += tmp_num_evals
1,006,904✔
93

94
            if !crossover_accepted && options.skip_mutation_failures
1,006,905✔
95
                continue
8,815✔
96
            end
97

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

105
            @recorder begin
998,088✔
106
                if !haskey(record, "mutations")
2,983✔
107
                    record["mutations"] = RecordType()
×
108
                end
109
                for member in [
17,896✔
110
                    allstar1,
111
                    allstar2,
112
                    baby1,
113
                    baby2,
114
                    pop.members[oldest1],
115
                    pop.members[oldest2],
116
                ]
117
                    if !haskey(record["mutations"], "$(member.ref)")
17,898✔
118
                        record["mutations"]["$(member.ref)"] = RecordType(
6,237✔
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
17,895✔
127
                crossover_event = RecordType(
2,983✔
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())
2,983✔
137
                death_event2 = RecordType("type" => "death", "time" => time())
2,983✔
138

139
                push!(record["mutations"]["$(allstar1.ref)"]["events"], crossover_event)
2,983✔
140
                push!(record["mutations"]["$(allstar2.ref)"]["events"], crossover_event)
2,983✔
141
                push!(
2,983✔
142
                    record["mutations"]["$(pop.members[oldest1].ref)"]["events"],
143
                    death_event1,
144
                )
145
                push!(
2,983✔
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
998,086✔
153
            pop.members[oldest2] = baby2
998,068✔
154
        end
155
    end
70,914,857✔
156

157
    return (pop, num_evals)
18,410,460✔
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