library(ggplot2)
library(dplyr)

Introduction

Science seldom advances in straight lines. This page documents a crooked one: two papers on the same algorithm, the same hardware, and the same question — how much energy does the Brave New Algorithm consume, and can we reduce it? — that initially reached incompatible conclusions before a careful look at the measurement methodology made everything click into place.

The first paper, presented at LION 20 (Merelo-Guervós et al. 2026), established a workflow for energy profiling, ran implementation optimizations, and explored how algorithm parameters affect the energy-vs-fitness trade-off. The second, published at OLA 2026 (J. Merelo and Molina 2026), zoomed in on the measurement process itself, identified three sources of noise and bias that had been lurking in the first paper’s data, and proposed fixes — each validated empirically.

Reading the two papers side by side is instructive, but you have to know where to look. This document does the cross-referencing for you.


The subject: the Brave New Algorithm on an AMD Ryzen

The Brave New Algorithm (BNA) (C. Merelo, Merelo, and Garcı́a-Valdez 2022) is an evolutionary optimizer in which the population is divided into castes inspired by Aldous Huxley’s Brave New World. Each caste uses a different reproduction strategy, giving fine-grained control over the exploration-exploitation balance. The BNA was implemented in Julia and benchmarked on the BBOB Sphere function (Hansen et al. 2010), initially across two chromosome dimensions (D = 3, 5) and two population sizes (P = 200, 400).

All experiments were run on an AMD Ryzen 9 9950X with Ubuntu Linux 25.04. Energy was measured with pinpoint (pinpoint?), which taps the CPU’s RAPL interface to record package-level power. Because AMD’s RAPL implementation exposes only a single PKG register (no separate memory or core breakdowns), all energy figures in this document are package-level Joules.

The algorithm’s key control parameters are:

Parameter LION values OLA values
Dimension D 3, 5 3, 5
Population P 200, 400 200, 400
max_gens (stop after N stagnant generations) 10, 25, 50 10, 25
alpha (% population in exploitation caste) 10%, 25% fixed

Part 1 — What LION-26 found

The starting point: baselines are noisy

Before measuring the algorithm, we needed a baseline — the energy consumed when the code runs but performs no evolution (just the initial population generation, which already exercises the Julia runtime, the garbage collector, and the RAPL interface itself). This is the overhead that must be subtracted from every workload measurement.

# LION-26 used two rounds of 120 baseline runs each,
# combined and summarized with a 20% trimmed mean.
lion_baseline_early <- readRDS("data/energy-full-data.rds")

lion_baseline_early %>%
  group_by(dimension, population_size) %>%
  summarise(
    n               = n(),
    median_PKG      = round(median(PKG), 1),
    trimmed_mean    = round(mean(PKG, trim = 0.2), 1),
    sd_PKG          = round(sd(PKG), 1),
    cv_pct          = round(100 * sd(PKG) / mean(PKG), 1),
    .groups = "drop"
  )
## # A tibble: 4 × 7
##   dimension population_size     n median_PKG trimmed_mean sd_PKG cv_pct
##       <int>           <int> <int>      <dbl>        <dbl>  <dbl>  <dbl>
## 1         3             200   240       319.         318.   37.8   11.6
## 2         3             400   240       330.         330    28.8    8.7
## 3         5             200   240       332.         332    28.3    8.4
## 4         5             400   240       372.         373.   36.3    9.7

Even before any workload is run, the spread is striking. Standard deviations are in the tens of Joules, and the coefficient of variation exceeds 10% in several cells.

lion_baseline_early$combo <- paste0("D=", lion_baseline_early$dimension,
                                     ", P=", lion_baseline_early$population_size)
ggplot(lion_baseline_early,
       aes(x = combo, y = PKG, fill = factor(dimension))) +
  geom_violin(alpha = 0.7, trim = FALSE) +
  geom_boxplot(width = 0.12, fill = "white", outlier.alpha = 0.3, alpha = 0.8) +
  scale_y_log10() +
  scale_fill_manual(values = c("3" = "#E07A5F", "5" = "#4E79A7")) +
  theme_minimal(base_size = 13) +
  theme(
    legend.position  = "none",
    axis.text.x      = element_text(angle = 15, hjust = 1),
    plot.title       = element_text(face = "bold"),
    plot.subtitle    = element_text(colour = "grey40")
  ) +
  labs(
    title    = "LION-26: baseline energy is noisy and multi-modal",
    subtitle = "Log scale. Each violin = 240 runs. Multi-modal shapes signal hardware state changes.",
    x        = NULL,
    y        = "PKG energy (J, log scale)"
  )
