@trebco/treb 30.11.2 → 30.15.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/dist/treb.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /*! API v30.11. Copyright 2018-2024 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
1
+ /*! API v30.15. Copyright 2018-2024 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
2
2
 
3
3
  /**
4
4
  * add our tag to the map
@@ -515,6 +515,12 @@ export declare class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
515
515
  */
516
516
  HideSheet(index?: number | string, hide?: boolean): void;
517
517
 
518
+ /** list sheets in the model */
519
+ ListSheets(): {
520
+ name: string;
521
+ hidden?: boolean;
522
+ }[];
523
+
518
524
  /**
519
525
  * Show or hide sheet. This method is deprecated because it's ambiguous.
520
526
  * To set a sheet's visibility, use `HideSheet`. To activate a sheet, use
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trebco/treb",
3
- "version": "30.11.2",
3
+ "version": "30.15.0",
4
4
  "license": "LGPL-3.0-or-later",
5
5
  "homepage": "https://treb.app",
6
6
  "repository": {
@@ -99,6 +99,24 @@ export const RectangularToPolar = (value: Complex): { r: number, theta: number }
99
99
  return { r, theta };
100
100
  };
101
101
 
102
+ export const TanH = (z: Complex): Complex => {
103
+
104
+ // tanh(a+bi) = (sinh a cos b + i cosh a sin b) / (cosh a cos b + i sinh a sin b)
105
+
106
+ const num: Complex = {
107
+ real: Math.sinh(z.real) * Math.cos(z.imaginary),
108
+ imaginary: Math.cosh(z.real) * Math.sin(z.imaginary),
109
+ };
110
+
111
+ const denom: Complex = {
112
+ real: Math.cosh(z.real) * Math.cos(z.imaginary),
113
+ imaginary: Math.sinh(z.real) * Math.sin(z.imaginary),
114
+ };
115
+
116
+ return Divide(num, denom);
117
+
118
+ };
119
+
102
120
  export const Tan = (z: Complex) => {
103
121
 
104
122
  // tan(a+bi) = (tan(a) + i tanh(b)) / (1 - i tan(a) tanh(b))
@@ -113,6 +131,17 @@ export const Tan = (z: Complex) => {
113
131
 
114
132
  };
115
133
 
134
+ export const CosH = (z: Complex): Complex => {
135
+
136
+ // cosh(a+bi) = cosh a cos b + i sinh a sin b
137
+
138
+ return {
139
+ real: Math.cosh(z.real) * Math.cos(z.imaginary),
140
+ imaginary: Math.sinh(z.real) * Math.sin(z.imaginary),
141
+ };
142
+
143
+ };
144
+
116
145
  export const Cos = (z: Complex) => {
117
146
 
118
147
  // sin(a+bi) = cos(a) cosh(b) + i sin(a) sinh(b)
@@ -124,6 +153,16 @@ export const Cos = (z: Complex) => {
124
153
 
125
154
  };
126
155
 
156
+ export const SinH = (z: Complex): Complex => {
157
+
158
+ // sinh(a+bi) = sinh a cos b + i cosh a sin b
159
+
160
+ return {
161
+ real: Math.sinh(z.real) * Math.cos(z.imaginary),
162
+ imaginary: Math.cosh(z.real) * Math.sin(z.imaginary),
163
+ };
164
+
165
+ };
127
166
 
128
167
  export const Sin = (z: Complex) => {
129
168
 
@@ -62,56 +62,6 @@ import { ConstructDate } from './date-utils';
62
62
 
63
63
  // OK, just one.
64
64
 
65
- /** error function (for gaussian distribution) */
66
- const erf = (x: number): number => {
67
-
68
- const a1 = 0.254829592;
69
- const a2 = -0.284496736;
70
- const a3 = 1.421413741;
71
- const a4 = -1.453152027;
72
- const a5 = 1.061405429;
73
- const p = 0.3275911;
74
-
75
- x = Math.abs(x);
76
- const t = 1 / (1 + p * x);
77
- return 1 - ((((((a5 * t + a4) * t) + a3) * t + a2) * t) + a1) * t * Math.exp(-1 * x * x);
78
-
79
- };
80
-
81
- const sqrt2pi = Math.sqrt(2 * Math.PI);
82
-
83
- const norm_dist = (x: number, mean: number, stdev: number, cumulative: boolean) => {
84
-
85
- let value = 0;
86
-
87
- if (cumulative) {
88
- const sign = (x < mean) ? -1 : 1;
89
- value = 0.5 * (1.0 + sign * erf((Math.abs(x - mean)) / (stdev * Math.sqrt(2))));
90
- }
91
- else {
92
- value = Math.exp(-1/2 * Math.pow((x - mean) / stdev, 2)) / (stdev * sqrt2pi);
93
- }
94
-
95
- return value;
96
-
97
- }
98
-
99
- /** imprecise but reasonably fast normsinv function */
100
- const inverse_normal = (q: number): number => {
101
-
102
- if (q === 0.50) {
103
- return 0;
104
- }
105
-
106
- const p = (q < 1.0 && q > 0.5) ? (1 - q) : q;
107
- const t = Math.sqrt(Math.log(1.0 / Math.pow(p, 2.0)));
108
- const x = t - (2.515517 + 0.802853 * t + 0.010328 * Math.pow(t, 2.0)) /
109
- (1.0 + 1.432788 * t + 0.189269 * Math.pow(t, 2.0) + 0.001308 * Math.pow(t, 3.0));
110
-
111
- return (q > 0.5 ? x : -x);
112
-
113
- };
114
-
115
65
 
