aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python/MLRsearch/target_stat.py
diff options
context:
space:
mode:
Diffstat (limited to 'resources/libraries/python/MLRsearch/target_stat.py')
-rw-r--r--resources/libraries/python/MLRsearch/target_stat.py59
1 files changed, 47 insertions, 12 deletions
diff --git a/resources/libraries/python/MLRsearch/target_stat.py b/resources/libraries/python/MLRsearch/target_stat.py
index 9d30d51b9c..e558139af7 100644
--- a/resources/libraries/python/MLRsearch/target_stat.py
+++ b/resources/libraries/python/MLRsearch/target_stat.py
@@ -14,7 +14,7 @@
"""Module defining LoadStat class."""
from dataclasses import dataclass, field
-from typing import Tuple
+from typing import Dict, Tuple
from .target_spec import TargetSpec
from .discrete_result import DiscreteResult
@@ -31,12 +31,9 @@ class TargetStat:
or an upper bound. For additional logic for dealing with loss inversion
see MeasurementDatabase.
- Besides the duration sums needed for determining upper and lower bound,
- a field useful for computing the conditional throughput is also included.
- The conditional throughput is average of the (relative) forwarding rates
- of good long trials weighted by gool long trial durations.
- As the intended load is stored elsewhere, the one additional field here
- has a peculiar unit, it is a sum of products of seconds and loss ratios.
+ Also, data needed for conditional throughput is gathered here,
+ exposed only as a pessimistic loss ratio
+ (as the load value is not stored here).
"""
target: TargetSpec = field(repr=False)
@@ -49,8 +46,8 @@ class TargetStat:
"""Sum of durations of shorter trials satisfying target loss ratio."""
bad_short: float = 0.0
"""Sum of durations of shorter trials not satisfying target loss ratio."""
- dur_rat_sum: float = 0.0
- """Sum over good long trials, of duration multiplied by loss ratio."""
+ long_losses: Dict[float, float] = field(repr=False, default_factory=dict)
+ """If a loss ratio value occured in a long trial, map it to duration sum."""
def __str__(self) -> str:
"""Convert into a short human-readable string.
@@ -73,14 +70,18 @@ class TargetStat:
:type result: DiscreteResult
"""
dwo = result.duration_with_overheads
+ rlr = result.loss_ratio
if result.intended_duration >= self.target.trial_duration:
- if result.loss_ratio > self.target.loss_ratio:
+ if rlr not in self.long_losses:
+ self.long_losses[rlr] = 0.0
+ self.long_losses = dict(sorted(self.long_losses.items()))
+ self.long_losses[rlr] += dwo
+ if rlr > self.target.loss_ratio:
self.bad_long += dwo
else:
self.good_long += dwo
- self.dur_rat_sum += dwo * result.loss_ratio
else:
- if result.loss_ratio > self.target.loss_ratio:
+ if rlr > self.target.loss_ratio:
self.bad_short += dwo
else:
self.good_short += dwo
@@ -115,3 +116,37 @@ class TargetStat:
optimistic = effective_excess <= limit_dursum
pessimistic = (effective_dursum - self.good_long) <= limit_dursum
return optimistic, pessimistic
+
+ def pessimistic_loss_ratio(self) -> float:
+ """Return the loss ratio for conditional throughput computation.
+
+ It adds missing dursum as full-loss trials to long_losses
+ and returns a quantile corresponding to exceed ratio.
+ In case of tie (as in median for even number of samples),
+ this returns the lower value (as being equal to goal exceed ratio
+ is allowed).
+
+ For loads classified as a lower bound, the return value
+ ends up being no larger than the target loss ratio.
+ This is because the excess short bad trials would only come
+ after the quantile in question (as would full-loss missing trials).
+ For other loads, anything can happen, but conditional throughput
+ should not be computed for those anyway.
+ Those two facts allow the logic here be simpler than in estimates().
+
+ :returns: Effective loss ratio based on long trial results.
+ :rtype: float
+ """
+ all_long = max(self.target.duration_sum, self.good_long + self.bad_long)
+ remaining = all_long * (1.0 - self.target.exceed_ratio)
+ ret = None
+ for ratio, dursum in self.long_losses.items():
+ if ret is None or remaining > 0.0:
+ ret = ratio
+ remaining -= dursum
+ else:
+ break
+ else:
+ if remaining > 0.0:
+ ret = 1.0
+ return ret