mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
Fabric short of the target is topped up with non-fabric measures 🟩
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
e880ae868c
commit
e652780873
1 changed files with 52 additions and 1 deletions
|
|
@ -248,7 +248,41 @@ def optimise_package_fabric_first(
|
|||
target_sap=target_sap,
|
||||
dependencies=dependencies,
|
||||
)
|
||||
return fabric_package
|
||||
if (
|
||||
target_sap is not None
|
||||
and fabric_package.score.sap_continuous >= target_sap
|
||||
):
|
||||
return fabric_package
|
||||
|
||||
# Phase 2 — the upgrade requirement is not met by fabric alone: optimise
|
||||
# the remaining groups (non-fabric, plus any fabric group phase 1 left
|
||||
# unpicked) on top of the committed fabric. Every score call is prefixed
|
||||
# with the phase-1 overlays, so candidates are valued against the
|
||||
# fabric-applied dwelling and the resulting package score stays the
|
||||
# truthful whole-package figure against the original baseline.
|
||||
remaining_groups: list[list[ScoredOption]] = [
|
||||
group
|
||||
for index, group in enumerate(groups)
|
||||
if index not in _used_group_indices(groups, fabric_package.selected)
|
||||
]
|
||||
post_fabric_scorer = _PrefixedScorer(
|
||||
scorer, [scored.option.overlay for scored in fabric_package.selected]
|
||||
)
|
||||
leftover_budget: Optional[float] = (
|
||||
None if budget is None else budget - _package_cost(fabric_package.selected)
|
||||
)
|
||||
top_up: OptimisedPackage = optimise_package(
|
||||
groups=remaining_groups,
|
||||
scorer=post_fabric_scorer,
|
||||
baseline_epc=baseline_epc,
|
||||
budget=leftover_budget,
|
||||
target_sap=target_sap,
|
||||
dependencies=dependencies,
|
||||
)
|
||||
return OptimisedPackage(
|
||||
selected=[*fabric_package.selected, *top_up.selected],
|
||||
score=top_up.score,
|
||||
)
|
||||
|
||||
|
||||
def _is_fabric_group(group: list[ScoredOption]) -> bool:
|
||||
|
|
@ -259,6 +293,23 @@ def _is_fabric_group(group: list[ScoredOption]) -> bool:
|
|||
)
|
||||
|
||||
|
||||
class _PrefixedScorer:
|
||||
"""A Scorer view of the dwelling with a committed package already applied:
|
||||
every score call sees the ``prefix`` overlays before the candidate's own.
|
||||
Phase 2 of Fabric First scores through this, so its candidates are valued
|
||||
against the post-fabric dwelling while the returned Score remains the
|
||||
truthful whole-package figure against the true baseline."""
|
||||
|
||||
def __init__(self, inner: Scorer, prefix: Sequence[EpcSimulation]) -> None:
|
||||
self._inner = inner
|
||||
self._prefix = list(prefix)
|
||||
|
||||
def score(
|
||||
self, baseline: EpcPropertyData, simulations: Sequence[EpcSimulation]
|
||||
) -> Score:
|
||||
return self._inner.score(baseline, [*self._prefix, *simulations])
|
||||
|
||||
|
||||
def _with_role1_signals(
|
||||
dependencies: Sequence[MeasureDependency],
|
||||
scorer: Scorer,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue