-
Notifications
You must be signed in to change notification settings - Fork 1
/
definitions.ts
143 lines (134 loc) · 5.16 KB
/
definitions.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import { BinaryOperator } from "./operators/binary";
import { UnaryOperator } from "./operators/unary";
/**
* Anything in an expression can be considered as a token.
* A tagging interface which all classes representing some mathematical
* object must implement.
*/
export interface Token {
/** The type of token `this` is representing. */
readonly type: "operator" | "expression" | "variable" | "constant";
}
/**
* Anything that has a value or can be later assigned a value.
* A tagging interface which all classes representing some mathematical object
* whose value can be evaluated, at run time or when user suppiles the value,
* must implement.
*/
export interface Evaluable extends Token {
/** The type of quantity with some way of evaluating a value `this` represents. */
readonly type: "expression" | "variable" | "constant";
/**
* The kind of physical quantity `this` implements.
*/
readonly quantity: string;
[x: string]: any;
}
/** Checks whether a given `Token` is an `Evaluable`. */
export function isEvaluable(e: Token): e is Evaluable {return e.type !== "operator"}
/**
* A variable is a symbolic representation of some quantity whose value we do
* not know yet. Something whose value is not fixed and could take different
* values depending upon the situation. This interface must be implemented by
* all classes representing varying/unknown values.
*/
export interface Variable extends Evaluable {
readonly type: "variable";
/** The string with which `this` is identified by. */
readonly name: string;
}
/** Checks whether a given `Evaluable` is a variable. */
export function isVariable(e: Evaluable): e is Variable {return e.type === "variable";}
/**
* A constant is such a quantity whose value is known and remains fixed always.
*/
export interface Constant extends Evaluable {
readonly type: "constant";
/** The fixed value `this` object will represent. */
readonly value: any;
/** The string with which `this` is identified by. For a constant, this value
* is optional. The implementing classes should take care that there is some
* default value assigned should the user choose not to initialise a [[Constant]]
* with a name.
*/
readonly name: string;
equals(that: Evaluable): boolean;
}
/** Checks whether a given `Evaluable` is a constant. */
export function isConstant(e: Evaluable): e is Constant {return e.type === "constant";}
/**
* An expression represents a concept whose value depends on one or more
* unknowns (variables). That "value" can be evaluated given the value(s) of
* the unknown(s). More abstractly, an expression is some combination of
* constants and variables to represent a quantity whose value depends on the
* values of the variables it depends on.
*
* As defined earlier, an expression is some combination of variables and constants.
* The thing which connects those bits together are operators. The Expression
* interface uses a tree structure to store the different operations which must
* be carried out on the operands. The postfix form of this tree would be
* identical to the postfix notation of the mathematical expression this object
* represents.
*/
export interface Expression extends Evaluable {
readonly type: "expression";
/** `Set` of `Variable` quantities `this` depends on. */
readonly arg_list: Set<Variable>;
readonly op: Operator;
/** Array of `Evaluable` quantity/quantities `this.op` operates on. */
readonly operands: Evaluable[];
/** Array of parameters needed by operator method other than the operands. */
readonly rest: any[];
/**
* The left hand side operand for `this.op`.
* @throws If `this.op` is a `UnaryOperator`.
*/
readonly lhs: Evaluable;
/**
* The right hand side operand for `this.op`.
* @throws If `this.op` is a `UnaryOperator`.
*/
readonly rhs: Evaluable;
/**
* The operand for `this.op`.
* @throws If `this.op` is a `BinaryOperator`.
*/
readonly arg: Evaluable;
/**
* Checks whether `this` expression object depends on the given `Variable`.
* @param v {Variable}
*/
isFunctionOf(v: Variable): boolean;
/**
* Evaluates `this` expression at the given values of the `Variable` quantities.
* @param values {Map<Variable, Constant>} The map from variables to constant values.
*/
at(values: Map<Variable, Constant>): Evaluable;
}
/** Checks whether a given `Evaluable` is an expression. */
export function isExpression(e: Evaluable): e is Expression {return e.type === "expression";}
/**
* All classes which handle some sort of numerical operations must implement
* this interface. This helps the global functions to recognise whether a certain
* operation (function) is defined for a particular type of argument.
*/
export abstract class Numerical {
/**
* Returns the class of which this object is an instance of.
*/
abstract classRef: any;
/**
* Checks whether a method exists on the object or as a static member of
* the class.
* @param methodName Name of the method.
*/
public getDefinition(methodName: string) {
if((<any>this)[methodName] !== undefined)
return "instance";
if(this.classRef[methodName] !== undefined)
return "static";
return "undefined";
}
}
/** The general operator type. */
export type Operator = UnaryOperator | BinaryOperator;