116
66
  const edate_calc = (start: number, months: number) => {
117
67
 
@@ -867,6 +817,9 @@ export const BaseFunctionLibrary: FunctionMap = {
867
817
  value = !!arg.value;
868
818
  break;
869
819
 
820
+ case ValueType.error:
821
+ return arg;
822
+
870
823
  }
871
824
  }
872
825
 
@@ -2172,94 +2125,6 @@ export const BaseFunctionLibrary: FunctionMap = {
2172
2125
  },
2173
2126
  },
2174
2127
 
2175
- Erf: {
2176
- fn: (a: number): UnionValue => {
2177
- return { type: ValueType.number, value: erf(a) };
2178
- },
2179
- },
2180
-
2181
- 'NormsInv': {
2182
-
2183
- description: 'Inverse of the normal cumulative distribution',
2184
- arguments: [
2185
- {name: 'probability'},
2186
- ],
2187
-
2188
- fn: (q: number): UnionValue => {
2189
- return {
2190
- type: ValueType.number,
2191
- value: inverse_normal(q),
2192
- }
2193
- }
2194
- },
2195
-
2196
- 'Norm.Inv': {
2197
- description: 'Inverse of the normal cumulative distribution',
2198
- arguments: [
2199
- {name: 'probability'},
2200
- {name: 'mean', default: 0},
2201
- {name: 'standard deviation', default: 1},
2202
- ],
2203
- xlfn: true,
2204
- fn: (q: number, mean = 0, stdev = 1): UnionValue => {
2205
- return {
2206
- type: ValueType.number,
2207
- value: inverse_normal(q) * stdev + mean,
2208
- }
2209
- }
2210
- },
2211
-
2212
- 'Norm.S.Inv': {
2213
- description: 'Inverse of the normal cumulative distribution',
2214
- arguments: [
2215
- {name: 'probability'},
2216
- {name: 'mean', default: 0},
2217
- {name: 'standard deviation', default: 1},
2218
- ],
2219
- xlfn: true,
2220
- fn: (q: number, mean = 0, stdev = 1): UnionValue => {
2221
- return {
2222
- type: ValueType.number,
2223
- value: inverse_normal(q) * stdev + mean,
2224
- }
2225
- }
2226
- },
2227
-
2228
- 'Norm.Dist': {
2229
-
2230
- description: 'Cumulative normal distribution',
2231
- arguments: [
2232
- {name: 'value'},
2233
- {name: 'mean', default: 0},
2234
- {name: 'standard deviation', default: 1},
2235
- {name: 'cumulative', default: true},
2236
- ],
2237
-
2238
- // this does need xlfn but it also requires four parameters
2239
- // (we have three and they are not required).
2240
-
2241
- xlfn: true,
2242
-
2243
- fn: (x: number, mean = 0, stdev = 1, cumulative = true): UnionValue => {
2244
- return { type: ValueType.number, value: norm_dist(x, mean, stdev, cumulative) };
2245
- },
2246
- },
2247
-
2248
- 'Norm.S.Dist': {
2249
-
2250
- description: 'Cumulative normal distribution',
2251
- arguments: [
2252
- {name: 'value'},
2253
- {name: 'cumulative', default: true},
2254
- ],
2255
-
2256
- xlfn: true,
2257
-
2258
- fn: (x: number, cumulative = true): UnionValue => {
2259
- return { type: ValueType.number, value: norm_dist(x, 0, 1, cumulative) };
2260
- },
2261
- },
2262
-
2263
2128
  Sqrt: {
2264
2129
  description: 'Returns the square root of the argument',
2265
2130
  arguments: [
@@ -2558,6 +2423,24 @@ export const BaseFunctionLibrary: FunctionMap = {
2558
2423
  },
2559
2424
  },
2560
2425
 
2426
+ SinH: {
2427
+ arguments: [
2428
+ { name: 'number', boxed: true, unroll: true },
2429
+ ],
2430
+ fn: (a: UnionValue) => {
2431
+
2432
+ if (a.type === ValueType.number) {
2433
+ return { type: ValueType.number, value: Math.sinh(a.value) };
2434
+ }
2435
+ if (a.type === ValueType.complex) {
2436
+ return { type: ValueType.complex, value: ComplexMath.SinH(a.value) };
2437
+ }
2438
+
2439
+ return ArgumentError();
2440
+
2441
+ },
2442
+ },
2443
+
2561
2444
  Sin: {
2562
2445
  arguments: [
2563
2446
  { name: 'angle in radians', boxed: true, unroll: true, }
@@ -2576,6 +2459,24 @@ export const BaseFunctionLibrary: FunctionMap = {
2576
2459
  },
2577
2460
  },
2578
2461
 
2462
+ CosH: {
2463
+ arguments: [
2464
+ { name: 'number', boxed: true, unroll: true },
2465
+ ],
2466
+ fn: (a: UnionValue) => {
2467
+
2468
+ if (a.type === ValueType.number) {
2469
+ return { type: ValueType.number, value: Math.cosh(a.value) };
2470
+ }
2471
+ if (a.type === ValueType.complex) {
2472
+ return { type: ValueType.complex, value: ComplexMath.CosH(a.value) };
2473
+ }
2474
+
2475
+ return ArgumentError();
2476
+
2477
+ },
2478
+ },
2479
+
2579
2480
  Cos: {
2580
2481
  arguments: [
2581
2482
  { name: 'angle in radians', boxed: true, unroll: true, }
@@ -2593,7 +2494,25 @@ export const BaseFunctionLibrary: FunctionMap = {
2593
2494
 
2594
2495
  },
2595
2496
  },
2596
-
2497
+
2498
+ TanH: {
2499
+ arguments: [
2500
+ { name: 'number', boxed: true, unroll: true, }
2501
+ ],
2502
+ fn: (a: UnionValue) => {
2503
+
2504
+ if (a.type === ValueType.number) {
2505
+ return { type: ValueType.number, value: Math.tanh(a.value) };
2506
+ }
2507
+ if (a.type === ValueType.complex) {
2508
+ return { type: ValueType.complex, value: ComplexMath.TanH(a.value) };
2509
+ }
2510
+
2511
+ return ArgumentError();
2512
+
2513
+ },
2514
+ },
2515
+
2597
2516
  Tan: {
2598
2517
  arguments: [
2599
2518
  { name: 'angle in radians', boxed: true, unroll: true, }
@@ -0,0 +1,244 @@
1
+ /*
2
+ * This file is part of TREB.
3
+ *
4
+ * TREB is free software: you can redistribute it and/or modify it under the
5
+ * terms of the GNU General Public License as published by the Free Software
6
+ * Foundation, either version 3 of the License, or (at your option) any
7
+ * later version.
8
+ *
9
+ * TREB is distributed in the hope that it will be useful, but WITHOUT ANY
10
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
+ * details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License along
15
+ * with TREB. If not, see <https://www.gnu.org/licenses/>.
16
+ *
17
+ * Copyright 2022-2024 trebco, llc.
18
+ * info@treb.app
19
+ *
20
+ */
21
+
22
+ const EPSILON = 2.2204460492503131e-16;
23
+
24
+ /**
25
+ * natural log of (1+x)
26
+ */
27
+ const Log1p = (x: number) => {
28
+ const y = 1 + x;
29
+ return Math.log(y) - ((y - 1) - x) / y;
30
+ }
31
+
32
+ /**
33
+ * continued fraction expansion
34
+ */
35
+ const BetaContFrac = (a: number, b: number, x: number, epsabs: number) => {
36
+
37
+ const cutoff = 2.0 * Number.MIN_VALUE;
38
+
39
+ let cf = 0;
40
+
41
+ let numerator = 1.0;
42
+ let denominator = 1.0 - (a + b) * x / (a + 1.0);
43
+
44
+ if (Math.abs(denominator) < cutoff) {
45
+ denominator = Number.NaN;
46
+ }
47
+
48
+ denominator = 1.0 / denominator;
49
+ cf = denominator;
50
+
51
+ for (let k = 1; k <= 512; k++) {
52
+
53
+ let coeff = k * (b - k) * x / (((a - 1.0) + 2 * k) * (a + 2 * k));
54
+ let delta_frac = 0;
55
+
56
+ denominator = 1.0 + coeff * denominator;
57
+ numerator = 1.0 + coeff / numerator;
58
+
59
+ if (Math.abs(denominator) < cutoff) {
60
+ denominator = Number.NaN;
61
+ }
62
+ if (Math.abs(numerator) < cutoff) {
63
+ numerator = Number.NaN;
64
+ }
65
+
66
+ denominator = 1.0 / denominator;
67
+
68
+ delta_frac = denominator * numerator;
69
+ cf *= delta_frac;
70
+
71
+ coeff = -(a + k) * (a + b + k) * x / ((a + 2 * k) * (a + 2 * k + 1.0));
72
+
73
+ denominator = 1.0 + coeff * denominator;
74
+ numerator = 1.0 + coeff / numerator;
75
+
76
+ if (Math.abs(denominator) < cutoff) {
77
+ denominator = Number.NaN;
78
+ }
79
+ if (Math.abs(numerator) < cutoff) {
80
+ numerator = Number.NaN;
81
+ }
82
+
83
+ denominator = 1.0 / denominator;
84
+
85
+ delta_frac = denominator * numerator;
86
+ cf *= delta_frac;
87
+
88
+ if ((Math.abs(delta_frac - 1.0) < 2.0 * EPSILON) || (cf * Math.abs(delta_frac - 1.0) < epsabs)) {
89
+ return cf;
90
+ };
91
+
92
+ }
93
+
94
+ return Number.NaN;
95
+
96
+ };
97
+
98
+ /**
99
+ * inverse beta function for beta (a, b)
100
+ */
101
+ export const InverseBeta = (p: number, a: number, b: number): number => {
102
+
103
+ if (a < 0.0 || b < 0.0) {
104
+ return Number.NaN;
105
+ }
106
+
107
+ if (p <= 0) {
108
+ return 0.0;
109
+ }
110
+
111
+ if (p >= 1) {
112
+ return 1.0;
113
+ }
114
+
115
+ if (p > 0.5) {
116
+ return 1 - InverseBeta(1 - p, b, a);
117
+ }
118
+
119
+ const mean = a / (a + b);
120
+
121
+ let x = 0;
122
+
123
+ if (p < 0.1) {
124
+ const lx = (Math.log(a) + LnGamma(a) + LnGamma(b) - LnGamma(a + b) + Math.log(p)) / a;
125
+ if (lx <= 0) {
126
+ x = Math.exp(lx);
127
+ x *= Math.pow(1 - x, -(b - 1) / a);
128
+ }
129
+ else {
130
+ x = mean;
131
+ }
132
+
133
+ if (x > mean) {
134
+ x = mean;
135
+ }
136
+ }
137
+ else {
138
+ x = mean;
139
+ }
140
+
141
+ for(let n = 0; n < 64; n++) {
142
+
143
+ const dP = p - BetaCDF(x, a, b);
144
+ const phi = BetaPDF(x, a, b);
145
+
146
+ if (dP === 0) {
147
+ return x;
148
+ }
149
+
150
+ const lambda = dP / Math.max(2 * Math.abs(dP / x), phi);
151
+
152
+ const step0 = lambda;
153
+ const step1 = -((a - 1) / x - (b - 1) / (1 - x)) * lambda * lambda / 2;
154
+ let step = step0;
155
+
156
+ if (Math.abs(step1) < Math.abs(step0)) {
157
+ step += step1;
158
+ }
159
+ else {
160
+ step *= 2 * Math.abs(step0 / step1);
161
+ }
162
+
163
+ if (x + step > 0 && x + step < 1) {
164
+ x += step;
165
+ }
166
+ else {
167
+ x = Math.sqrt(x) * Math.sqrt(mean);
168
+ }
169
+
170
+ if (Math.abs(step0) <= 1e-10 * x) {
171
+ return x;
172
+ }
173
+
174
+ }
175
+
176
+ return x;
177
+
178
+ };
179
+
180
+ /**
181
+ * this is a faster approximation for real numbers
182
+ */
183
+ export const LnGamma = (z: number) => {
184
+
185
+ let x = z - 1.0;
186
+ let y = x + 5.5;
187
+ y -= (x + 0.5) * Math.log(y);
188
+ let a = 1.0;
189
+
190
+ const coefficients = [
191
+ 76.18009173,
192
+ -86.50532033,
193
+ 24.01409822,
194
+ -1.231739516,
195
+ 0.120858003e-2,
196
+ -0.536382e-5,
197
+ ];
198
+
199
+ for (const coeff of coefficients) {
200
+ a += coeff / (++x);
201
+ }
202
+
203
+ return (-y + Math.log(2.50662827465 * a));
204
+
205
+ };
206
+
207
+ /** PDF of the beta distribution */
208
+ export const BetaPDF = (x: number, a: number, b: number) => {
209
+ if (x < 0 || x > 1) {
210
+ return 0;
211
+ }
212
+ return Math.exp(LnGamma(a + b) - LnGamma(a) - LnGamma(b)) *
213
+ Math.pow(x, a - 1) * Math.pow(1 - x, b - 1);
214
+ };
215
+
216
+ /** CDF of the beta distribution */
217
+ export const BetaCDF = (x: number, a: number, b: number) => {
218
+
219
+ if (x <= 0.0) {
220
+ return 0.0;
221
+ }
222
+
223
+ if (x >= 1.0) {
224
+ return 1.0;
225
+ }
226
+
227
+ const ln_beta = (LnGamma(a) + LnGamma(b) - LnGamma(a + b));
228
+ const ln_pre = -ln_beta + a * Math.log(x) + b * Log1p(-x);
229
+ const prefactor = Math.exp(ln_pre);
230
+
231
+ if (x < (a + 1.0) / (a + b + 2.0)) {
232
+ const cf = BetaContFrac(a, b, x, 0);
233
+ return (prefactor * cf / a);
234
+ }
235
+ else {
236
+ const epsabs = Math.abs(b / prefactor) * EPSILON;
237
+ const cf = BetaContFrac(b, a, 1.0 - x, epsabs);
238
+ const term = prefactor * cf / b;
239
+ return (1 - term);
240
+
241
+ }
242
+
243
+ };
244
+