import { XpbdIncrementalPotentialProblemN, type XpbdArmijoAcceptedN, type XpbdArmijoExhaustedN, type XpbdArmijoNotDescentN, type XpbdArmijoStepFilterRefusedN, type XpbdPackedIncrementalPotentialEvaluationN } from './xpbd-incremental-potential-problem.js'; import { type XpbdIncrementalPotentialDirectionEvidenceN, type XpbdIncrementalPotentialDirectionPolicyNameN, type XpbdIncrementalPotentialDirectionPolicyN } from './xpbd-incremental-potential-direction.js'; /** * Which physical quantity a stop test bounds. * * The packed objective is `½‖x − x̃‖²_M + deltaTime² U(x)`, so a packed * gradient entry carries mass·length and the two criteria below differ by * exactly `deltaTime²`. That factor is not a detail: no single criterion * bounds both the per-step position error and the residual acceleration, so * the choice belongs to the author of the scene rather than to this library. * * Measured over an eight-fold timestep refinement at a fixed authored * tolerance, the delivered error spreads by: * * | criterion | acceleration | position | * | ------------------------------- | ------------ | -------- | * | `'packed-gradient'` | 45.4× | 1.5× | * | `'maximum-acceleration-residual'`| 1.02× | 62.8× | * * Pick `'packed-gradient'` to hold a per-step position residual, and * `'maximum-acceleration-residual'` to hold a force resolution. */ export type XpbdIncrementalPotentialConvergenceKindN = 'packed-gradient' | 'maximum-acceleration-residual'; /** * An authored stop test: which quantity is bounded, and by how much. * * Discriminated rather than a bare number because the two tolerances are not * interconvertible without a timestep and a mass, and are not even in the same * units. */ export type XpbdIncrementalPotentialConvergenceN = { readonly kind: 'packed-gradient'; /** * Absolute packed-gradient norm, in mass·length (= force·time²). * * Because `deltaTime²` is folded into the potential, this bounds forces * only down to `tolerance / deltaTime²`: halving the timestep quarters * the force this test can still see. It is exactly the shipped default's * semantics. */ readonly tolerance: number; } | { readonly kind: 'maximum-acceleration-residual'; /** * Largest residual acceleration left on any free particle, in * length/time². * * Computed as `max_i ‖gradient_i‖ / (mass_i · deltaTime²)`. Fixed * particles are excluded: they hold no packed coordinate and their * gradient is identically zero, so they can neither raise nor lower it. * * Independent of the timestep, of the particle count, and of the choice * of mass unit — a scene whose particles differ in mass by a thousandfold * is bounded by the worst-accelerated one, not by an aggregate that a * heavy particle can hide inside. */ readonly tolerance: number; }; /** The authored stop test, echoed on every terminal. */ export interface XpbdIncrementalPotentialConvergenceContractN { /** Which quantity decided this result. */ readonly kind: XpbdIncrementalPotentialConvergenceKindN; /** Authored threshold, in that criterion's own unit. */ readonly tolerance: number; } /** The authored stop test together with what it actually measured. */ export interface XpbdIncrementalPotentialConvergenceEvidenceN extends XpbdIncrementalPotentialConvergenceContractN { /** Criterion residual at the authored initial coordinates. */ readonly initialResidual: number; /** * Criterion residual at the last accepted iterate. * * `converged` is exactly `finalResidual <= tolerance`; every other terminal * reports how far short it stopped, in the unit the author chose. */ readonly finalResidual: number; } export interface MinimizeXpbdIncrementalPotentialNOptions { readonly problem: XpbdIncrementalPotentialProblemN; readonly initialCoordinates: ArrayLike; /** * Stop test to apply; defaults to `'packed-gradient'` at `1e-8`. * * Mutually exclusive with {@link gradientTolerance}, which is the legacy * spelling of the same packed-gradient criterion. Authoring both is refused * before anything is evaluated rather than silently resolved. */ readonly convergence?: XpbdIncrementalPotentialConvergenceN; /** * Absolute packed-gradient norm tolerance; default `1e-8`. * * The packed objective folds `deltaTime²` into the potential, so this * threshold resolves forces only down to `gradientTolerance / deltaTime²` and * is not invariant under timestep refinement. See * {@link XpbdIncrementalPotentialMinimizationPolicyN.gradientTolerance}. */ readonly gradientTolerance?: number; /** Accepted-step budget; default 128. Zero performs evaluation only. */ readonly maximumIterations?: number; /** Initial Armijo step; default one. */ readonly initialStep?: number; /** Armijo contraction in `(0, 1)`; default `0.5`. */ readonly contractionFactor?: number; /** Armijo sufficient-decrease coefficient in `(0, 1)`; default `1e-4`. */ readonly sufficientDecrease?: number; /** Trial budget for each Armijo search; default 32. */ readonly maximumLineSearchTrials?: number; /** * Packed search-direction policy; defaults to steepest descent. * * A name selects a shipped policy and is resolved against this problem, so * `'newton-cg'` is reachable here rather than only through a factory the * caller has to know exists. */ readonly directionPolicy?: XpbdIncrementalPotentialDirectionPolicyN | XpbdIncrementalPotentialDirectionPolicyNameN; } /** Complete evidence for one Armijo-accepted search-direction attempt. */ export interface XpbdIncrementalPotentialIterationN { /** Zero-based accepted-iteration index. */ readonly index: number; /** Stable identity of the policy that produced `direction`. */ readonly directionPolicyId: string; /** Defensive packed direction passed to the Armijo search. */ readonly direction: Float64Array; /** Complete accepted search and admissible-step evidence. */ readonly search: XpbdArmijoAcceptedN; /** Euclidean norm of the accepted packed coordinate displacement. */ readonly stepNorm: number; /** Positive objective reduction produced by the accepted displacement. */ readonly objectiveDecrease: number; /** Policy-defined record of how this iteration's direction was obtained. */ readonly directionEvidence?: XpbdIncrementalPotentialDirectionEvidenceN; } /** * Backward-compatible name for one accepted minimizer iteration. * * @deprecated Use `XpbdIncrementalPotentialIterationN`. */ export type XpbdSteepestDescentIterationN = XpbdIncrementalPotentialIterationN; /** Evidence every minimization terminal carries, however it ended. */ interface XpbdIncrementalPotentialMinimizationBaseN { /** Exact compiled objective and identity context the search ran against. */ readonly problem: XpbdIncrementalPotentialProblemN; /** Objective evidence at the authored initial coordinates. */ readonly initial: XpbdPackedIncrementalPotentialEvaluationN; /** Objective evidence at the last accepted iterate. */ readonly final: XpbdPackedIncrementalPotentialEvaluationN; /** Accepted iterations in execution order, empty when none were. */ readonly iterations: readonly XpbdIncrementalPotentialIterationN[]; /** Stable identity of the direction policy used for every attempt. */ readonly directionPolicyId: string; /** * Packed-gradient norm threshold, in mass·length. * * Retained on every terminal, and still the stop test whenever * `convergence.kind` is `'packed-gradient'`. Under any other criterion this * is the inert default and did **not** decide the result — read * {@link convergence}, which names the criterion that did. */ readonly gradientTolerance: number; /** The stop test that decided this result, and what it measured. */ readonly convergence: XpbdIncrementalPotentialConvergenceEvidenceN; /** Authored accepted-step budget. */ readonly maximumIterations: number; /** * Evidence of the final direction attempt. * * Present on a terminal reached because that attempt failed, so the record * of why survives the terminal rather than being discarded with it. */ readonly directionEvidence?: XpbdIncrementalPotentialDirectionEvidenceN; } export interface XpbdIncrementalPotentialConvergedN extends XpbdIncrementalPotentialMinimizationBaseN { readonly status: 'converged'; readonly convergencePoint: 'initial' | 'accepted-iterate'; } export interface XpbdIncrementalPotentialIterationLimitN extends XpbdIncrementalPotentialMinimizationBaseN { readonly status: 'iteration-limit'; } export interface XpbdIncrementalPotentialLineSearchExhaustedN extends XpbdIncrementalPotentialMinimizationBaseN { readonly status: 'line-search-exhausted'; readonly search: XpbdArmijoExhaustedN; } /** Minimization refusal before any uncertified Armijo trial is evaluated. */ export interface XpbdIncrementalPotentialLineSearchRefusedN extends XpbdIncrementalPotentialMinimizationBaseN { /** Exact compiled objective and identity context. */ readonly problem: XpbdIncrementalPotentialProblemN; /** Objective evidence at the authored initial coordinates. */ readonly initial: XpbdPackedIncrementalPotentialEvaluationN; /** Last accepted objective evidence before refusal. */ readonly final: XpbdPackedIncrementalPotentialEvaluationN; /** Accepted iterations preceding the refused search. */ readonly iterations: readonly XpbdSteepestDescentIterationN[]; /** Absolute gradient norm required for convergence. */ readonly gradientTolerance: number; /** Authored accepted-step budget. */ readonly maximumIterations: number; /** Distinct admissible-step refusal rather than numerical exhaustion. */ readonly status: 'line-search-refused'; /** Complete filter evidence from the refused Armijo search. */ readonly search: XpbdArmijoStepFilterRefusedN; } export type XpbdIncrementalPotentialStallReasonN = 'coordinate-resolution' | 'objective-resolution' | 'not-descent'; export interface XpbdIncrementalPotentialStalledN extends XpbdIncrementalPotentialMinimizationBaseN { readonly status: 'stalled'; readonly reason: XpbdIncrementalPotentialStallReasonN; readonly search: XpbdArmijoAcceptedN | XpbdArmijoNotDescentN; } /** * Termination because the direction policy declined to propose a direction. * * Distinct from a stall: the minimizer did not run out of progress, it was * never given a direction to try. No Armijo trial was evaluated and no * coordinate moved. */ export interface XpbdIncrementalPotentialDirectionRefusedN extends XpbdIncrementalPotentialMinimizationBaseN { /** Distinguishes a policy refusal from a search or resolution terminal. */ readonly status: 'direction-refused'; /** Stable policy-stated reason, such as `'non-positive-curvature'`. */ readonly reason: string; } /** * The authored base point lies outside one potential law's open domain. * * No objective evaluation was accepted and no coordinate moved. This is an * expected mathematical refusal for contact barriers, distinct from malformed * input or an ordinary provider failure, which still throws. */ export interface XpbdIncrementalPotentialInitialStateRefusedN { /** Distinguishes an inadmissible base from a refused trial step. */ readonly status: 'initial-state-refused'; /** Exact compiled objective and identity context. */ readonly problem: XpbdIncrementalPotentialProblemN; /** Defensive copy of the packed coordinates that could not be evaluated. */ readonly initialCoordinates: Float64Array; /** Stable identifier of the law whose open domain excluded the base. */ readonly lawId: string; /** Machine-facing reason supplied by that law. */ readonly reason: string; /** Human-facing explanation supplied by that law. */ readonly message: string; /** Empty because no accepted iterate exists before the base evaluation. */ readonly iterations: readonly []; /** Stable identity of the direction policy that would have been used. */ readonly directionPolicyId: string; /** Authored gradient tolerance, retained for diagnosis. */ readonly gradientTolerance: number; /** * The stop test that would have applied, retained for diagnosis. * * Carries no residuals: the base could not be evaluated, so neither * criterion has a measured value here. */ readonly convergence: XpbdIncrementalPotentialConvergenceContractN; /** Authored iteration budget, retained for diagnosis. */ readonly maximumIterations: number; } export type XpbdIncrementalPotentialMinimizationResultN = XpbdIncrementalPotentialConvergedN | XpbdIncrementalPotentialInitialStateRefusedN | XpbdIncrementalPotentialDirectionRefusedN | XpbdIncrementalPotentialIterationLimitN | XpbdIncrementalPotentialLineSearchExhaustedN | XpbdIncrementalPotentialLineSearchRefusedN | XpbdIncrementalPotentialStalledN; /** * Bounded Float64 first-order reference for a compiled packed problem. * * The default policy selects `direction = -gradient`. An authored policy may * choose another packed direction, while acceptance and typed * constitutive-domain backtracking remain delegated to Armijo. The routine * records every accepted iterate and never writes into live particles. */ export declare function minimizeXpbdIncrementalPotentialN(options: MinimizeXpbdIncrementalPotentialNOptions): XpbdIncrementalPotentialMinimizationResultN; export {}; //# sourceMappingURL=xpbd-incremental-potential-minimizer.d.ts.map