/**
 * Pareto frontier — multi-objective optimization over candidate runs.
 *
 * Lifted from ADC pareto.ts and blueprint-agent frontier.ts. When you're
 * trading off (cost, latency, quality) or (passRate, tokenBudget,
 * ttfb), you rarely have a single "winner" — you have a set of
 * non-dominated candidates. This module exposes:
 *
 *   - `paretoFrontier`: filter a set of candidates to the non-dominated ones
 *   - `dominates`: does A dominate B across all objectives?
 *
 * Each objective is declared with a direction: 'maximize' (higher=better)
 * or 'minimize' (lower=better). Candidates are any object; pass an
 * `objective(candidate)` accessor.
 */
export type Direction = 'maximize' | 'minimize';
export interface Objective<T> {
    /** Stable label used in reports. */
    name: string;
    direction: Direction;
    value: (candidate: T) => number;
}
export interface ParetoResult<T> {
    frontier: T[];
    dominated: T[];
    /** Index map: frontier[i] dominates each of dominatedBy[i]. */
    dominanceMap: Array<{
        dominator: T;
        dominated: T[];
    }>;
}
/** Does candidate A weakly dominate B — strictly better on at least one objective and no worse on any? */
export declare function dominates<T>(a: T, b: T, objectives: Objective<T>[]): boolean;
/**
 * Compute the non-dominated frontier. Candidates with NaN/Infinity on any
 * objective are excluded (can't rank them). A candidate enters the frontier
 * iff no other candidate dominates it.
 */
export declare function paretoFrontier<T>(candidates: T[], objectives: Objective<T>[]): ParetoResult<T>;
/**
 * Weighted-sum scalarisation. Use as a tie-break / single-winner selector
 * when callers don't want to consume a frontier. Each objective contributes
 * its normalised value (0..1 via min-max across the candidate pool) times
 * its weight; missing weights default to 1/N.
 *
 * Direction is honoured automatically — `minimize` axes have their values
 * inverted before scaling so "higher scalar = better" always holds.
 */
export declare function scalarScore<T>(candidates: T[], objectives: Objective<T>[], options?: {
    weights?: Partial<Record<string, number>>;
}): Array<{
    candidate: T;
    score: number;
}>;
/**
 * NSGA-II crowding distance — secondary sort for ties on the frontier.
 *
 * When the Pareto front collapses to a single point (or many candidates tie
 * on dominance), naive selection picks arbitrarily and the population
 * degenerates over generations. NSGA-II preserves diversity by preferring
 * candidates with more empty space around them on the frontier.
 *
 * Returns an array of `{ candidate, distance }` in the SAME order as the
 * input. Higher distance = more isolated = should be preferred when
 * preserving diversity.
 */
export declare function crowdingDistance<T>(candidates: T[], objectives: Objective<T>[]): Array<{
    candidate: T;
    distance: number;
}>;
/**
 * Pareto frontier with tie-break by crowding distance — the canonical
 * NSGA-II selection step. Returns the frontier sorted by descending crowding
 * distance so callers can `.slice(0, k)` to pick K diverse winners.
 */
export declare function paretoFrontierWithCrowding<T>(candidates: T[], objectives: Objective<T>[]): Array<{
    candidate: T;
    distance: number;
}>;
//# sourceMappingURL=pareto.d.ts.map