Spaces:
Sleeping
Sleeping
File size: 2,970 Bytes
b0b1bdf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | """Frontière de Pareto multi-objectifs (Sprint 19).
Algorithme générique sur N objectifs (CER, coût, vitesse, CO₂…).
Renvoie les noms des points non-dominés.
"""
from __future__ import annotations
from typing import Optional
def compute_pareto_front(
points: list[dict],
objectives: tuple[str, ...] = ("cer", "cost"),
name_key: str = "engine",
minimize: Optional[tuple[bool, ...]] = None,
) -> list[str]:
"""Calcule la frontière de Pareto sur ``len(objectives)`` dimensions.
Un point ``p`` est Pareto-dominant si aucun autre point n'a, pour TOUS
les objectifs, une valeur au moins aussi bonne ET au moins une valeur
strictement meilleure.
Parameters
----------
points:
Liste de dicts. Chaque dict doit contenir ``name_key`` et toutes les
clés de ``objectives``. Les points dont une valeur d'objectif est
``None`` sont ignorés (pas de comparaison possible).
objectives:
Clés des objectifs à minimiser/maximiser.
name_key:
Clé identifiant le point (par défaut ``"engine"``).
minimize:
Pour chaque objectif, ``True`` = minimiser (ex. CER, coût),
``False`` = maximiser (ex. ancrage). Doit avoir la même longueur
que ``objectives``.
Returns
-------
Liste des ``name`` des points sur le front Pareto, ordre stable depuis
``points``.
"""
if minimize is None:
minimize = tuple(True for _ in objectives)
if len(minimize) != len(objectives):
raise ValueError("`minimize` doit avoir la même longueur que `objectives`")
valid = []
for p in points:
try:
vals = tuple(float(p[k]) for k in objectives)
except (KeyError, TypeError, ValueError):
continue
valid.append((p[name_key], vals))
front: list[str] = []
for name_a, vals_a in valid:
dominated = False
for name_b, vals_b in valid:
if name_a == name_b:
continue
# B domine A si B est ≥ aussi bon partout ET strictement meilleur quelque part
better_or_equal_everywhere = True
strictly_better_somewhere = False
for va, vb, mini in zip(vals_a, vals_b, minimize):
if mini:
if vb > va:
better_or_equal_everywhere = False
break
if vb < va:
strictly_better_somewhere = True
else: # maximiser
if vb < va:
better_or_equal_everywhere = False
break
if vb > va:
strictly_better_somewhere = True
if better_or_equal_everywhere and strictly_better_somewhere:
dominated = True
break
if not dominated:
front.append(name_a)
return front
__all__ = ["compute_pareto_front"]
|