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

MilesCranmer / SymbolicRegression.jl / 14392282150

10 Apr 2025 11:34PM UTC coverage: 95.424%. Remained the same
14392282150

push

github

web-flow
Merge pull request #434 from MilesCranmer/compathelper/new_version/2025-04-01-00-13-44-470-03845517700

CompatHelper: bump compat for Optim to 1, (keep existing compat)

3378 of 3540 relevant lines covered (95.42%)

31009973.69 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(
17,539,183✔
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
17,537,391✔
23
    n_evol_cycles = ceil(Int, pop.n / options.tournament_selection_n)
17,537,451✔
24

25
    for i in 1:n_evol_cycles
17,536,703✔
26
        if rand() > options.crossover_probability
42,830,506✔
27
            allstar = best_of_sample(pop, running_search_statistics, options)
79,325,015✔
28
            mutation_recorder = RecordType()
41,857,910✔
29
            baby, mutation_accepted, tmp_num_evals = next_generation(
41,816,057✔
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
41,866,301✔
39

40
            if !mutation_accepted && options.skip_mutation_failures
41,866,782✔
41
                # Skip this mutation rather than replacing oldest member with unchanged member
42
                continue
13,041,753✔
43
            end
44

45
            oldest = argmin_fast([pop.members[member].birth for member in 1:(pop.n)])
28,824,139✔
46

47
            @recorder begin
28,854,880✔
48
                if !haskey(record, "mutations")
72,846✔
49
                    record["mutations"] = RecordType()
44✔
50
                end
51
                for member in [allstar, baby, pop.members[oldest]]
106,989✔
52
                    if !haskey(record["mutations"], "$(member.ref)")
218,370✔
53
                        record["mutations"]["$(member.ref)"] = RecordType(
94,982✔
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
218,360✔
62
                mutate_event = RecordType(
72,850✔
63
                    "type" => "mutate",
64
                    "time" => time(),
65
                    "child" => baby.ref,
66
                    "mutation" => mutation_recorder,
67
                )
68
                death_event = RecordType("type" => "death", "time" => time())
72,857✔
69

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

77
            pop.members[oldest] = baby
28,836,498✔
78

79
        else # Crossover
80
            allstar1 = best_of_sample(pop, running_search_statistics, options)
1,809,657✔
81
            allstar2 = best_of_sample(pop, running_search_statistics, options)
1,809,626✔
82

83
            crossover_recorder = RecordType()
963,561✔
84
            baby1, baby2, crossover_accepted, tmp_num_evals = crossover_generation(
1,222,888✔
85
                allstar1,
86
                allstar2,
87
                dataset,
88
                curmaxsize,
89
                options;
90
                recorder=crossover_recorder,
91
            )
92
            num_evals += tmp_num_evals
963,565✔
93

94
            if !crossover_accepted && options.skip_mutation_failures
963,565✔
95
                continue
7,140✔
96
            end
97

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

105
            @recorder begin
956,428✔
106
                if !haskey(record, "mutations")
3,007✔
107
                    record["mutations"] = RecordType()
×
108
                end
109
                for member in [
14,411✔
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,041✔
118
                        record["mutations"]["$(member.ref)"] = RecordType(
6,292✔
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,036✔
127
                crossover_event = RecordType(
3,007✔
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,007✔
137
                death_event2 = RecordType("type" => "death", "time" => time())
3,007✔
138

139
                push!(record["mutations"]["$(allstar1.ref)"]["events"], crossover_event)
3,007✔
140
                push!(record["mutations"]["$(allstar2.ref)"]["events"], crossover_event)
3,006✔
141
                push!(
3,007✔
142
                    record["mutations"]["$(pop.members[oldest1].ref)"]["events"],
143
                    death_event1,
144
                )
145
                push!(
3,007✔
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
956,422✔
153
            pop.members[oldest2] = baby2
956,391✔
154
        end
155
    end
68,123,131✔
156

157
    return (pop, num_evals)
17,539,412✔
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