Applies a fitness_aggregator function to the values that were alive in the archive at at any generation. mies_aggregate_single_generation() is used, see there for more information about fitness_aggregator.

Generations for which fitness_aggregator returns NULL, or which are not present in any dob in the archive, or which contain no alive individuals (e.g. because eol is smaller or equal dob for all of them) are ignored.

as.list() is applied to the values returned by fitness_aggregator, and data.table::rbindlist() is called on the list of resulting values. If the first non-NULL-value returned by fitness_aggregator, then data.table::rbindlist() is called with fill = TRUE and use.names = TRUE.

If no non-empty generations are present, or fitness_aggregator returns NULL on every call, then the return value is data.table(dob = numeric(0)).

In contrast with mies_aggregate_generations(), mies_generate_apply() can construct aggregated values for entire fitness matrices, not only individual objectives (see examples). However, mies_aggregate_generations() is simpler if per-objective aggregates are desired.

mies_generation_apply(
  archive,
  fitness_aggregator,
  include_previous_generations = FALSE
)

Arguments

archive

(Archive)
The archive over which to aggregate.

fitness_aggregator

(function)
Aggregation function, called with information about alive individuals of each generation. See mies_aggregate_single_generation().

include_previous_generations

(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.

Value

data.table with columns dob, next to the columns constructed from the return values of fitness_aggregator.

Examples

set.seed(1)
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("evals", n_evals = 40))

op <- opt("mies",
  lambda = 4, mu = 4,
  mutator = mut("gauss", sdev = 0.1),
  recombinator = rec("xounif"),
  parent_selector = sel("random"),
  survival_selector = sel("best", scl("hypervolume"))
)

op$optimize(oi)
#>       x1    x2  x_domain    y1    y2
#>    <num> <num>    <list> <num> <num>
#> 1:     1    -1 <list[2]>     1    -1

# Aggregated hypervolume of individuals alive in each gen:
mies_generation_apply(oi$archive, function(fitnesses) {
  domhv(fitnesses)
})
#>       dob        V1
#>     <num>     <num>
#>  1:     1 0.4299653
#>  2:     2 0.4842743
#>  3:     3 0.6508345
#>  4:     4 0.8669871
#>  5:     5 0.8932747
#>  6:     6 0.8987237
#>  7:     7 0.9668899
#>  8:     8 0.9674088
#>  9:     9 1.0000000
#> 10:    10 1.0000000

# Aggregated hypervolume of all points evaluated up to each gen
# (may be slightly more, since the domhv of more points is evaluated).
# This would be the dominated hypervolume of the result set at each
# generation:
mies_generation_apply(oi$archive, function(fitnesses) {
  domhv(fitnesses)
}, include_previous_generations = TRUE)
#>       dob        V1
#>     <num>     <num>
#>  1:     1 0.4299653
#>  2:     2 0.4900229
#>  3:     3 0.6562904
#>  4:     4 0.8724430
#>  5:     5 0.8986106
#>  6:     6 0.9286387
#>  7:     7 0.9722402
#>  8:     8 0.9727591
#>  9:     9 1.0000000
#> 10:    10 1.0000000

# The following are simpler with mies_aggregate_single_generations():
mies_generation_apply(oi$archive, function(fitnesses) {
  apply(fitnesses, 2, mean)
})
#>       dob        y1        y2
#>     <num>     <num>     <num>
#>  1:     1 0.5296734 0.3236138
#>  2:     2 0.5285369 0.5169834
#>  3:     3 0.6970645 0.5814416
#>  4:     4 0.7709625 0.6907804
#>  5:     5 0.8663453 0.8039020
#>  6:     6 0.8563497 0.8824235
#>  7:     7 0.8854497 0.9866064
#>  8:     8 0.9382245 0.9870996
#>  9:     9 0.9490188 1.0000000
#> 10:    10 0.9609022 1.0000000
# Compare:
mies_aggregate_generations(oi, aggregations = list(mean = mean))
#>       dob   mean.y1   mean.y2
#>     <int>     <num>     <num>
#>  1:     1 0.5296734 0.3236138
#>  2:     2 0.5285369 0.5169834
#>  3:     3 0.6970645 0.5814416
#>  4:     4 0.7709625 0.6907804
#>  5:     5 0.8663453 0.8039020
#>  6:     6 0.8563497 0.8824235
#>  7:     7 0.8854497 0.9866064
#>  8:     8 0.9382245 0.9870996
#>  9:     9 0.9490188 1.0000000
#> 10:    10 0.9609022 1.0000000

mies_generation_apply(oi$archive, function(objectives_unscaled) {
  apply(objectives_unscaled, 2, mean)
})
#>       dob        y1         y2
#>     <num>     <num>      <num>
#>  1:     1 0.5296734 -0.3236138
#>  2:     2 0.5285369 -0.5169834
#>  3:     3 0.6970645 -0.5814416
#>  4:     4 0.7709625 -0.6907804
#>  5:     5 0.8663453 -0.8039020
#>  6:     6 0.8563497 -0.8824235
#>  7:     7 0.8854497 -0.9866064
#>  8:     8 0.9382245 -0.9870996
#>  9:     9 0.9490188 -1.0000000
#> 10:    10 0.9609022 -1.0000000
# Compare:
mies_aggregate_generations(oi, aggregations = list(mean = mean),
  as_fitnesses = FALSE)
#>       dob   mean.y1    mean.y2
#>     <int>     <num>      <num>
#>  1:     1 0.5296734 -0.3236138
#>  2:     2 0.5285369 -0.5169834
#>  3:     3 0.6970645 -0.5814416
#>  4:     4 0.7709625 -0.6907804
#>  5:     5 0.8663453 -0.8039020
#>  6:     6 0.8563497 -0.8824235
#>  7:     7 0.8854497 -0.9866064
#>  8:     8 0.9382245 -0.9870996
#>  9:     9 0.9490188 -1.0000000
#> 10:    10 0.9609022 -1.0000000