How the Pareto calculation works
1. The core idea
Section titled “1. The core idea”Each simulation run becomes a point within a cube defined by three axes — decentralization (degree of decentralization, DoD), security, and scalability.
A run is Pareto-optimal if there is no other run that dominates , i.e. that is at least as good across all three axes and strictly better on at least one of them.
Since, according to the blockchain trilemma, it is impossible to maximize all three goals simultaneously, trade-offs must be made. Consequently, there is usually no single best solution, but rather several equally valid compromises — and these are precisely what we are looking for. The group of those Pareto-optimal runs is called the Pareto front.
2. How it is done
Section titled “2. How it is done”Imagine a cube whose edges range from to : .
- Right (axis ) = greater decentralization
- Back (axis ) = greater security
- Top (axis ) = greater scalability
A run with the values is therefore highly decentralized, not very secure, and moderately scalable. For every axis, the following applies uniformly: higher = better.
The task is simple: How do we get from the many raw numbers of a simulation to these three clean values between and ? These are the next four steps.
Step 1 – Collect the raw values
Section titled “Step 1 – Collect the raw values”Each run provides many individual measurements (metrics), e.g.:
| Metric | Meaning | Belongs to axis | Good is … |
|---|---|---|---|
ShannonEntropy | Dispersion of block production | Decentralization | high |
GiniCoefficient | Inequality of distribution | Decentralization | low |
Reliability | Reliability | Security | high |
TransactionThroughput | Transactions per minute | Scalability | high |
(The complete mapping is located in TrilemmaMetricRegistry in .core.analysis.)
We simply read out these numbers for each run.
Step 2 – Normalize the values
Section titled “Step 2 – Normalize the values”The problem: The metrics have completely different units and orders of magnitude. TransactionThroughput might be , whereas the GiniCoefficient ranges between and . You cannot combine them directly — the large number would completely dominate the others.
The solution: We convert each metric to a common scale from to . This is known as min-max normalization. For a given value of a metric, we look at the minimum value () and the maximum value () of that metric across all runs in the group and calculate:
- The worst run for a metric thus receives .
- The best receives .
- All others fall in between.
Aligning direction: For some metrics, a lower value is better (e.g., GiniCoefficient). To ensure that “higher = better” applies across the board, we simply invert such values:
Step 3 – Aggregate by axis (mean value)
Section titled “Step 3 – Aggregate by axis (mean value)”An axis (e.g., decentralization) is often derived from multiple metrics. We simply calculate the average of the normalized values for that axis. Which metrics take part can be chosen per analysis — see choosing which metrics count.
If an axis has metrics with the normalized values , the axis score is:
Each run thus has exactly three numbers: its point within the cube.
Step 4 – Dominance and the Pareto front
Section titled “Step 4 – Dominance and the Pareto front”Now we compare the points with each other.
Dominance. A run dominates a run if is at least as good on all three axes and strictly better on at least one. Formally, with the points and :
In words: is nowhere worse and strictly better in at least one respect. In this case, is clearly inferior — after all, there is an alternative that is better in every regard.
Pareto-optimal. A run is Pareto-optimal if no other run dominates it. The set of all Pareto-optimal runs is called the Pareto front. This front typically comprises multiple runs — representing the various “best compromises,” all of which are equally valid.
3. A fully worked-out example
Section titled “3. A fully worked-out example”Four runs, four raw metrics:
| Run | ShannonEntropy | GiniCoefficient | Reliability | Throughput |
|---|---|---|---|---|
| A | 4 | 0.2 | 0.9 | 100 |
| B | 2 | 0.6 | 0.5 | 300 |
| C | 3 | 0.4 | 0.7 | 200 |
| D | 2 | 0.6 | 0.5 | 100 |
Normalization (Step 2)
Section titled “Normalization (Step 2)”Min/max per metric across all four runs: Shannon , Gini , Reliability , Throughput .
| Run | Shannon (high=good) | Gini (low=good → inverted) | Reliability | Throughput |
|---|---|---|---|---|
| A | ||||
| B | ||||
| C | ||||
| D |
Average per axis (Step 3)
Section titled “Average per axis (Step 3)”Decentralization = Mean of Shannon and Gini. Security = Reliability. Scalability = Throughput. This yields the points in the cube:
| Run | Decentralization | Security | Scalability | Point |
|---|---|---|---|---|
| A | ||||
| B | ||||
| C | ||||
| D |
Check for dominance (Step 4)
Section titled “Check for dominance (Step 4)”- D : C is everywhere and strictly better on every axis → C dominates D. (A and B also dominate D.) → D is not Pareto optimal.
- A : No other option is at least as good across the board. B has lower ; C has lower . → A is Pareto optimal.
- B : B is the only one with ; no other option matches this while keeping the other values the same. → B is Pareto optimal.
- C : While A has higher , it has lower (), so it is not everywhere. The same applies to B. → C is Pareto optimal.
Result – the Pareto frontier: . Only D is excluded because there is an alternative (C) that is better in every respect.
It is interesting to note: A, B, and C represent three distinct trade-offs (A prioritizes decentralization and security, B prioritizes scalability, and C is balanced) — and all three are valid “winners.” This is precisely the point of the trilemma.
4. Choosing which metrics count
Section titled “4. Choosing which metrics count”By default every registered metric contributes to its axis. A research question rarely needs all of them, though — so the analysis accepts a selection: one list of metric names per axis, and only those are aggregated in Step 3.
The metric registry is the single source of truth for what exists. It maps every raw simulator metric to its axis and its direction (higher or lower is better), and the front end builds its selection UI from that list rather than hardcoding names:
List<MetricContribution> available = bench.availableParetoMetrics();
List<ParetoPoint> points = bench.paretoAnalysis(runs, new ParetoSelection( List.of("ShannonEntropy", "GiniCoefficient"), // decentralization List.of("AvailabilitySecurity"), // security List.of("TransactionThroughput"))); // scalabilityThree properties are worth knowing:
Selections are validated, not silently ignored. An unknown metric name, a metric listed under the wrong axis, or the same metric twice (which would double its weight in the mean) is rejected with an IllegalArgumentException. A typo fails loudly instead of quietly changing the front.
An empty list ignores that axis. Every run then scores a constant on it, so all points come to lie on that face of the cube. Because the value is identical for all runs, it has no influence on dominance — the analysis effectively becomes two-dimensional while the view stays a cube. This is distinct from the neutral described below, which means “metric selected but not present in this run’s data”.
The analysis is stateless. Nothing is cached between calls, so several analyses with different selections over the same group are simply several calls, and they can be shown side by side. Calling the analysis without a selection keeps the previous behaviour and considers every registered metric.
5. Three nuances
Section titled “5. Three nuances”Constant metric → neutral value of . If all runs have the same value for a given metric, then , and the formula would involve division by zero. In this case, the metric provides no basis for differentiation, so we assign it the neutral value of . Since this applies to all runs equally, it does not alter the ranking (dominance). An axis for which a run has no metric value at all is assigned this same value.
Everything is group-relative. The values ranging from to are derived from comparisons within a group (the and are drawn from that specific group). Thus, a point signifies “good compared to the other runs in this group” — not “good on an absolute scale.” Consequently, values across different groups are not directly comparable.
Minute computational inaccuracies. Computers introduce slight inaccuracies when calculating with floating-point numbers. To prevent from being incorrectly deemed “better” than , we perform comparisons using a tiny tolerance of .