/** * Immutable expression AST. * * Invariants (maintained by the smart constructors, relied on everywhere): * - A Sum never contains a direct Sum child; a Product never contains a * direct Product child (auto-flatten). * - No Neg(Neg(x)) — double negation collapses to x. * - Sum/Product always have >= 2 children. Constructing with 0 children * yields the identity literal (0 / 1); with 1 child yields the child. * - Integer.value >= 0. Negative literals are canonically Neg(Integer). * - Every node has a stable, tree-unique id. Operations that rebuild a * tree must preserve the ids of untouched subtrees (use the * *-PreservingId helpers, never re-create nodes you didn't change). */ export type NodeId = string; export declare function freshId(): NodeId; export interface Integer { readonly kind: "int"; readonly id: NodeId; /** Always >= 0; negative values are represented as Neg(Integer). */ readonly value: bigint; } export interface Variable { readonly kind: "var"; readonly id: NodeId; readonly name: string; } export interface Sum { readonly kind: "sum"; readonly id: NodeId; /** N-ary; never contains a direct Sum child; length >= 2. */ readonly children: readonly Expr[]; } export interface Product { readonly kind: "product"; readonly id: NodeId; /** N-ary; never contains a direct Product child; length >= 2. */ readonly children: readonly Expr[]; } export interface Neg { readonly kind: "neg"; readonly id: NodeId; /** Never itself a Neg. */ readonly child: Expr; } export interface Fraction { readonly kind: "fraction"; readonly id: NodeId; /** Implicit products; an empty list means 1. */ readonly num: readonly Expr[]; readonly den: readonly Expr[]; } export interface Pow { readonly kind: "pow"; readonly id: NodeId; readonly base: Expr; readonly exp: Expr; } export interface Sqrt { readonly kind: "sqrt"; readonly id: NodeId; readonly child: Expr; } /** An nth-root radical ⁿ√x. Degree n ≥ 3; squares are their own node (`Sqrt`). * The index is metadata (not an addressable child) — you simplify the radical, * you don't drag its index. */ export interface Root { readonly kind: "root"; readonly id: NodeId; readonly index: bigint; readonly radicand: Expr; } /** The relation between the two sides. Inequalities are first-class. */ export type RelationKind = "=" | "<" | "≤" | ">" | "≥"; /** a R b ⇔ b flip(R) a; also what multiplying by a negative does. */ export declare function flipRelation(r: RelationKind): RelationKind; export interface Equation { readonly kind: "equation"; readonly id: NodeId; readonly lhs: Expr; readonly rhs: Expr; readonly relation: RelationKind; } /** Expressions that can appear inside other expressions. */ export type Expr = Integer | Variable | Sum | Product | Neg | Fraction | Pow | Sqrt | Root; /** Anything addressable in a tree. Equation only ever appears at the root. */ export type Node = Expr | Equation; /** Integer literal; negative inputs canonicalize to Neg(Integer). */ export declare function int(value: bigint | number): Expr; export declare function variable(name: string): Variable; /** * N-ary sum. Flattens direct Sum children; 0 children -> 0; 1 child -> the * child itself (id preserved). */ export declare function sum(children: readonly Expr[]): Expr; /** * N-ary product. Flattens direct Product children; 0 children -> 1; 1 child * -> the child itself (id preserved). */ export declare function product(children: readonly Expr[]): Expr; /** Negation; collapses Neg(Neg(x)) to x (x keeps its id). */ export declare function neg(child: Expr): Expr; export declare function fraction(num: readonly Expr[], den: readonly Expr[]): Fraction; export declare function pow(base: Expr, exp: Expr): Pow; export declare function sqrt(child: Expr): Sqrt; /** An nth-root radical ⁿ√x, for n ≥ 3 (squares use `sqrt`). */ export declare function root(index: bigint, radicand: Expr): Root; export declare function equation(lhs: Expr, rhs: Expr, relation?: RelationKind): Equation; /** * Rebuild a Sum/Product around a new child list, keeping the original node's * id when the node survives. Collapses to the identity literal / single child * exactly like the smart constructors. */ export declare function rebuildNary(original: Sum | Product, children: readonly Expr[]): Expr; /** * Replace the node with id `targetId` by `replacement`. All ancestors of the * target are rebuilt with their original ids; every other subtree is reused * untouched (same object identity, same ids). * * The caller is responsible for the replacement keeping the tree invariants * (e.g. don't put a Sum directly under a Sum). Throws if `targetId` is not in * the tree, or if the replacement of a child position would need to be an * Equation. */ export declare function replaceNode(root: Equation, targetId: NodeId, replacement: Expr): Equation; /** * Like replaceNode, but repairs what a substitution can break at the splice * point: a Neg replacement under a Neg parent collapses both (no * Neg(Neg(x))), a Sum/Product replacement under a same-kind parent flattens * into it, and a Product replacement inside a Fraction list spreads into the * list (the lists ARE implicit products, and rules pair individual list * elements — a nested Product would strand its factors out of reach). One * level is always enough because the surrounding tree already satisfies the * invariants. */ export declare function replaceTermRespectingInvariants(root: Equation, targetId: NodeId, replacement: Expr): Equation; /** Deep copy with all-new ids (for inserting a second copy of a subtree). */ export declare function cloneFresh(node: Expr): Expr; /** Direct child expressions of a node, in display order. */ export declare function childrenOf(node: Node): readonly Expr[]; /** Pre-order traversal of every node in the tree (including the root). */ export declare function allNodes(root: Node): Generator; /** The node whose child list contains `id`, or undefined for the root / missing ids. */ export declare function findParent(root: Node, id: NodeId): Node | undefined; export declare function findById(root: Node, id: NodeId): Node | undefined; /** All variable names appearing in the tree. */ export declare function variablesIn(root: Node): Set; /** Compact debug/description rendering. Not a UI concern — UI does layout. */ export declare function exprToString(node: Node): string; /** * Structural equality. Ignores node ids. Sum and Product (and Fraction's * num/den lists, which are implicit products) compare their children as * multisets — order-insensitive. Equation sides are ordered (a=b ≠ b=a). */ export declare function eq(a: Node, b: Node): boolean; /** Returns a list of invariant violations (empty = healthy tree). */ export declare function invariantViolations(root: Node): string[]; //# sourceMappingURL=expr.d.ts.map