**Fig. 1** — Violin plot of LION-26 baseline PKG energy by dimension and population size (log scale). The multi-modal shapes — especially visible for D=3 — hint at the hardware entering different operating states during the measurement session.

Fig. 1 — Violin plot of LION-26 baseline PKG energy by dimension and population size (log scale). The multi-modal shapes — especially visible for D=3 — hint at the hardware entering different operating states during the measurement session.

What we said in the LION-26 paper: The violin plots show “three clusters” and “a big dispersion, especially for D=3, P=200.” The paper attributed this to “time-dependent effects” and resolved to use a trimmed mean — a sensible choice, but one that would later prove insufficient on its own.


# Load LION-era 50 ms-sampled data (the basis for the LION results section)
baseline_evoapps <- read.csv(
  "data/evoapps-1.11.7-baseline-bna-baseline-16-Oct-11-08-20.csv"
)
null_cols <- c("alpha", "max_gens", "different_seeds",
               "diff_fitness", "generations", "evaluations")
baseline_evoapps[null_cols] <- NULL

baseline_evoapps %>%
  group_by(dimension, population_size) %>%
  summarise(
    median_energy = median(PKG),
    median_time   = median(seconds),
    .groups       = "drop"
  ) -> summary_baseline_evoapps

subtract_baseline <- function(workload, bsummary) {
  workload$delta_PKG     <- NA_real_
  workload$delta_seconds <- NA_real_
  for (d in c(3, 5)) {
    for (p in c(200, 400)) {
      mask <- workload$dimension == d & workload$population_size == p
      b    <- bsummary[bsummary$dimension == d & bsummary$population_size == p, ]
      workload$delta_PKG[mask]     <- workload$PKG[mask]     - b$median_energy
      workload$delta_seconds[mask] <- workload$seconds[mask] - b$median_time
    }
  }
  workload
}

# Fix-rand mutation (the final LION baseline for further analysis)
wl_fixrand <- read.csv("data/evoapps-1.11.7-fix-rand-bna-fix-rand-25-Oct-11-06-07.csv")
wl_fixrand <- subtract_baseline(wl_fixrand, summary_baseline_evoapps)
wl_fixrand$log_diff <- log10(wl_fixrand$diff_fitness)

The Julia 1.11.8 surprise — first look

LION-26 repeated the fix-rand experiments under Julia 1.11.8 (just released at the time) to check if platform updates affect the results.

# LION 1.11.8 data
lion_baseline_118 <- read.csv("data/lion-1.11.8-baseline.csv")
lion_baseline_118 %>%
  group_by(dimension, population_size) %>%
  summarise(median_energy = median(PKG), median_time = median(seconds), .groups = "drop") ->
  summary_lion_baseline_118

lion_wl_118 <- read.csv("data/lion-1.11.8-bna-fix-rand.csv")
lion_wl_118 <- subtract_baseline(lion_wl_118, summary_lion_baseline_118)
lion_wl_118$julia  <- "v1.11.8 (LION)"
lion_wl_118$log_diff <- log10(lion_wl_118$diff_fitness)

wl_fixrand_labelled <- wl_fixrand %>% mutate(julia = "v1.11.7 (LION)")

julia_cmp_lion <- bind_rows(
  wl_fixrand_labelled %>% select(julia, dimension, population_size, max_gens, delta_PKG),
  lion_wl_118        %>% select(julia, dimension, population_size, max_gens, delta_PKG)
) %>%
  mutate(dim_pop = paste0("D=", dimension, ", P=", population_size))

pal_lion_julia <- c("v1.11.7 (LION)" = "#E07A5F", "v1.11.8 (LION)" = "#3D9970")

