covertable
Version:
Efficient TypeScript library for pairwise testing, generating minimal covering arrays with constraint support.
150 lines (149 loc) • 6.11 kB
TypeScript
import { FactorsType, ScalarType, PairByKeyType, CandidateType, RowType, OptionsType, PairType, SuggestRowType } from "./types";
import { UncoveredPair } from "./exceptions";
export declare class Row extends Map<ScalarType, number> implements RowType {
/** Pair keys that failed constraint checks for this row attempt. */
invalidPairs: Set<ScalarType>;
constructor(row: CandidateType);
getPairKey(...newPair: number[]): ScalarType;
copy(row: Row): void;
}
export interface ControllerStats {
/** Total pairs before any pruning. */
totalPairs: number;
/** Number of pairs pruned by constraints (infeasible). */
prunedPairs: number;
/** Number of pairs consumed so far. */
coveredPairs: number;
/** Coverage ratio: coveredPairs / (totalPairs - prunedPairs). */
progress: number;
/** Number of generated rows. */
rowCount: number;
/** Pairs that could not be covered. Populated after make/makeAsync completes. */
uncoveredPairs: UncoveredPair[];
/** Counts of values filled by close() (completion), keyed by factor then value. */
completions: Record<string, Record<string, number>>;
}
export declare class Controller<T extends FactorsType> {
factors: FactorsType;
options: OptionsType<T>;
factorLength: number;
factorIsArray: Boolean;
private serials;
private parents;
private indices;
incomplete: PairByKeyType;
private rejected;
row: Row;
private _totalPairs;
private _prunedPairs;
private _rowCount;
private _uncoveredPairs;
private _completions;
get stats(): ControllerStats;
private constraints;
private constraintsByKey;
private comparer;
/**
* Indices into `constraints` that have already evaluated to `true`
* against the **current** row. Cleared whenever the row is reset or
* yielded. Safe because the row only grows and each condition is
* deterministic over its declared keys.
*/
private passedIndexes;
constructor(factors: FactorsType, options?: OptionsType<T>);
/** Normalize `in` conditions: convert `values` arrays to Sets for O(1) lookup. */
private static normalizeCondition;
private resolveConstraints;
private serialize;
private setIncomplete;
/**
* Try to add a candidate pair to the current row. Evaluates constraints
* against a snapshot (row + pair) without mutating `this.row`. If all
* constraints pass (or are unknown), the pair is committed to `this.row`
* and `true` is returned. If any constraint definitively fails, `this.row`
* is unchanged and `false` is returned.
*/
private setPair;
private consumePairs;
getCandidate(pair: PairType): CandidateType;
isCompatible(pair: PairType): number | null;
/**
* Check whether adding `candidate` to `row` would violate any constraint.
* Returns `true` (OK), `false` (definitively violated), or `null`
* (some dependency is still missing — defer).
*
* Constraints already in `passedIndexes` are skipped.
*/
private storableCheck;
/**
* Returns the number of new keys this candidate would add to `row`, or
* `null` if the candidate is incompatible or would definitively violate a
* constraint. `null` results from three-valued evaluation are treated
* as "OK for now" — they will be rechecked once more keys are known.
*/
storable(candidate: CandidateType, row?: Row): number | null;
/**
* Evaluate constraints against `row` and mark those that pass as done.
* Returns `false` if any constraint definitively fails (= the row is
* unsalvageable and should be abandoned), `true` otherwise.
*/
private markPassedConstraints;
/**
* Forward checking: given a snapshot row, propagate constraints to prune
* domains of unfilled factors. If any factor's domain becomes empty, the
* current assignment is unsolvable — return false.
*
* This is read-only: it does NOT modify this.row. It builds a temporary
* domain map and iteratively narrows it by evaluating constraints with
* each candidate value.
*/
private forwardCheck;
isFilled(row: Row): boolean;
private toMap;
private toObject;
private reset;
private restore;
/**
* Fill the remaining unfilled factors of `this.row` and check constraints.
* Uses depth-first backtracking: each unfilled factor tries its values in
* order (weight-sorted on the first pass). When a value causes a
* constraint to evaluate to `false` (via three-valued `storable`), the
* next candidate is tried; if all candidates are exhausted, the previous
* factor is backtracked.
*
* Returns `true` when a valid completion is found (the row is updated in
* place), or `false` when no valid completion exists.
*/
/**
* Result of close(): `true` = valid completion found; `false` = failed;
* or an object with the conflict keys from the first failing constraint.
*/
private close;
get strength(): number;
get allStrengths(): number[];
private valueToSerial;
private applyPreset;
private orderByWeight;
get isComplete(): boolean;
/**
* Find the keys of the first failing constraint on the current row.
* Returns the set of factor keys that participate in the conflict,
* or null if the row passes all constraints.
*/
private findConflictKeys;
/**
* Analyse remaining incomplete pairs and identify which constraint(s)
* make each pair infeasible. Used to build a diagnostic when throwing
* NeverMatch.
*/
private diagnoseUncoveredPairs;
/**
* Record which factor values were filled by close() (completion) rather
* than by greedy. `greedyKeys` are the keys that were already in the row
* before close() ran.
*/
private recordCompletions;
get progress(): number;
make<T extends FactorsType>(): SuggestRowType<T>[];
makeAsync<T extends FactorsType>(): Generator<SuggestRowType<T>, void, unknown>;
}