Something went wrong. Try again.
A functional toolkit for authoring resource-leveling algorithms — compose constraint and scoring blocks, enumerate feasible schedules
Something went wrong. Try again.
1.7 kB · 50 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051// Multi-objective combination as data — spaCy's `default_score_weights`.//// A weight map, not a hand-composed closure, so the combination serializes// into a run config. `null` means "compute and report, but don't optimize// on it" — how you watch a tradeoff before committing to it.
import type { Schedule, Scorer } from "./types.ts";
export interface WeightedEntry { readonly scorer: Scorer; /** Contribution multiplier; null = reported but unweighted. */ readonly weight: number | null;}
/** Combine scorers into one minimizing objective. `max`-direction scorers * contribute negated, so a higher raw value still improves the combined * score. Entries with null/zero weight are excluded from the objective * (use `scoreReport` to still see their values). */export function weightedScorer( entries: readonly WeightedEntry[], name = "objective",): Scorer { const active = entries.filter( (e): e is WeightedEntry & { weight: number } => e.weight !== null && e.weight !== 0, ); return { name, direction: "min", score(schedule: Schedule): number { let total = 0; for (const e of active) { const sign = e.scorer.direction === "min" ? 1 : -1; total += sign * e.weight * e.scorer.score(schedule); } return total; }, };}
/** Every scorer's raw value for a schedule, keyed by scorer name — the * reported-but-unweighted view that rides along with the objective. */export function scoreReport( schedule: Schedule, scorers: readonly Scorer[],): Record<string, number> { const report: Record<string, number> = {}; for (const scorer of scorers) report[scorer.name] = scorer.score(schedule); return report;}