ggplot(julia_cmp_lion %>% filter(is.finite(delta_PKG)),
       aes(x = dim_pop, y = delta_PKG, fill = julia)) +
  geom_boxplot(notch = TRUE, outlier.alpha = 0.25, alpha = 0.8,
               position = position_dodge(0.8), width = 0.6) +
  scale_fill_manual(values = pal_lion_julia) +
  facet_wrap(~ paste0("max_gens=", max_gens)) +
  theme_minimal(base_size = 13) +
  theme(
    legend.position = "bottom",
    axis.text.x     = element_text(angle = 30, hjust = 1),
    strip.text      = element_text(face = "bold"),
    plot.title      = element_text(face = "bold"),
    plot.subtitle   = element_text(colour = "grey40")
  ) +
  labs(
    title    = "LION-26: Julia 1.11.8 looks *worse* with the original methodology",
    subtitle = "Both baselines and workloads collected in separate sessions; 50 ms RAPL sampling.",
    x        = NULL,
    y        = "Delta PKG energy (J)",
    fill     = NULL
  )
**Fig. 5** — LION-26 view of the Julia version effect. Workload delta PKG energy under Julia 1.11.7 (LION data, coral) vs. Julia 1.11.8 (LION data, teal), both using the old batch-baseline methodology (50 ms sampling, separate sessions).

Fig. 5 — LION-26 view of the Julia version effect. Workload delta PKG energy under Julia 1.11.7 (LION data, coral) vs. Julia 1.11.8 (LION data, teal), both using the old batch-baseline methodology (50 ms sampling, separate sessions).

What LION-26 found: Julia 1.11.8 appeared to consume more energy than 1.11.7, “consistently.” The recommendation was to stay on Julia 1.11.7 rather than upgrade.

Part 2 shows how the measurement methodology was driving this apparent difference — once the diagnostic tools from OLA are applied, the picture changes completely.


Part 2 — What OLA-26 found (and why it changes Part 1)

Three sources of measurement noise

The OLA paper systematically examined the LION methodology and identified three independent measurement effects. Each is introduced and the insight it provides is demonstrated in turn.


Fix 1 — Reduce the RAPL polling rate

The LION experiments used pinpoint’s default sampling interval of 50 ms (20 samples/second). OLA switched to 100 ms (10 samples/second).

At 50 ms, the measurement tool itself interrupts the CPU’s power accounting more often, adding a polling overhead and, in some cases, producing suspiciously small readings that pile up just below 50 J in the workload data.

baseline_ola_100s <- read.csv("data/ola-base-ola-baseline-14-Dec-12-06-42.csv")
baseline_ola_100s[null_cols] <- NULL

baseline_ola_100s %>%
  group_by(dimension, population_size) %>%
  summarise(median_energy = median(PKG), median_time = median(seconds), .groups = "drop") ->
  summary_baseline_ola_100s

wl_ola_100s <- read.csv("data/ola-1.11.7-ola-14-Dec-13-02-30.csv")
wl_ola_100s  <- subtract_baseline(wl_ola_100s, summary_baseline_ola_100s)
wl_ola_100s$Sampling  <- "100 ms (OLA)"
wl_fixrand$Sampling   <- "50 ms (LION)"

sampling_cmp <- bind_rows(
  wl_fixrand %>% select(Sampling, delta_PKG, delta_seconds),
  wl_ola_100s %>% select(Sampling, delta_PKG, delta_seconds)
)

pal_sampling <- c("50 ms (LION)" = "#E07A5F", "100 ms (OLA)" = "#3D9970")

ggplot(sampling_cmp %>% filter(is.finite(delta_PKG), is.finite(delta_seconds)),
       aes(x = delta_seconds, y = delta_PKG, colour = Sampling)) +
  geom_point(alpha = 0.45, size = 2) +
  scale_colour_manual(values = pal_sampling) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "top", plot.title = element_text(face = "bold"),
        plot.subtitle = element_text(colour = "grey40")) +
  labs(
    title    = "Slower polling removes a cluster of spurious low-energy readings",
    subtitle = "Each dot = one algorithm run (baseline-corrected). Left cluster at 50 ms = measurement artefact.",
    x        = "Delta time (s)",
    y        = "Delta PKG energy (J)",
    colour   = NULL
  )
**Fig. 6** — Delta energy vs. delta time for 50 ms (LION, coral) and 100 ms (OLA, teal) sampling. The cluster of anomalously small energy values visible at the bottom-left in the 50 ms data disappears at 100 ms.

Fig. 6 — Delta energy vs. delta time for 50 ms (LION, coral) and 100 ms (OLA, teal) sampling. The cluster of anomalously small energy values visible at the bottom-left in the 50 ms data disappears at 100 ms.

