UNPKG

@stemcmicro/core

Version:

Computer Algebra System in TypeScript

544 lines (524 loc) 17.3 kB
import { Native } from '@stemcmicro/native'; export { NATIVE_MAX, NATIVE_MIN, Native, code_from_native_sym, is_native_sym, native_sym } from '@stemcmicro/native'; import { ExprContext, LambdaExpr, ExprHandler } from '@stemcmicro/context'; import { U, Cons, Atom } from '@stemcmicro/tree'; import { Directive } from '@stemcmicro/directive'; import * as _stemcmicro_atoms from '@stemcmicro/atoms'; import { CellHost, Tensor, Sym, Cell, Uom } from '@stemcmicro/atoms'; import { ProgramEnv, ProgramControl, ProgramIO, StackFunction, Stack, ProgramIOListener } from '@stemcmicro/stack'; export { create_algebra_as_blades } from '@stemcmicro/helpers'; type Sign = -1 | 0 | 1; type TFLAGS = number; /** * Corresponds to the 'name' property on an Atom. */ type FEATURE = "Blade" | "Boo" | "Cell" | "Flt" | "Imu" | "Map" | "Rat" | "Sym" | "Tensor" | "Uom"; declare const ALL_FEATURES: FEATURE[]; declare function directive_from_flag(value: boolean | undefined): number; /** * */ interface PrintHandler { print(...items: string[]): void; } type CompareFn = (lhs: U, rhs: U) => Sign; /** * */ interface ExprComparator { compare(lhs: U, rhs: U, $: ExtensionEnv): Sign; } /** * Not to be confused with a LambdaExpr. * Here the first argument is the expression including the operator. */ type EvalFunction = (expr: Cons, $: ExtensionEnv) => U; interface Predicates { /** * An algebraic number is any number that is a root of a non-zero polynomial having rational coefficients. * All algebraic numbers are complex. * An algebraic number may or may not be real. * Includes all rational numbers. */ algebraic: boolean; /** * An element of the field of antihermitian operators. * Defaults to false. */ antihermitian: boolean; /** * A commutative expression. * A commutative expression commutes with all other expressions under multiplication. * If an expression a has commutative then a * b == b * a for any other expression b (even if b is not commutative). * Unlike all other assumptions predicates commutative must always be true or false and can never be undefined. * Also unlike all other predicates commutative defaults to true. */ commutative: boolean; /** * A complex number is any number of the form x+i*y where x and y are real. * All complex numbers are finite. Includes all real numbers. */ complex: boolean; extended_negative: boolean; extended_nonnegative: boolean; extended_nonpositive: boolean; extended_nonzero: boolean; extended_positive: boolean; /** * A finite expression. * Any expression that is not infinite is considered finite. */ finite: boolean; /** * An element of the field of Hermitian operators. */ hermitian: boolean; /** * The extension of the complex numbers to include infinitesimals and infinite numbers. */ hypercomplex: boolean; /** * The extension of the real numbers to include infinitesimals and infinite numbers. */ hyperreal: boolean; imaginary: boolean; /** * An infinite expression. */ infinite: boolean; infinitesimal: boolean; integer: boolean; irrational: boolean; negative: boolean; noninteger: boolean; nonnegative: boolean; nonpositive: boolean; nonzero: boolean; /** * A real number that is greater than zero. * All positive numbers are finite so infinity is not positive. */ positive: boolean; rational: boolean; real: boolean; /** * A complex number that is not algebraic. * All transcendental numbers are complex. * A transcendental number may or may not be real but can never be rational. * Defaults to false. */ transcendental: boolean; zero: boolean; } interface AtomListener { reset(from: U, to: U, source: Cell): void; } /** * */ interface ExtensionEnv extends ExprContext, ProgramEnv, ProgramControl, Pick<ProgramIO, "listeners"> { addAtomListener(subscriber: AtomListener): void; removeAtomListener(subscriber: AtomListener): void; getCellHost(): CellHost; setCellHost(host: CellHost): void; getProlog(): readonly string[]; getPrintHandler(): PrintHandler; setPrintHandler(handler: PrintHandler): void; abs(expr: U): U; algebra(metric: Tensor<U>, labels: Tensor<U>): Tensor<U>; /** * */ add(...args: U[]): U; arccos(expr: U): U; arcsin(expr: U): U; arctan(expr: U): U; arg(expr: U): U; clock(expr: U): U; conj(expr: U): U; cos(expr: U): U; clearBindings(): void; clearOperators(): void; compareFn(opr: Sym): CompareFn; component(tensor: Tensor<U>, indices: U): U; /** * Defines the implementation of a function that is used to transform (name ...) expressions. */ defineEvalFunction(opr: Sym, evalFunction: EvalFunction): void; defineFunction(match: U, lambda: LambdaExpr): void; defineStackFunction(opr: Sym, stackFunction: StackFunction): void; defineExtension(builder: ExtensionBuilder<U>, immediate?: boolean): void; defineUserSymbol(name: Sym): void; derivedEnv(): ExtensionEnv; divide(lhs: U, rhs: U): U; /** * */ equals(lhs: U, rhs: U): boolean; evaluate(opr: Native, ...args: U[]): U; exp(expr: U): U; factor(expr: U): U; /** * */ factorize(poly: U, x: U): U; float(expr: U): U; getDirective(directive: number): number; getSymbolPredicates(sym: Sym): Predicates; /** * Used during rendering. */ getSymbolPrintName(sym: Sym): string; getSymbolUsrFunc(sym: Sym): U; getSymbolsInfo(): { sym: Sym; value: U; }[]; /** * Used to make the environment ready after all operator builders have been added. */ buildOperators(): void; im(expr: U): U; /** * */ inner(lhs: U, rhs: U): U; /** * Generalized predicate testing. * @param predicate * @param expr */ is(predicate: Sym, expr: U): boolean; iscomplex(expr: U): boolean; isExpanding(): boolean; isFactoring(): boolean; /** * Meaning is imaginary valued. i.e. evaluates to i times a real number. */ isimag(expr: U): boolean; isinfinite(expr: U): boolean; isinfinitesimal(expr: U): boolean; isminusone(expr: U): boolean; isnegative(expr: U): boolean; /** * @deprecated The implementation doesn't need a full context. */ isone(expr: U): boolean; ispositive(expr: U): boolean; isreal(expr: U): boolean; /** * Determines whether expr is scalar-valued. */ isscalar(expr: U): boolean; /** * A convenience for appling the predicate function to the expression. */ iszero(expr: U): boolean; /** * */ log(expr: U): U; /** * */ multiply(...args: U[]): U; /** * */ negate(expr: U): U; extensionFor(expr: U): Extension<U> | undefined; /** * */ outer(...args: U[]): U; polar(expr: U): U; /** * */ power(base: U, expo: U): U; re(expr: U): U; rect(expr: U): U; remove(varName: Sym): void; pushDirective(directive: number, value: number): void; popDirective(): void; setSymbolOrder(sym: Sym, order: ExprComparator): void; setSymbolPredicates(sym: Sym, predicates: Partial<Predicates>): void; setSymbolPrintName(sym: Sym, printName: string): void; setSymbolUsrFunc(sym: Sym, usrfunc: U): void; simplify(expr: U): U; sin(expr: U): U; sqrt(expr: U): U; st(expr: U): U; subst(newExpr: U, oldExpr: U, expr: U): U; /** * */ subtract(lhs: U, rhs: U): U; toInfixString(expr: U): string; toLatexString(expr: U): string; toSExprString(expr: U): string; transform(expr: U): [TFLAGS, U]; valueOf(expr: U): U; } /** * The interface that MUST be implemented by extensions to the environment. * The type parameter,T, allows you to constrain the argument types of the * methods that you implement. e.g. If isKind() only matches a Cons, then set T * to be Cons. If isKind() only matches Sym, set T to be Sym. In more general * cases, use a more general type. The rule is that isKind determines which expression are matched, * and when the other method are called (they all contain at least one argument that matches T), * it determines the possible dynamic types for T. */ interface ExtensionBuilder<T extends U> { create(config: Readonly<EnvConfig>): Extension<T>; } /** * */ interface Extension<T extends U> extends ExprHandler<T> { readonly hash: string; readonly name: string; readonly phases?: number; readonly dependencies?: FEATURE[]; iscons(): this is Extension<Cons>; operator(): Sym; isKind(expr: U, env: ExprContext): boolean; toHumanString(expr: T, env: ExprContext): string; toInfixString(expr: T, env: ExprContext): string; toLatexString(expr: T, env: ExprContext): string; toListString(expr: T, env: ExprContext): string; /** * This method assumes that the opr is in the operator slot of a combination. * Except for Sym, that's an experimental proposition. */ evaluate(opr: T, argList: Cons, $: ExprContext): [TFLAGS, U]; transform(expr: T, $: ExprContext): [TFLAGS, U]; valueOf(expr: T, $: ExprContext): U; } interface EnvConfig { allowUndeclaredVars: "Err" | "Nil"; assumes: { [name: string]: Partial<Predicates>; }; dependencies: FEATURE[]; enable: Directive[]; disable: Directive[]; noOptimize: boolean; useCaretForExponentiation: boolean; useDerivativeShorthandLowerD: boolean; useIntegersForPredicates: boolean; useParenForTensors: boolean; } interface ExprHandlerBuilder<T extends U> { create(): ExprHandler<T>; } declare class AtomExtensionBuilderFromExprHandlerBuilder<T extends Atom> implements ExtensionBuilder<T> { readonly builder: ExprHandlerBuilder<T>; readonly type: string; readonly guard: (expr: Atom) => boolean; constructor(builder: ExprHandlerBuilder<T>, type: string, guard: (expr: Atom) => boolean); create(config: Readonly<EnvConfig>): Extension<T>; } interface EnvOptions { allowUndeclaredVars: "Err" | "Nil"; assumes?: { [name: string]: Partial<Predicates>; }; dependencies?: FEATURE[]; enable?: Directive[]; disable?: Directive[]; noOptimize?: boolean; useCaretForExponentiation?: boolean; useDerivativeShorthandLowerD?: boolean; useIntegersForPredicates?: boolean; useParenForTensors?: boolean; } declare function create_env(options?: EnvOptions): ExtensionEnv; declare function simplify(x: U, env: ExprContext): U; declare function assert_sym(expr: U): Sym; type TYPE_UOM_NAME = "ampere" | "candela" | "coulomb" | "farad" | "henry" | "hertz" | "joule" | "kelvin" | "kilogram" | "meter" | "metre" | "mole" | "newton" | "ohm" | "one" | "pascal" | "second" | "siemens" | "tesla" | "volt" | "watt" | "weber"; declare const UOM_NAMES: TYPE_UOM_NAME[]; declare function create_uom(name: TYPE_UOM_NAME): Uom; /** * */ interface PrintConfig { pushDirective(directive: number, value: number): void; popDirective(): void; getBinding(opr: Sym, target: Cons): U; getDirective(directive: number): number; getSymbolPrintName(sym: Sym): string; handlerFor<T extends U>(expr: T): ExprHandler<T>; valueOf(expr: U): U; } declare function render_as_ascii(expr: U, $: PrintConfig): string; declare function render_as_human(expr: U, $: PrintConfig): string; declare function render_as_infix(expr: U, $: PrintConfig): string; declare function render_as_latex(expr: U, $: PrintConfig): string; /** * The standard way of serializing to s-expr format. * @param expr The expression to be rendered. * @param $ The extension environment. */ declare function render_as_sexpr(expr: U, $: PrintConfig): string; /** * @param p * @param x * @returns */ declare function roots(p: U, x: U, $: ExprContext): Tensor; interface ExprTransformOptions { autoExpand?: boolean; autoFactor?: boolean; /** * Directives that become enabled by setting to true. */ enable?: Directive[]; /** * Directives that become disabled by setting to false. */ disable?: Directive[]; useIntegersForPredicates?: boolean; } interface ScriptExecuteOptions extends ExprTransformOptions { /** * Determines whether execptions are caught and returned in the errors property. */ catchExceptions?: boolean; } interface ScriptContextOptions extends ScriptExecuteOptions { /** * The default is ???. */ allowUndeclaredVars?: "Err" | "Nil"; /** * The assumptions about unbound symbols. */ assumes?: { [name: string]: Partial<Predicates>; }; dependencies?: string[]; /** * Determines whether the circumflex (caret) character, '^', will be used during parsing to denote exponentiation. * The alternative is to use '**', freeing the caret character for use with outer products which is convenient * in applications using Geometric Algebra. The default value is false. */ useCaretForExponentiation?: boolean; useDerivativeShorthandLowerD?: boolean; /** * Determines whether test functions will return boolean or integer values. * * The default is false. */ useIntegersForPredicates?: boolean; /** * Determines whether parentheses, "(" and ")", or square brackets, "[" and "]", will be used to delimit tensors. */ useParenForTensors?: boolean; } declare function init_env($: ExtensionEnv, options?: ScriptContextOptions): void; declare function env_term($: ExtensionEnv): void; /** * Evaluates the parse tree using the operators defined in the environment. * @param tree The parse tree. * @param options The opti * @param $ The environment defining the operators. * @returns The return values (zero or one), print outputs, and errors. */ declare function transform_tree(tree: U, options: ExprTransformOptions, $: ExtensionEnv): { value: U; prints: string[]; errors: Error[]; }; /** * 'last' */ declare const RESERVED_KEYWORD_LAST: _stemcmicro_atoms.Sym; /** * 'tty' */ declare const RESERVED_KEYWORD_TTY: _stemcmicro_atoms.Sym; declare class Thing { readonly proto: unknown; getter: unknown; setter: unknown; properties: unknown; constructor(proto: unknown); } interface Scope { thing: Thing; evaluate(opr: Native, ...args: U[]): U; hasBinding(sym: Sym, target: Cons): boolean; getBinding(sym: Sym, target: Cons): U; setBinding(sym: Sym, binding: U): void; hasUserFunction(sym: Sym): boolean; getUserFunction(sym: Sym): U; setUserFunction(sym: Sym, usrfunc: U): void; valueOf(expr: U): U; } declare class State { readonly input: U; readonly $: Scope; /** * For use by evaluators. Let's the evaluator know it is being called for the first time. * The evaluator is responsible for updating the value to false if it chooses to use it. */ firstTime: boolean; /** * MUST be initialized to false. */ done: boolean; doneArg: boolean[]; /** * For use by evaluators to keep track of evaluated arguments. */ argValues: U[]; /** * Contains the value from the previous invocation of the evaluator. */ value: U; /** * The inputs from the invocation of the module. */ inputs: U[]; /** * The values from the invocation of the module. */ values: U[]; doneCallee: number; doneArgs: boolean; funcThis: unknown; func: unknown; arguments: unknown; constructor(input: U, $: Scope); } interface StepperHandler { atom(after: U, before: U): void; } interface StepperConfig { allowUndeclaredVars: boolean; } declare class Stepper { #private; POLYFILL_TIMEOUT: number; /** * @param module * @param options * @param initFunc */ constructor(module: Cons, options?: Partial<StepperConfig>, initFunc?: (runner: Stepper, globalObject: Thing) => void); createScope(node: unknown, parentScope: Scope): Scope; createObjectProto(proto: unknown | null): Thing; defineFunction(name: Sym, lambda: LambdaExpr): void; initGlobal(globalObject: Thing): void; run(handler?: StepperHandler): boolean; /** * Execute one step of the interpreter. * @returns true if there are more instructions to execute. */ next(handler?: StepperHandler): boolean; get stack(): Stack<State>; addListener(listener: ProgramIOListener): void; removeListener(listener: ProgramIOListener): void; } export { ALL_FEATURES, AtomExtensionBuilderFromExprHandlerBuilder, type ExtensionEnv, type FEATURE, RESERVED_KEYWORD_LAST, RESERVED_KEYWORD_TTY, type Scope, State, Stepper, type StepperConfig, type StepperHandler, Thing, UOM_NAMES, assert_sym, create_env, create_uom, directive_from_flag, env_term, init_env, render_as_ascii, render_as_human, render_as_infix, render_as_latex, render_as_sexpr, roots, simplify, transform_tree };