R/mies_methods.R
mies_aggregate_single_generation.RdApplies 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