What this explains about LION-26: Some of the scatter in the LION violin plots — and the occasional negative delta values — originated partly in polling overhead. Switching to 100 ms brings readings back into a physically plausible range.


Fix 2 — Recognize hardware thermal drift

Even with a better sampling rate, the LION baseline violin (Fig. 1) still showed multi-modal shapes. The OLA insight was to plot baseline energy against cumulative experimental time to make any within-session thermal evolution visible. Applying this technique retroactively to the actual LION-26 baseline data shows exactly what was happening.

# Apply the OLA methodology (cumulative-time plot) to the actual LION-26 baseline data.
# baseline_evoapps is the LION 1.11.7 baseline (50 ms sampling, 480 runs), loaded earlier.
lion_drift_117 <- baseline_evoapps[, c("PKG", "seconds")]
lion_drift_117$cumulative_time <- cumsum(lion_drift_117$seconds)
lion_drift_117$Session <- "LION 1.11.7 baseline (50 ms)"

# LION 1.11.8 baseline — collected in a separate, shorter session
lion_drift_118 <- lion_baseline_118[, c("PKG", "seconds")]
lion_drift_118$cumulative_time <- cumsum(lion_drift_118$seconds)
lion_drift_118$Session <- "LION 1.11.8 baseline (50 ms)"

lbl_117 <- "LION 1.11.7 baseline (50 ms)"
lbl_118 <- "LION 1.11.8 baseline (50 ms)"

drift_data <- bind_rows(
  lion_drift_117[, c("cumulative_time", "PKG", "Session")],
  lion_drift_118[, c("cumulative_time", "PKG", "Session")]
)

pal_drift <- c(lbl_117 = "#4E79A7", lbl_118 = "#F28E2B")
names(pal_drift) <- c(lbl_117, lbl_118)

# Changepoint detection: find positions that minimise within-segment RSS.
# Uses prefix-sum trick for O(1) per-segment evaluation.
find_changepoints <- function(y, n_cp = 1L) {
  n   <- length(y)
  cs  <- c(0, cumsum(y))
  cs2 <- c(0, cumsum(y^2))
  seg_rss <- function(a, b) {
    len <- b - a + 1L
    cs2[b + 1L] - cs2[a] - (cs[b + 1L] - cs[a])^2 / len
  }
  if (n_cp == 1L) {
    rss <- vapply(seq_len(n - 1L),
                  function(k) seg_rss(1L, k) + seg_rss(k + 1L, n),
                  numeric(1))
    return(which.min(rss))
  }
  if (n_cp == 2L) {
    best <- Inf; pos <- c(NA_integer_, NA_integer_)
    for (k1 in seq_len(n - 2L)) {
      r1 <- seg_rss(1L, k1)
      for (k2 in (k1 + 1L):(n - 1L)) {
        v <- r1 + seg_rss(k1 + 1L, k2) + seg_rss(k2 + 1L, n)
        if (v < best) { best <- v; pos <- c(k1, k2) }
      }
    }
    return(pos)
  }
}

# 1.11.7: two changepoints (longer session, visible warm-up + plateau + rise)
cp117_idx <- find_changepoints(lion_drift_117$PKG, n_cp = 2L)
cp_x117   <- lion_drift_117$cumulative_time[cp117_idx]

# 1.11.8: one changepoint (shorter session, single thermal shift)
cp118_idx <- find_changepoints(lion_drift_118$PKG, n_cp = 1L)
cp_x118   <- lion_drift_118$cumulative_time[cp118_idx]

y_top <- max(drift_data$PKG) * 0.97

ggplot(drift_data, aes(x = cumulative_time, y = PKG, colour = Session)) +
  geom_point(alpha = 0.5, size = 1.8) +
  geom_smooth(method = "loess", span = 0.3, se = FALSE, linewidth = 1.2) +
  geom_vline(xintercept = cp_x117, colour = "#4E79A7",
             linetype = "dashed", linewidth = 0.8) +
  geom_vline(xintercept = cp_x118, colour = "#F28E2B",
             linetype = "dashed", linewidth = 0.8) +
  annotate("text", x = cp_x117, y = y_top,
           label = c("1.11.7\nshift 1", "1.11.7\nshift 2"),
           hjust = -0.1, size = 3.0, colour = "#4E79A7") +
  annotate("text", x = cp_x118, y = y_top,
           label = "1.11.8\nshift",
           hjust = -0.1, size = 3.0, colour = "#F28E2B") +
  scale_colour_manual(values = pal_drift) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "top", plot.title = element_text(face = "bold"),
        plot.subtitle = element_text(colour = "grey40")) +
  labs(
    title    = "The OLA diagnostic applied to LION-26 data reveals thermal drift that was always there",
    subtitle = "The two sessions sit at different absolute energy levels — a cross-session offset invisible without this plot.",
    x        = "Cumulative time (s)",
    y        = "PKG energy per run (J)",
    colour   = NULL
  )
