Source code for eclypse.policies.constraints.normalise
"""Normalisation constraint policy."""
from __future__ import annotations
from typing import (
TYPE_CHECKING,
Any,
)
from eclypse.policies._filters import (
coerce_numeric_like,
ensure_numeric_value,
iter_selected_keys,
)
if TYPE_CHECKING:
from eclypse.graph.asset_graph import AssetGraph
from eclypse.utils.types import UpdatePolicy
[docs]
def normalise(
total: float,
*,
node_assets: str | list[str] | None = None,
edge_assets: str | list[str] | None = None,
) -> UpdatePolicy:
"""Scale selected values so their graph-wide sum equals ``total``.
Args:
total (float): Desired sum across all selected assets.
node_assets (str | list[str] | None): Optional node asset key selector.
edge_assets (str | list[str] | None): Optional edge asset key selector.
Returns:
Policy that rescales selected numeric assets.
"""
def policy(graph: AssetGraph):
selected: list[tuple[dict[str, Any], str]] = []
if node_assets is not None:
for _, data in graph.nodes.data():
selected.extend(
(data, key) for key in iter_selected_keys(data, node_assets)
)
if edge_assets is not None:
for _, _, data in graph.edges.data():
selected.extend(
(data, key) for key in iter_selected_keys(data, edge_assets)
)
current_total = 0.0
for data, key in selected:
current_total += ensure_numeric_value(key, data[key])
if current_total == 0:
return
factor = total / current_total
for data, key in selected:
value = ensure_numeric_value(key, data[key]) * factor
data[key] = coerce_numeric_like(data[key], value)
return policy