verbena-complex 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +1 -7
- package/lib/index.js +43 -121
- package/lib/lib.d.ts +22 -0
- package/lib/lib.js +87 -0
- package/package.json +5 -6
- package/readme.md +22 -22
package/lib/index.d.ts
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
import { Complex } from 'complex.js';
|
|
2
|
-
import { Library } from 'verbena/lib';
|
|
3
2
|
import { vbFunction } from 'verbena/function';
|
|
4
|
-
|
|
5
|
-
* Library for complex functions.
|
|
6
|
-
*
|
|
7
|
-
* Includes complex operations and functions, as well as constants for i, pi and e.
|
|
8
|
-
*/
|
|
9
|
-
export declare const complexLib: Library<Complex>;
|
|
3
|
+
export * from './lib';
|
|
10
4
|
export declare function ComplexFunction(source: string): vbFunction<Complex>;
|
package/lib/index.js
CHANGED
|
@@ -1,130 +1,52 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ComplexFunction =
|
|
4
|
-
const
|
|
5
|
-
const lib_1 = require("verbena/lib");
|
|
17
|
+
exports.ComplexFunction = ComplexFunction;
|
|
18
|
+
const function_1 = require("verbena/function");
|
|
6
19
|
const lexer_1 = require("verbena/lexer");
|
|
7
|
-
const parser_1 = require("verbena/parser");
|
|
8
20
|
const compileFn_1 = require("verbena/compileFn");
|
|
9
21
|
const token_1 = require("verbena/token");
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*
|
|
13
|
-
* Includes complex operations and functions, as well as constants for i, pi and e.
|
|
14
|
-
*/
|
|
15
|
-
exports.complexLib = {
|
|
16
|
-
operations: {
|
|
17
|
-
add: forceComplex((l, r) => l.add(r)),
|
|
18
|
-
sub: forceComplex((l, r) => l.sub(r)),
|
|
19
|
-
mul: forceComplex((l, r) => l.mul(r)),
|
|
20
|
-
div: forceComplex((l, r) => l.div(r)),
|
|
21
|
-
pow: forceComplex((l, r) => l.pow(r)),
|
|
22
|
-
neg: forceComplex((z) => z.mul(-1)),
|
|
23
|
-
mod: forceReal((x, y) => x % y),
|
|
24
|
-
fac: forceReal(lib_1.standard.functions.fac)
|
|
25
|
-
},
|
|
26
|
-
functions: {
|
|
27
|
-
re: forceComplex((z) => (0, complex_js_1.Complex)(z.re)),
|
|
28
|
-
im: forceComplex((z) => (0, complex_js_1.Complex)(0, z.im)),
|
|
29
|
-
abs: forceComplex((z) => (0, complex_js_1.Complex)(z.abs())),
|
|
30
|
-
acos: forceComplex((z) => z.acos()),
|
|
31
|
-
acosh: forceComplex((z) => z.acosh()),
|
|
32
|
-
asin: forceComplex((z) => z.asin()),
|
|
33
|
-
asinh: forceComplex((z) => z.asinh()),
|
|
34
|
-
atan: forceComplex((z) => z.atan()),
|
|
35
|
-
atanh: forceComplex((z) => z.atanh()),
|
|
36
|
-
cbrt: forceComplex((z) => z.pow(1 / 3)),
|
|
37
|
-
ceil: forceComplex((z) => z.ceil(0)),
|
|
38
|
-
cos: forceComplex((z) => z.cos()),
|
|
39
|
-
cosh: forceComplex((z) => z.cosh()),
|
|
40
|
-
exp: forceComplex((z) => z.exp()),
|
|
41
|
-
floor: forceComplex((z) => z.floor(0)),
|
|
42
|
-
hypot: forceComplex((...zs) => zs.reduce((acc, z) => acc.add(z.pow(2)), (0, complex_js_1.Complex)(0)).sqrt()),
|
|
43
|
-
log_: forceComplex((z, b = (0, complex_js_1.Complex)(10)) => z.log().div(b.log())),
|
|
44
|
-
ln: forceComplex((z) => z.log()),
|
|
45
|
-
max: forceReal(Math.max),
|
|
46
|
-
min: forceReal(Math.min),
|
|
47
|
-
pow: forceComplex((z, p) => z.pow(p)),
|
|
48
|
-
random: () => (0, complex_js_1.Complex)(Math.random()),
|
|
49
|
-
round: forceComplex((z) => z.round(0)),
|
|
50
|
-
sign: forceComplex((z) => z.sign()),
|
|
51
|
-
sin: forceComplex((z) => z.sin()),
|
|
52
|
-
sinh: forceComplex((z) => z.sinh()),
|
|
53
|
-
sqrt: forceComplex((z) => z.sqrt()),
|
|
54
|
-
tan: forceComplex((z) => z.tan()),
|
|
55
|
-
tanh: forceComplex((z) => z.tanh())
|
|
56
|
-
},
|
|
57
|
-
constants: {
|
|
58
|
-
i: complex_js_1.Complex.I,
|
|
59
|
-
pi: complex_js_1.Complex.PI,
|
|
60
|
-
e: complex_js_1.Complex.E,
|
|
61
|
-
}
|
|
62
|
-
};
|
|
22
|
+
const lib_1 = require("./lib");
|
|
23
|
+
__exportStar(require("./lib"), exports);
|
|
63
24
|
function ComplexFunction(source) {
|
|
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
|
-
paramList: {
|
|
91
|
-
value: compiledFn.paramList,
|
|
92
|
-
writable: false,
|
|
93
|
-
enumerable: false
|
|
94
|
-
},
|
|
95
|
-
body: {
|
|
96
|
-
value: compiledFn.body,
|
|
97
|
-
writable: false,
|
|
98
|
-
enumerable: false
|
|
25
|
+
return (0, function_1.Function)(source, {
|
|
26
|
+
lib: lib_1.complexLib,
|
|
27
|
+
scanner: (source, lib) => (0, lexer_1.scan)(source, lib).map(token => {
|
|
28
|
+
// Little hack to allow implicit of identifiers with i, like ix
|
|
29
|
+
if (token.type == token_1.TokenType.IDENTIFIER && token.lexeme == 'i') {
|
|
30
|
+
token.type = token_1.TokenType.CONSTANT;
|
|
31
|
+
}
|
|
32
|
+
return token;
|
|
33
|
+
}),
|
|
34
|
+
compiler: (decl, lib) => {
|
|
35
|
+
// Error if clauses
|
|
36
|
+
if (decl.clauses.length > 0) {
|
|
37
|
+
throw Error("Function clauses are not allowed in complex functions");
|
|
38
|
+
}
|
|
39
|
+
// Compile the function as a real function using the complex library
|
|
40
|
+
let compiledFn = (0, compileFn_1.compileFn)(decl, lib);
|
|
41
|
+
// Force conversion of function arguments and result to a complex number
|
|
42
|
+
let complexFn = (0, lib_1.forceComplex)((...args) => compiledFn(...args));
|
|
43
|
+
// Copy over the real function's properties to the complex one
|
|
44
|
+
Object.defineProperties(complexFn, Object.fromEntries(Reflect.ownKeys(compiledFn).map(prop => [prop, {
|
|
45
|
+
value: compiledFn[prop],
|
|
46
|
+
writable: false,
|
|
47
|
+
enumerable: false
|
|
48
|
+
}])));
|
|
49
|
+
return complexFn;
|
|
99
50
|
}
|
|
100
51
|
});
|
|
101
|
-
return complexFn;
|
|
102
|
-
}
|
|
103
|
-
exports.ComplexFunction = ComplexFunction;
|
|
104
|
-
/**
|
|
105
|
-
* Utility function to wrap a complex function, converting all its arguments to a Complex value.
|
|
106
|
-
*
|
|
107
|
-
* @param f Complex function
|
|
108
|
-
* @returns `f` with all its parameters converted to Complex
|
|
109
|
-
*/
|
|
110
|
-
function forceComplex(f) {
|
|
111
|
-
return (...args) => f(...args.map(z => (0, complex_js_1.Complex)(z)));
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Utility function to wrap a real function, forcing all its arguments to be real numbers.
|
|
115
|
-
*
|
|
116
|
-
* @param f Real function
|
|
117
|
-
* @returns `f`, but will throw an error on any complex arguments
|
|
118
|
-
*/
|
|
119
|
-
function forceReal(f) {
|
|
120
|
-
return (...args) => {
|
|
121
|
-
let realArgs = args.map(z => {
|
|
122
|
-
z = (0, complex_js_1.Complex)(z);
|
|
123
|
-
if (z.im != 0) {
|
|
124
|
-
throw Error("complex " + f.name + "is unsupported");
|
|
125
|
-
}
|
|
126
|
-
return z.re;
|
|
127
|
-
});
|
|
128
|
-
return (0, complex_js_1.Complex)(f(...realArgs));
|
|
129
|
-
};
|
|
130
52
|
}
|
package/lib/lib.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Complex } from 'complex.js';
|
|
2
|
+
import { Library } from 'verbena/lib';
|
|
3
|
+
/**
|
|
4
|
+
* Library for complex functions.
|
|
5
|
+
*
|
|
6
|
+
* Includes complex operations and functions, as well as constants for i, pi and e.
|
|
7
|
+
*/
|
|
8
|
+
export declare const complexLib: Library<Complex>;
|
|
9
|
+
/**
|
|
10
|
+
* Utility function to wrap a complex function, converting all its arguments to a Complex value.
|
|
11
|
+
*
|
|
12
|
+
* @param f Complex function
|
|
13
|
+
* @returns `f` with all its parameters converted to Complex
|
|
14
|
+
*/
|
|
15
|
+
export declare function forceComplex(f: (...args: Complex[]) => Complex | number): (...args: Complex[]) => Complex;
|
|
16
|
+
/**
|
|
17
|
+
* Utility function to wrap a real function, forcing all its arguments to be real numbers.
|
|
18
|
+
*
|
|
19
|
+
* @param f Real function
|
|
20
|
+
* @returns `f`, but will throw an error on any complex arguments
|
|
21
|
+
*/
|
|
22
|
+
export declare function forceReal(f: (...args: number[]) => number): (...args: Complex[]) => Complex;
|
package/lib/lib.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.complexLib = void 0;
|
|
4
|
+
exports.forceComplex = forceComplex;
|
|
5
|
+
exports.forceReal = forceReal;
|
|
6
|
+
const complex_js_1 = require("complex.js");
|
|
7
|
+
const lib_1 = require("verbena/lib");
|
|
8
|
+
/**
|
|
9
|
+
* Library for complex functions.
|
|
10
|
+
*
|
|
11
|
+
* Includes complex operations and functions, as well as constants for i, pi and e.
|
|
12
|
+
*/
|
|
13
|
+
exports.complexLib = {
|
|
14
|
+
operations: {
|
|
15
|
+
add: forceComplex((l, r) => l.add(r)),
|
|
16
|
+
sub: forceComplex((l, r) => l.sub(r)),
|
|
17
|
+
mul: forceComplex((l, r) => l.mul(r)),
|
|
18
|
+
div: forceComplex((l, r) => l.div(r)),
|
|
19
|
+
pow: forceComplex((l, r) => l.pow(r)),
|
|
20
|
+
neg: forceComplex((z) => z.mul(-1)),
|
|
21
|
+
mod: forceReal((x, y) => x % y),
|
|
22
|
+
fac: forceReal(lib_1.standard.functions.fac)
|
|
23
|
+
},
|
|
24
|
+
functions: {
|
|
25
|
+
re: forceComplex((z) => z.re),
|
|
26
|
+
im: forceComplex((z) => z.im),
|
|
27
|
+
abs: forceComplex((z) => z.abs()),
|
|
28
|
+
acos: forceComplex((z) => z.acos()),
|
|
29
|
+
acosh: forceComplex((z) => z.acosh()),
|
|
30
|
+
asin: forceComplex((z) => z.asin()),
|
|
31
|
+
asinh: forceComplex((z) => z.asinh()),
|
|
32
|
+
atan: forceComplex((z) => z.atan()),
|
|
33
|
+
atanh: forceComplex((z) => z.atanh()),
|
|
34
|
+
cbrt: forceComplex((z) => z.pow(1 / 3)),
|
|
35
|
+
ceil: forceComplex((z) => z.ceil(0)),
|
|
36
|
+
cos: forceComplex((z) => z.cos()),
|
|
37
|
+
cosh: forceComplex((z) => z.cosh()),
|
|
38
|
+
exp: forceComplex((z) => z.exp()),
|
|
39
|
+
floor: forceComplex((z) => z.floor(0)),
|
|
40
|
+
hypot: forceComplex((...zs) => zs.reduce((acc, z) => acc.add(z.pow(2)), (0, complex_js_1.Complex)(0)).sqrt()),
|
|
41
|
+
log_: forceComplex((z, b = (0, complex_js_1.Complex)(10)) => z.log().div(b.log())),
|
|
42
|
+
ln: forceComplex((z) => z.log()),
|
|
43
|
+
max: forceReal(Math.max),
|
|
44
|
+
min: forceReal(Math.min),
|
|
45
|
+
pow: forceComplex((z, p) => z.pow(p)),
|
|
46
|
+
random: () => (0, complex_js_1.Complex)(Math.random()),
|
|
47
|
+
round: forceComplex((z) => z.round(0)),
|
|
48
|
+
sign: forceComplex((z) => z.sign()),
|
|
49
|
+
sin: forceComplex((z) => z.sin()),
|
|
50
|
+
sinh: forceComplex((z) => z.sinh()),
|
|
51
|
+
sqrt: forceComplex((z) => z.sqrt()),
|
|
52
|
+
tan: forceComplex((z) => z.tan()),
|
|
53
|
+
tanh: forceComplex((z) => z.tanh())
|
|
54
|
+
},
|
|
55
|
+
constants: {
|
|
56
|
+
i: complex_js_1.Complex.I,
|
|
57
|
+
pi: complex_js_1.Complex.PI,
|
|
58
|
+
e: complex_js_1.Complex.E,
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Utility function to wrap a complex function, converting all its arguments to a Complex value.
|
|
63
|
+
*
|
|
64
|
+
* @param f Complex function
|
|
65
|
+
* @returns `f` with all its parameters converted to Complex
|
|
66
|
+
*/
|
|
67
|
+
function forceComplex(f) {
|
|
68
|
+
return (...args) => (0, complex_js_1.Complex)(f(...args.map(z => (0, complex_js_1.Complex)(z))));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Utility function to wrap a real function, forcing all its arguments to be real numbers.
|
|
72
|
+
*
|
|
73
|
+
* @param f Real function
|
|
74
|
+
* @returns `f`, but will throw an error on any complex arguments
|
|
75
|
+
*/
|
|
76
|
+
function forceReal(f) {
|
|
77
|
+
return (...args) => {
|
|
78
|
+
let realArgs = args.map(z => {
|
|
79
|
+
z = (0, complex_js_1.Complex)(z);
|
|
80
|
+
if (z.im != 0) {
|
|
81
|
+
throw Error("complex " + f.name + "is unsupported");
|
|
82
|
+
}
|
|
83
|
+
return z.re;
|
|
84
|
+
});
|
|
85
|
+
return (0, complex_js_1.Complex)(f(...realArgs));
|
|
86
|
+
};
|
|
87
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "verbena-complex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "verbena + complex numbers",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
|
-
"build": "tsc"
|
|
10
|
-
},
|
|
11
7
|
"files": [
|
|
12
8
|
"lib",
|
|
13
9
|
"README.md"
|
|
@@ -28,9 +24,12 @@
|
|
|
28
24
|
"mathjs",
|
|
29
25
|
"math.js"
|
|
30
26
|
],
|
|
31
|
-
"packageManager": "pnpm@9.14.2+sha512.6e2baf77d06b9362294152c851c4f278ede37ab1eba3a55fda317a4a17b209f4dbb973fb250a77abc463a341fcb1f17f17cfa24091c4eb319cda0d9b84278387",
|
|
32
27
|
"dependencies": {
|
|
33
28
|
"complex.js": "^2.4.2",
|
|
34
29
|
"verbena": "^0.4.0"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
33
|
+
"build": "tsc"
|
|
35
34
|
}
|
|
36
35
|
}
|
package/readme.md
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
# verbena-complex
|
|
2
|
-
|
|
3
|
-
This package acts as a complex number extension to the [verbena](https://github.com/p2js/verbena) math function transcompiler to JS.
|
|
4
|
-
|
|
5
|
-
It uses verbena's standard lexer, parser and compiler, all completely unmodified. The magic happens with the library: All operations are redefined to convert all numbers to complex.js `Complex` numbers, and `i` is treated as a simple constant.
|
|
6
|
-
|
|
7
|
-
Some additional logic is implemented after lexing and parsing to allow for additional robustness and ergonomics:
|
|
8
|
-
- any identifier `i` will be converted to the constant `i` to allow implicit multiplications of variables by i, such as `ix`.
|
|
9
|
-
- due to the lack of logical operator overloading in verbena, as well as the lack of a natural order on the complex numbers, function clauses are unimplemented and will
|
|
10
|
-
|
|
11
|
-
## Usage
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
npm install verbena-complex
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
```js
|
|
18
|
-
import { ComplexFunction } from 'verbena-complex';
|
|
19
|
-
|
|
20
|
-
const f = ComplexFunction("f(x) = re(x * (3+2i))");
|
|
21
|
-
|
|
22
|
-
console.log(f(2)); // { re: 6, im: 0 }
|
|
1
|
+
# verbena-complex
|
|
2
|
+
|
|
3
|
+
This package acts as a complex number extension to the [verbena](https://github.com/p2js/verbena) math function transcompiler to JS.
|
|
4
|
+
|
|
5
|
+
It uses verbena's standard lexer, parser and compiler, all completely unmodified. The magic happens with the library: All operations are redefined to convert all numbers to complex.js `Complex` numbers, and `i` is treated as a simple constant.
|
|
6
|
+
|
|
7
|
+
Some additional logic is implemented after lexing and parsing to allow for additional robustness and ergonomics:
|
|
8
|
+
- any identifier `i` will be converted to the constant `i` to allow implicit multiplications of variables by i, such as `ix`.
|
|
9
|
+
- due to the lack of logical operator overloading in verbena, as well as the lack of a natural order on the complex numbers, function clauses are unimplemented and adding them to a function definition will cause an error.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
npm install verbena-complex
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import { ComplexFunction } from 'verbena-complex';
|
|
19
|
+
|
|
20
|
+
const f = ComplexFunction("f(x) = re(x * (3+2i))");
|
|
21
|
+
|
|
22
|
+
console.log(f(2)); // { re: 6, im: 0 }
|
|
23
23
|
```
|