**Fig. 7** — Applying the OLA visualization technique to the LION-26 baseline data: PKG energy per run vs. cumulative experiment time for the two LION-era baseline sessions (1.11.7 in blue, 1.11.8 in orange). Dashed vertical lines mark thermal-regime changepoints detected by minimising within-segment RSS: two for the longer 1.11.7 session (blue) and one for the 1.11.8 session (orange). The 1.11.8 baseline sits at a consistently lower absolute energy level, revealing the cross-session thermal variation that OLA's interleaved design was built to neutralise.

Fig. 7 — Applying the OLA visualization technique to the LION-26 baseline data: PKG energy per run vs. cumulative experiment time for the two LION-era baseline sessions (1.11.7 in blue, 1.11.8 in orange). Dashed vertical lines mark thermal-regime changepoints detected by minimising within-segment RSS: two for the longer 1.11.7 session (blue) and one for the 1.11.8 session (orange). The 1.11.8 baseline sits at a consistently lower absolute energy level, revealing the cross-session thermal variation that OLA’s interleaved design was built to neutralise.

What the OLA diagnostic reveals about the LION-26 data: The “three clusters” in Fig. 1 correspond to baseline runs collected at different points in a long session, as the CPU cycled through warm-up and a warmer steady-state regime. Without plotting PKG against cumulative time — the technique OLA introduced — this structure was invisible: the violin plot summarises all 480 runs together and shows only the aggregate spread. When a single baseline average from one session is subtracted from workload runs measured in a different session, any thermal offset between the sessions is silently absorbed into the delta — producing both inflated positive deltas and the occasional negative one.

The dimension-5 results in LION-26 were systematically affected: the D=5 experiments ran later in the session, when the chip was warmer, inflating their apparent energy.


Fix 3 — Interleave baseline and workload runs

The fix to the cross-session thermal drift is to remove the time gap between baseline and workload: run them back to back, alternating baseline-workload-baseline-workload. When the hardware drifts, both measurements drift together, and their difference remains stable. LION-26 used batch-separated sessions; OLA-26 introduced this interleaved design, which eliminates the cross-session thermal confound. Because the LION-26 data were not collected this way, this design cannot be applied retroactively to the LION data — but the cumulative-time plot in Fig. 7 makes visible exactly the cross-session energy offset that the interleaved design is designed to prevent.


Part 3 — The reversal: what the improved methodology revealed

Julia 1.11.8 is actually better

The cumulative-time plot in Fig. 7 directly explains one of the most surprising LION-26 findings: the apparent energy disadvantage of Julia 1.11.8. The LION 1.11.8 baseline session (orange in Fig. 7) was collected separately from the 1.11.7 workload session (blue). The two sessions sit at visibly different absolute energy levels — a cross-session thermal offset that, without the OLA diagnostic, was invisible. When LION-26 subtracted a single average from the 1.11.7 baseline and applied it to the 1.11.8 workload runs, that thermal gap was silently absorbed into the delta, making 1.11.8 appear worse.

What the OLA methodology reveals about the LION-26 measurement context: The LION 1.11.8 baseline and workload were collected in a separate session from the Julia 1.11.7 data. Without the diagnostic tools OLA provides — cumulative-time plots and per-pair deltas — there was no way to know the sessions were operating in different thermal states. Subtracting an averaged baseline from one session and applying it to workload runs from another silently absorbed any thermal offset into the delta. The interleaved design of OLA addresses this directly: every workload run is paired with the baseline run immediately preceding it, taken under identical thermal conditions.

Practical implication: Upgrading from Julia 1.11.7 to 1.11.8 is a free, significant energy saving — roughly 10% across most configurations, more for longer runs — and should not be delayed on energy grounds. Any future Julia upgrade should be re-validated with the interleaved protocol before drawing conclusions.


