R/mies_methods.R
mies_aggregate_single_generation.Rd
Applies a fitness_aggregator
function to the values that were alive in the archive at a given generation.
The function is supplied with the fitness values, and optionally other data, of all individuals that are alive at that point.
mies_aggregate_single_generation(
archive,
fitness_aggregator,
generation = NA,
include_previous_generations = FALSE
)
(Archive
)
The archive over which to aggregate.
(function
)
Aggregation function, called with information about alive individuals of each generation. See details.
(numeric(1)
)
Generation for which to aggregate the value.
If include_previous_generations
is FALSE
, then an individual is considered to be alive at generation i
if its dob
is smaller or equal to i
, and
if its eol
is either NA
or greater than i
. If include_previous_generations
is TRUE
, then all individuals with dob
smaller or equal to i
are
considered.
If this is NA
, the currently alive (include_previous_generations
FALSE
) or all (include_previous_generations
TRUE
) individuals are aggregated.
If multiple individuals considered "alive" with the same x_id
are found, then only the last individual is used.
This excludes previous individuals that were re-evaluated with a different fidelity.
(logical(1)
)
Aggregate all individuals that were alive at generation
or at any point before that.
Duplicates with the same x_id
are removed, meaning that if an individual was re-evaluated with different fidelity, only the last
re-evaluation is counted.
However, note that individuals from different generations may still have been evaluated with different fidelity, so if
Default FALSE
.
The value returned by fitness_aggregator
when applied to individuals alive at generation generation
. If no
individuals of the requested generation are present, fitness_aggregator
is not called
and mies_aggregate_single_generation()
returns NULL
instead.
The fitness_aggregator
function may have any of the following arguments, which will be given the following information when
fitness_aggregator
is called:
fitnesses
:: matrix
Will contain fitnesses for each alive individual. This value has one column when doing single-crit optimization and one column for
each "criterion" when doing multi-crit optimization.
Fitnesses are always being maximized, so if an objective is being minimized, the fitness_aggregator
function is given the objective values * -1.
objectives_unscaled
:: matrix
The objective values as given to fitnesses
, but not multiplied by -1 if they are being minimized. It is recommended that
the codomain
argument is queried for "maximize"
or "minimize"
tags when objectives_unscaled
is used.
budget
:: scalar
If multi-fidelity evaluation is being performed, then this is the "budget" value of each individual. Otherwise it is a vector containing the value
1 for each individual.
xdt
:: data.table
The configurations that were evaluated for the alive individuals. Rows are in the same order as the values given to fitnesses
or objectives_unscaled
.
search_space
:: ParamSet
The search space of the Archive
under evaluation.
codomain
:: ParamSet
The codomain of the Archive
under evaluation.
This is particularly useful when using objectives_unscaled
to determine minimization or maximization.
Not all of these arguments need to present, but at least one of fitnesses
, objectives_unscaled
, or xdt
must be.
fitness_aggregator
will never be called for an empty generation.
Other aggregation methods:
mies_aggregate_generations()
,
mies_get_generation_results()
library("bbotk")
lgr::threshold("warn")
objective <- ObjectiveRFun$new(
fun = function(xs) {
list(y1 = xs$x1, y2 = xs$x2)
},
domain = ps(x1 = p_dbl(0, 1), x2 = p_dbl(-1, 0)),
codomain = ps(y1 = p_dbl(0, 1, tags = "maximize"),
y2 = p_dbl(-1, 0, tags = "minimize"))
)
oi <- OptimInstanceMultiCrit$new(objective, terminator = trm("none"))
try(mies_aggregate_single_generation(oi$archive, identity), silent = TRUE)
mies_aggregate_single_generation(oi$archive, function(fitnesses) fitnesses)
#> NULL
mies_init_population(oi, 2, budget_id = "x1", fidelity = .5)
oi$archive$data
#> x2 x1 dob eol x_id y1 y2 x_domain
#> <num> <num> <num> <num> <num> <num> <num> <list>
#> 1: -0.3379949 0.5 1 NA 1 0.5 -0.3379949 <list[2]>
#> 2: -0.5931698 0.5 1 NA 2 0.5 -0.5931698 <list[2]>
#> timestamp batch_nr
#> <POSc> <int>
#> 1: 2024-05-13 04:41:05 1
#> 2: 2024-05-13 04:41:05 1
mies_aggregate_single_generation(oi$archive, function(fitnesses) fitnesses)
#> y1 y2
#> [1,] 0.5 0.3379949
#> [2,] 0.5 0.5931698
# Notice how fitnesses are positive, since x2 is scaled with -1.
# To get the original objective-values, use objectives_unscaled:
mies_aggregate_single_generation(oi$archive,
function(objectives_unscaled) objectives_unscaled)
#> y1 y2
#> [1,] 0.5 -0.3379949
#> [2,] 0.5 -0.5931698
# When `...` is used, all information is passed:
mies_aggregate_single_generation(oi$archive, function(...) names(list(...)))
#> [1] "fitnesses" "objectives_unscaled" "xdt"
#> [4] "search_space" "codomain" "budget"
# Generation 10 is not present, but individuals with eol `NA` are still
# considered alive:
mies_aggregate_single_generation(oi$archive, function(fitnesses) fitnesses,
generation = 10)
#> y1 y2
#> [1,] 0.5 0.3379949
#> [2,] 0.5 0.5931698
# Re-evaluating points with higher "fidelity" (x1)
mies_step_fidelity(oi, budget_id = "x1", fidelity = 0.7)
oi$archive$data
#> x2 x1 dob eol x_id y1 y2 x_domain
#> <num> <num> <num> <num> <num> <num> <num> <list>
#> 1: -0.3379949 0.5 1 1 1 0.5 -0.3379949 <list[2]>
#> 2: -0.5931698 0.5 1 1 2 0.5 -0.5931698 <list[2]>
#> 3: -0.3379949 0.7 1 NA 1 0.7 -0.3379949 <list[2]>
#> 4: -0.5931698 0.7 1 NA 2 0.7 -0.5931698 <list[2]>
#> timestamp batch_nr
#> <POSc> <int>
#> 1: 2024-05-13 04:41:05 1
#> 2: 2024-05-13 04:41:05 1
#> 3: 2024-05-13 04:41:05 2
#> 4: 2024-05-13 04:41:05 2
# Lower-fidelity values are considered dead now, even for generation 1:
mies_aggregate_single_generation(oi$archive, function(fitnesses) fitnesses,
generation = 1)
#> y1 y2
#> [1,] 0.7 0.3379949
#> [2,] 0.7 0.5931698
# This adds two new alive individuals at generation 2.
# Also the individuals from gen 1 are reevaluated with fidelity 0.8
mies_evaluate_offspring(oi, offspring = data.frame(x2 = c(-0.1, -0.2)),
budget_id = "x1", fidelity = 0.9, reevaluate_fidelity = 0.8)
oi$archive$data
#> x2 x1 dob eol x_id y1 y2 x_domain
#> <num> <num> <num> <num> <num> <num> <num> <list>
#> 1: -0.3379949 0.5 1 1 1 0.5 -0.3379949 <list[2]>
#> 2: -0.5931698 0.5 1 1 2 0.5 -0.5931698 <list[2]>
#> 3: -0.3379949 0.7 1 2 1 0.7 -0.3379949 <list[2]>
#> 4: -0.5931698 0.7 1 2 2 0.7 -0.5931698 <list[2]>
#> 5: -0.1000000 0.9 2 NA 3 0.9 -0.1000000 <list[2]>
#> 6: -0.2000000 0.9 2 NA 4 0.9 -0.2000000 <list[2]>
#> 7: -0.3379949 0.8 2 NA 1 0.8 -0.3379949 <list[2]>
#> 8: -0.5931698 0.8 2 NA 2 0.8 -0.5931698 <list[2]>
#> timestamp batch_nr
#> <POSc> <int>
#> 1: 2024-05-13 04:41:05 1
#> 2: 2024-05-13 04:41:05 1
#> 3: 2024-05-13 04:41:05 2
#> 4: 2024-05-13 04:41:05 2
#> 5: 2024-05-13 04:41:05 3
#> 6: 2024-05-13 04:41:05 3
#> 7: 2024-05-13 04:41:05 3
#> 8: 2024-05-13 04:41:05 3
mies_aggregate_single_generation(oi$archive, function(budget, ...) budget)
#> [1] 1 1 1 1
mies_aggregate_single_generation(oi$archive, function(fitnesses) fitnesses,
generation = 1)
#> y1 y2
#> [1,] 0.7 0.3379949
#> [2,] 0.7 0.5931698
mies_aggregate_single_generation(oi$archive, function(fitnesses) fitnesses,
generation = 2)
#> y1 y2
#> [1,] 0.9 0.1000000
#> [2,] 0.9 0.2000000
#> [3,] 0.8 0.3379949
#> [4,] 0.8 0.5931698
# No individuals were killed, but some were fidelity-reevaluated.
# These are not present with include_previous_generations:
mies_aggregate_single_generation(oi$archive, function(fitnesses) fitnesses,
generation = 2, include_previous_generations = TRUE)
#> y1 y2
#> [1,] 0.9 0.1000000
#> [2,] 0.9 0.2000000
#> [3,] 0.8 0.3379949
#> [4,] 0.8 0.5931698
# Typical use-case: get dominated hypervolume
mies_aggregate_single_generation(oi$archive, function(fitnesses) domhv(fitnesses))
#> [1] 0.4945359
# Get generation-wise mean fitness values
mies_aggregate_single_generation(oi$archive, function(fitnesses) {
apply(fitnesses, 2, mean)
})
#> y1 y2
#> 0.8500000 0.3077912