@stemcmicro/core
Version:
Computer Algebra System in TypeScript
544 lines (524 loc) • 17.3 kB
TypeScript
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 };