Part 4 — The unified picture

How the methodological improvements propagate

The table below traces each LION-26 observation to its OLA-26 explanation.

LION-26 observation Root cause identified in OLA-26 Recommended fix
Multi-modal baseline violin plots Hardware thermal drift during a long session Interleave baseline & workload; plot PKG vs. cumulative time
Negative delta-PKG values Baseline measured in a different thermal state from the workload Interleave; compute per-pair delta
Cluster of near-zero delta values 50 ms polling overhead Use 100 ms RAPL sampling
Julia 1.11.8 appears worse Cross-session thermal confound absorbed into the delta Interleaved design eliminates the confound
High variance across D=5 runs D=5 runs happened later in the session, in a warmer regime Interleave; randomise parameter order

What the LION findings still stand on

OLA-26 provides a deeper understanding of how everything works — especially of how energy is measured and what it depends on. This reanalysis shows that the findings about algorithmic parameters remain robust, because they were derived from a within-session, same-platform comparison:

  • Smaller alpha (less exploitation) is better on both energy and fitness. This result holds because all alpha conditions were run in the same session under comparable hardware states. The OLA interleaved data confirms the direction.

  • Lower max_gens saves energy at the cost of worse fitness. This is a genuine exploration-vs-exploitation trade-off that does not depend on the baseline methodology. Both papers show consistent directionality.

  • Fixing the random generator is worth the marginal energy cost. The fitness improvement from exploring the full [-5, 5] range far outweighs any energy penalty. This conclusion is independent of the baseline measurement approach.

  • Population size has minimal net energy impact after baseline correction. Because the initial population generation is captured in the baseline, the per-generation cost scales primarily with dimension, not population size, at these scales.

The energy-fitness frontier — then and now

# Load the OLA 1.11.7 workload data needed for the tradeoff comparison.
ola_mixed <- read.csv("data/ola-1.11.7-mixed-ola-mixed-15-Dec-19-49-11.csv")
ola_mixed$delta_PKG     <- NA_real_
for (i in 2:nrow(ola_mixed)) {
  if (ola_mixed$work[i] == "ola-mixed") {
    ola_mixed$delta_PKG[i] <- ola_mixed$PKG[i] - ola_mixed$PKG[i - 1]
  }
}
w117 <- ola_mixed[ola_mixed$work == "ola-mixed", ]

lion_tradeoff <- wl_fixrand %>%
  filter(is.finite(delta_PKG), is.finite(log_diff), diff_fitness > 0) %>%
  mutate(
    Setup      = "LION-26 (50 ms, batch baseline)",
    max_gens_f = factor(paste0("max_gens=", max_gens)),
    dimension  = factor(dimension)
  ) %>%
  select(Setup, delta_PKG, log_diff, max_gens_f, dimension)

ola_tradeoff <- w117 %>%
  filter(is.finite(delta_PKG)) %>%
  mutate(
    log_diff   = log10(diff_fitness),
    Setup      = "OLA-26 (100 ms, interleaved)",
    max_gens_f = factor(paste0("max_gens=", max_gens)),
    dimension  = factor(dimension)
  ) %>%
  filter(is.finite(log_diff), diff_fitness > 0) %>%
  select(Setup, delta_PKG, log_diff, max_gens_f, dimension)

both_setups <- bind_rows(lion_tradeoff, ola_tradeoff)

ggplot(both_setups,
       aes(x = delta_PKG, y = log_diff,
           colour = max_gens_f, shape = dimension)) +
  geom_point(alpha = 0.5, size = 2) +
  facet_wrap(~ Setup) +
  theme_minimal(base_size = 13) +
  theme(
    legend.position = "bottom",
    strip.text      = element_text(face = "bold"),
    plot.title      = element_text(face = "bold"),
    plot.subtitle   = element_text(colour = "grey40")
  ) +
  labs(
    title    = "Energy-fitness trade-off: same algorithm, two measurement approaches",
    subtitle = "The panels measure different things: batch-averaged delta (LION) vs. per-pair delta (OLA)",
    x        = "Delta PKG energy (J)",
    y        = "log10 fitness improvement",
    colour   = "max_gens",
    shape    = "Dimension"
  )
