stemcmicro
Version:
Computer Algebra System in TypeScript
810 lines (795 loc) • 24.5 kB
TypeScript
import { Native } from 'math-expression-native';
export { NATIVE_MAX, NATIVE_MIN, Native, code_from_native_sym, is_native_sym, native_sym } from 'math-expression-native';
import { Sym, CellHost, Tensor, Cell } from 'math-expression-atoms';
import { LambdaExpr, CompareFn as CompareFn$1, ExprHandler, ExprContext } from 'math-expression-context';
import { U, Cons, Shareable, Atom } from 'math-expression-tree';
declare enum SyntaxKind {
/**
* ClojureScript Language.
*/
ClojureScript = 1,
/**
* Eigenmath Scripting Language by George Weigt.
*/
Eigenmath = 2,
/**
* EcmaScript Language
*/
EcmaScript = 3,
/**
* Python Scripting Language
*/
PythonScript = 4
}
declare function human_readable_syntax_kind(syntaxKind: SyntaxKind): "ClojureScript" | "EcmaScript" | "Eigenmath" | "PythonScript";
declare const syntaxKinds: SyntaxKind[];
declare class Stack<T> {
#private;
tos: number;
constructor(elements?: T[]);
get length(): number;
set length(length: number);
get top(): T;
getAt(i: number): T;
setAt(i: number, element: T): void;
peek(index: number): T;
push(element: T): void;
pushItems(items: T[]): void;
pop(): T;
popItems(n: number): T[];
/**
* [a,b,c,d,e] => [a,b,d,e,c] (n=3)
*/
rotateL(n: number): void;
/**
* [a,b,c,d,e] => [a,b,e,c,d] (n=3)
*/
rotateR(n: number): void;
copy(): Stack<T>;
some(predicate: (value: T, index: number, array: T[]) => boolean): boolean;
splice(start: number, deleteCount?: number): T[];
/**
* Changes the order of the top two elements on the stack.
*/
swap(): void;
}
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: ExprEngineListener): void;
removeListener(listener: ExprEngineListener): void;
}
interface ProgramControl {
compareFn(opr: Sym): CompareFn$1;
getDirective(directive: number): number;
pushDirective(directive: number, value: number): void;
popDirective(): void;
getSymbolPrintName(sym: Sym): string;
}
interface ProgramStack extends Shareable {
get length(): number;
set length(length: number);
concat(exprs: U[]): void;
get isatom(): boolean;
get iscons(): boolean;
get istrue(): boolean;
dupl(): void;
peek(): U;
pop(): U;
push(expr: U): void;
head(): void;
rest(): void;
rotateL(n: number): void;
rotateR(n: number): void;
swap(): void;
getAt(i: number): U;
setAt(i: number, expr: U): void;
splice(start: number, deleteCount?: number): U[];
}
interface ProgramEnv extends Shareable {
clearBindings(): void;
executeProlog(script: string[]): void;
getBinding(opr: Sym, target: Cons): U;
getUserFunction(name: Sym): U;
hasBinding(opr: Sym, target: Cons): boolean;
hasUserFunction(name: Sym): boolean;
setBinding(opr: Sym, binding: U): void;
setUserFunction(name: Sym, userfunc: U): void;
defineUserSymbol(name: Sym): void;
handlerFor<T extends U>(expr: T): ExprHandler<T>;
/**
* If a stack is provided, the computed value is pushed onto the stack and nil is returned.
*/
valueOf(expr: U, stack?: Pick<ProgramStack, "push">): U;
hasState(key: string): boolean;
getState(key: string): Shareable;
setState(key: string, value: Shareable): void;
}
interface StackFunction {
(x: Cons, env: ProgramEnv, ctrl: ProgramControl, $: ProgramStack): void;
}
interface ProgramIO {
get inbuf(): string;
set inbuf(inbuf: string);
get listeners(): ExprEngineListener[];
get trace1(): number;
set trace1(trace1: number);
get trace2(): number;
set trace2(trace2: number);
}
interface EnvConfig {
allowUndeclaredVars: UndeclaredVars;
assumes: {
[name: string]: Partial<Predicates>;
};
dependencies: FEATURE[];
enable: Directive[];
disable: Directive[];
noOptimize: boolean;
useCaretForExponentiation: boolean;
useDerivativeShorthandLowerD: boolean;
useIntegersForPredicates: boolean;
useParenForTensors: boolean;
syntaxKind?: SyntaxKind;
}
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";
/**
* Determines how an expression is evaluated.
*/
declare enum Directive {
/**
* Convert familiar expressions to canonical form. Mutually exclusive with familiarize.
*/
canonicalize = 0,
/**
* Replace sin with cos. Mutually exclusive with convertCosToSim.
*/
convertSinToCos = 1,
/**
* Replace cos with sin. Mutually exclusive with convertSinToCos.
*/
convertCosToSin = 2,
/**
* Convert canonical expressions to familiar form. Mutually exclusive with canonicalize.
*/
familiarize = 3,
/**
* Is not the same as the expand function.
* Mutually exclusive with factoring.
*/
expanding = 4,
/**
* Determines whether abs(a + b + c ...) is expanded.
*/
expandAbsSum = 5,
/**
* Determines whether cos(a + b + c ...) is expanded.
*/
expandCosSum = 6,
/**
* Determines whether (a + b + c ...) raised to a positive integer exponent is expanded.
* The default is true.
*/
expandPowSum = 7,
/**
* Determines whether cos(a + b + c ...) is expanded.
*/
expandSinSum = 8,
/**
* Determines whether numeric types are converted to floating point numbers for numeric evaluation.
*
* The default value as false.
*/
evaluatingAsFloat = 9,
/**
* Determines whether complex numbers are driven towards clock form.
* The other possibilities are polar and rectanglular.
*
* The default value is false.
*/
complexAsClock = 10,
/**
* Determines whether complex numbers are driven towards polar form.
* The other possibilities are clock and rectanglular.
*
* The default value is false.
*/
complexAsPolar = 11,
/**
* Determines whether complex numbers are driven towards rectangular form.
* The other possibilities are clock and polar.
*
* The default value is false.
*/
complexAsRectangular = 12,
/**
* Determines whether exponential functions are converted ti exponential form.
*/
convertExpToTrig = 13,
/**
* Determines whether trigonometric functions are converted to exponential form.
*
* The default is false.
*/
convertTrigToExp = 14,
/**
* Determines whether zero terms are kept in sums in attempt to preserve the dynamic type.
* The alternative is to use a canonical zero value, usually that for rational numbers.
*
* The default value is false.
*/
keepZeroTermsInSums = 15,
/**
* Is not the same as the factor function.
* Mutually exclusive with expanding.
*/
factoring = 16,
/**
* Determines whether floating point numbers are rendered as EcmaScript numbers.
* If not, floating point numbers are rendered in a proprietary format.
*
* The default value is false.
*/
renderFloatAsEcmaScript = 17,
/**
* Determines whether caret token '^' will be used for exponentiation or for the exterior product.
* Using the caret token for exponetitation is common in mathematical tools but not in programming languages.
*
* The default value is false.
*/
useCaretForExponentiation = 18,
/**
* Determines whether test funtions will return Boo or Rat values.
*
* The default value is false.
*/
useIntegersForPredicates = 19,
useParenForTensors = 20,
depth = 21,
drawing = 22,
nonstop = 23,
forceFixedPrintout = 24,
maxFixedPrintoutDigits = 25,
printMode = 26,
codeGen = 27
}
/**
*
*/
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;
type KeywordRunner = ($: ExtensionEnv) => void;
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 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;
/**
* e.g. clearall
*/
defineKeyword(sym: Sym, runner: KeywordRunner): 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;
executeProlog(prolog: readonly string[]): void;
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 ParseConfig {
useCaretForExponentiation: boolean;
useParenForTensors: boolean;
explicitAssocAdd: boolean;
explicitAssocExt: boolean;
explicitAssocMul: boolean;
syntaxKind: SyntaxKind;
}
interface RenderConfig {
format: "Ascii" | "Human" | "Infix" | "LaTeX" | "SExpr" | "SVG";
useCaretForExponentiation: boolean;
useParenForTensors: boolean;
}
declare enum Concept {
Last = 1,
TTY = 2
}
interface AtomListener {
reset(from: U, to: U, source: Cell): void;
}
interface ExprEngineListener {
output(output: string): void;
}
interface ExprHandlerBuilder<T extends U> {
create(): ExprHandler<T>;
}
interface ExprEngine extends Pick<ProgramEnv, "clearBindings"> {
clearBindings(): void;
executeProlog(prolog: string[]): void;
executeScript(sourceText: string): {
values: U[];
prints: string[];
errors: Error[];
};
defineAtomHandler<T extends Atom>(builder: ExprHandlerBuilder<T>, type: string, guard: (expr: Atom) => boolean): void;
defineFunction(name: Sym, lambda: LambdaExpr): void;
parse(sourceText: string, options?: Partial<ParseConfig>): {
trees: U[];
errors: Error[];
};
parseModule(sourceText: string, options?: Partial<ParseConfig>): {
module: Cons;
errors: Error[];
};
simplify(expr: U): U;
valueOf(expr: U): U;
getBinding(opr: Sym, target: Cons): U;
hasBinding(opr: Sym, target: Cons): boolean;
setBinding(opr: Sym, binding: U): void;
hasUserFunction(name: Sym): boolean;
getUserFunction(name: Sym): U;
setUserFunction(name: Sym, userfunc: U): void;
symbol(concept: Concept): Sym;
renderAsString(expr: U, config?: Partial<RenderConfig>): string;
addAtomListener(listener: AtomListener): void;
removeAtomListener(listener: AtomListener): void;
addListener(listener: ExprEngineListener): void;
removeListener(listener: ExprEngineListener): void;
release(): void;
}
/**
* Determines the action upon attempts to access an undeclared variable.
*/
declare enum UndeclaredVars {
Err = 1,// ClojureScript
Nil = 2
}
interface EngineConfig {
allowUndeclaredVars: UndeclaredVars;
prolog: string[];
syntaxKind: SyntaxKind;
useCaretForExponentiation: boolean;
useDerivativeShorthandLowerD: boolean;
useIntegersForPredicates: boolean;
}
declare function create_engine(options?: Partial<EngineConfig>): ExprEngine;
/**
* @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;
/**
* Determines what kind of parser is used for the sourceText.
*/
syntaxKind?: SyntaxKind;
}
interface ScriptContextOptions extends ScriptExecuteOptions {
/**
* The default is ???.
*/
allowUndeclaredVars?: UndeclaredVars;
/**
* 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;
/**
*
*/
prolog?: string[];
/**
* 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;
}
interface ScriptContext {
readonly $: ExtensionEnv;
clearBindings(): void;
defineFunction(pattern: U, impl: LambdaExpr): void;
getSymbolProps(sym: Sym): Predicates;
getBinding(opr: Sym, target: Cons): U;
getSymbolsInfo(): {
sym: Sym;
value: U;
}[];
evaluate(tree: U, options?: ExprTransformOptions): {
value: U;
prints: string[];
errors: Error[];
};
executeProlog(prolog: string[]): void;
executeScript(sourceText: string, options?: ScriptExecuteOptions): {
values: U[];
prints: string[];
errors: Error[];
};
renderAsAscii(expr: U): string;
renderAsHuman(expr: U): string;
renderAsInfix(expr: U): string;
renderAsLaTeX(expr: U): string;
renderAsSExpr(expr: U): string;
simplify(expr: U): U;
addRef(): void;
release(): void;
}
/**
* TODO: The REP should migrate toward the ExprEngine API.
* @deprecated Used only by development REPL.
*/
declare function create_script_context(contextOptions?: ScriptContextOptions): ScriptContext;
export { type AtomListener, Concept, type EngineConfig, type ExprEngine, type ExprEngineListener, type ExprHandlerBuilder, type FEATURE, type ParseConfig, type RenderConfig, type Scope, Stack, State, Stepper, type StepperConfig, type StepperHandler, SyntaxKind, Thing, UndeclaredVars, create_engine, create_script_context, human_readable_syntax_kind, roots, syntaxKinds };