**Fig. 8** — Energy-fitness view across both paper setups. Left panel: LION-26 fix-rand data (50 ms, batch baseline). Right panel: OLA-26 interleaved data (100 ms, per-pair delta). The x-axis range differs between panels because the OLA delta is computed per-pair (workload minus immediately-preceding baseline), while the LION delta subtracts a single batch-averaged baseline — a methodologically distinct quantity.

Fig. 8 — Energy-fitness view across both paper setups. Left panel: LION-26 fix-rand data (50 ms, batch baseline). Right panel: OLA-26 interleaved data (100 ms, per-pair delta). The x-axis range differs between panels because the OLA delta is computed per-pair (workload minus immediately-preceding baseline), while the LION delta subtracts a single batch-averaged baseline — a methodologically distinct quantity.

The overall structure of the trade-off — no single setting minimizes energy and maximizes fitness simultaneously — is consistent across both papers. The key difference between the two panels is what the delta measures: the LION delta subtracts a single batch-averaged baseline from a separate session, so it carries any cross-session thermal offset; the OLA per-pair delta subtracts the baseline run that immediately precedes each workload run, so it isolates workload-only energy under matched thermal conditions. The wider spread visible in the OLA panel is expected: computing a per-pair difference from runs that are not perfectly matched on all thermal variables introduces more variability in the delta itself, even as the underlying energy signal becomes more precise and less confounded.


Summary: lessons across both papers

On the Brave New Algorithm itself

  1. Exploration-heavy configurations (low alpha) are simultaneously energy-efficient and solution-quality-efficient on the Sphere function at D=3, 5. The caste stratification of the BNA makes this tunable in a single parameter.

  2. The stopping criterion (max_gens) controls an energy-fitness trade-off that must be resolved by the application context: 10 stagnant generations saves energy; 25 delivers better fitness.

  3. Correcting implementation bugs (the random generator range) is unambiguously worthwhile: marginal energy cost, dramatic fitness gain.

  4. Keeping the runtime up to date saves energy for free: Julia 1.11.8 delivers around 10% lower energy than 1.11.7 for the same algorithm — a saving available with zero algorithmic changes.

On measuring energy in population-based algorithms

  1. Baseline correction is necessary but not sufficient: subtracting a batch-averaged baseline from workload runs leaves a thermal-drift confound whenever the two sets are collected in different sessions.

  2. The fix is the interleaved design: pair each workload run with the baseline run that immediately precedes it. The pair shares a thermal context; their difference is stable.

  3. Slow down the measurement tool: 100 ms RAPL sampling reduces polling overhead and eliminates a cluster of spurious near-zero readings that 50 ms sampling produced.

  4. Platform matters and needs re-validation after changes: a single energy claim has a version number. Report Julia version, kernel version, and pinpoint commit alongside every table of results.


About this document

This document cross-references the LION-26 paper (Merelo-Guervós et al. 2026) and the OLA-26 paper (J. Merelo and Molina 2026). All data and code are available in the GitHub repository under an open licence.

Research is supported by the Ministerio español de Economía y Competitividad under project PID2023-147409NB-C21.


Sources: (Merelo-Guervós et al. 2026; J. Merelo and Molina 2026). Please check references.bib and ours.bib for BibTeX entries.

References

Hansen, Nikolaus, Anne Auger, Raymond Ros, Steffen Finck, and Petr Pošı́k. 2010. “Comparing Results of 31 Algorithms from the Black-Box Optimization Benchmarking BBOB-2009.” In Proceedings of the 12th Annual Conference Companion on Genetic and Evolutionary Computation, 1689–96.
Merelo, Cecilia, Juan J Merelo, and Mario Garcı́a-Valdez. 2022. “A Brave New Algorithm to Maintain the Exploration/Exploitation Balance.” In New Perspectives on Hybrid Intelligent System Design Based on Fuzzy Logic, Neural Networks and Metaheuristics, 305–16. Springer.
Merelo, JJ, and Cecilia Merelo Molina. 2026. “Best Practices in Measuring Energy Consumption in Population-Based Metaheuristics.” In Proceedings OLA’26 International Conference on Optimization and Learning, 183–94.
Merelo-Guervós, Juan J., Cecilia Merelo-Molina, Pablo García-Sánchez, and Mario García-Valdez. 2026. “Is There a (Carbon-) Free Lunch? Energy/Performance Tradeoffs in Population-Based Metaheuristics.”