@trebco/treb 23.6.5 → 25.0.0-rc2

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.
Files changed (217) hide show
  1. package/.eslintignore +8 -0
  2. package/.eslintrc.js +164 -0
  3. package/README-shadow-DOM.md +88 -0
  4. package/README.md +37 -130
  5. package/api-config.json +29 -0
  6. package/api-generator/api-generator-types.ts +82 -0
  7. package/api-generator/api-generator.ts +1172 -0
  8. package/api-generator/package.json +3 -0
  9. package/build/treb-spreadsheet.mjs +14 -0
  10. package/{treb.d.ts → build/treb.d.ts} +323 -271
  11. package/esbuild-custom-element.mjs +336 -0
  12. package/esbuild.js +305 -0
  13. package/package.json +49 -14
  14. package/treb-base-types/package.json +5 -0
  15. package/treb-base-types/src/api_types.ts +36 -0
  16. package/treb-base-types/src/area.ts +583 -0
  17. package/treb-base-types/src/basic_types.ts +45 -0
  18. package/treb-base-types/src/cell.ts +612 -0
  19. package/treb-base-types/src/cells.ts +1066 -0
  20. package/treb-base-types/src/color.ts +124 -0
  21. package/treb-base-types/src/import.ts +71 -0
  22. package/treb-base-types/src/index-standalone.ts +29 -0
  23. package/treb-base-types/src/index.ts +42 -0
  24. package/treb-base-types/src/layout.ts +47 -0
  25. package/treb-base-types/src/localization.ts +187 -0
  26. package/treb-base-types/src/rectangle.ts +145 -0
  27. package/treb-base-types/src/render_text.ts +72 -0
  28. package/treb-base-types/src/style.ts +545 -0
  29. package/treb-base-types/src/table.ts +109 -0
  30. package/treb-base-types/src/text_part.ts +54 -0
  31. package/treb-base-types/src/theme.ts +608 -0
  32. package/treb-base-types/src/union.ts +152 -0
  33. package/treb-base-types/src/value-type.ts +164 -0
  34. package/treb-base-types/style/resizable.css +59 -0
  35. package/treb-calculator/modern.tsconfig.json +11 -0
  36. package/treb-calculator/package.json +5 -0
  37. package/treb-calculator/src/calculator.ts +2546 -0
  38. package/treb-calculator/src/complex-math.ts +558 -0
  39. package/treb-calculator/src/dag/array-vertex.ts +198 -0
  40. package/treb-calculator/src/dag/graph.ts +951 -0
  41. package/treb-calculator/src/dag/leaf_vertex.ts +118 -0
  42. package/treb-calculator/src/dag/spreadsheet_vertex.ts +327 -0
  43. package/treb-calculator/src/dag/spreadsheet_vertex_base.ts +44 -0
  44. package/treb-calculator/src/dag/vertex.ts +352 -0
  45. package/treb-calculator/src/descriptors.ts +162 -0
  46. package/treb-calculator/src/expression-calculator.ts +1069 -0
  47. package/treb-calculator/src/function-error.ts +103 -0
  48. package/treb-calculator/src/function-library.ts +103 -0
  49. package/treb-calculator/src/functions/base-functions.ts +1214 -0
  50. package/treb-calculator/src/functions/checkbox.ts +164 -0
  51. package/treb-calculator/src/functions/complex-functions.ts +253 -0
  52. package/treb-calculator/src/functions/finance-functions.ts +399 -0
  53. package/treb-calculator/src/functions/information-functions.ts +102 -0
  54. package/treb-calculator/src/functions/matrix-functions.ts +182 -0
  55. package/treb-calculator/src/functions/sparkline.ts +335 -0
  56. package/treb-calculator/src/functions/statistics-functions.ts +350 -0
  57. package/treb-calculator/src/functions/text-functions.ts +298 -0
  58. package/treb-calculator/src/index.ts +27 -0
  59. package/treb-calculator/src/notifier-types.ts +59 -0
  60. package/treb-calculator/src/primitives.ts +428 -0
  61. package/treb-calculator/src/utilities.ts +305 -0
  62. package/treb-charts/package.json +5 -0
  63. package/treb-charts/src/chart-functions.ts +156 -0
  64. package/treb-charts/src/chart-types.ts +230 -0
  65. package/treb-charts/src/chart.ts +1288 -0
  66. package/treb-charts/src/index.ts +24 -0
  67. package/treb-charts/src/main.ts +37 -0
  68. package/treb-charts/src/rectangle.ts +52 -0
  69. package/treb-charts/src/renderer.ts +1841 -0
  70. package/treb-charts/src/util.ts +122 -0
  71. package/treb-charts/style/charts.scss +221 -0
  72. package/treb-charts/style/old-charts.scss +250 -0
  73. package/treb-embed/markup/layout.html +137 -0
  74. package/treb-embed/markup/toolbar.html +175 -0
  75. package/treb-embed/modern.tsconfig.json +25 -0
  76. package/treb-embed/src/custom-element/content-types.d.ts +18 -0
  77. package/treb-embed/src/custom-element/global.d.ts +11 -0
  78. package/treb-embed/src/custom-element/spreadsheet-constructor.ts +1228 -0
  79. package/treb-embed/src/custom-element/treb-global.ts +44 -0
  80. package/treb-embed/src/custom-element/treb-spreadsheet-element.ts +52 -0
  81. package/treb-embed/src/embedded-spreadsheet.ts +5358 -0
  82. package/treb-embed/src/index.ts +16 -0
  83. package/treb-embed/src/language-model.ts +41 -0
  84. package/treb-embed/src/options.ts +298 -0
  85. package/treb-embed/src/progress-dialog.ts +228 -0
  86. package/treb-embed/src/selection-state.ts +16 -0
  87. package/treb-embed/src/spinner.ts +42 -0
  88. package/treb-embed/src/toolbar-message.ts +96 -0
  89. package/treb-embed/src/types.ts +167 -0
  90. package/treb-embed/style/autocomplete.scss +103 -0
  91. package/treb-embed/style/dark-theme.scss +114 -0
  92. package/treb-embed/style/defaults.scss +36 -0
  93. package/treb-embed/style/dialog.scss +181 -0
  94. package/treb-embed/style/dropdown-select.scss +101 -0
  95. package/treb-embed/style/formula-bar.scss +193 -0
  96. package/treb-embed/style/grid.scss +374 -0
  97. package/treb-embed/style/layout.scss +424 -0
  98. package/treb-embed/style/mouse-mask.scss +67 -0
  99. package/treb-embed/style/note.scss +92 -0
  100. package/treb-embed/style/overlay-editor.scss +102 -0
  101. package/treb-embed/style/spinner.scss +92 -0
  102. package/treb-embed/style/tab-bar.scss +228 -0
  103. package/treb-embed/style/table.scss +80 -0
  104. package/treb-embed/style/theme-defaults.scss +444 -0
  105. package/treb-embed/style/toolbar.scss +416 -0
  106. package/treb-embed/style/tooltip.scss +68 -0
  107. package/treb-embed/style/treb-icons.scss +130 -0
  108. package/treb-embed/style/treb-spreadsheet-element.scss +20 -0
  109. package/treb-embed/style/z-index.scss +43 -0
  110. package/treb-export/docs/charts.md +68 -0
  111. package/treb-export/modern.tsconfig.json +19 -0
  112. package/treb-export/package.json +4 -0
  113. package/treb-export/src/address-type.ts +77 -0
  114. package/treb-export/src/base-template.ts +22 -0
  115. package/treb-export/src/column-width.ts +85 -0
  116. package/treb-export/src/drawing2/chart-template-components2.ts +389 -0
  117. package/treb-export/src/drawing2/chart2.ts +282 -0
  118. package/treb-export/src/drawing2/column-chart-template2.ts +521 -0
  119. package/treb-export/src/drawing2/donut-chart-template2.ts +296 -0
  120. package/treb-export/src/drawing2/drawing2.ts +355 -0
  121. package/treb-export/src/drawing2/embedded-image.ts +71 -0
  122. package/treb-export/src/drawing2/scatter-chart-template2.ts +555 -0
  123. package/treb-export/src/export-worker/export-worker.ts +99 -0
  124. package/treb-export/src/export-worker/index-modern.ts +22 -0
  125. package/treb-export/src/export2.ts +2204 -0
  126. package/treb-export/src/import2.ts +882 -0
  127. package/treb-export/src/relationship.ts +36 -0
  128. package/treb-export/src/shared-strings2.ts +128 -0
  129. package/treb-export/src/template-2.ts +22 -0
  130. package/treb-export/src/unescape_xml.ts +47 -0
  131. package/treb-export/src/workbook-sheet2.ts +182 -0
  132. package/treb-export/src/workbook-style2.ts +1285 -0
  133. package/treb-export/src/workbook-theme2.ts +88 -0
  134. package/treb-export/src/workbook2.ts +491 -0
  135. package/treb-export/src/xml-utils.ts +201 -0
  136. package/treb-export/template/base/[Content_Types].xml +2 -0
  137. package/treb-export/template/base/_rels/.rels +2 -0
  138. package/treb-export/template/base/docProps/app.xml +2 -0
  139. package/treb-export/template/base/docProps/core.xml +12 -0
  140. package/treb-export/template/base/xl/_rels/workbook.xml.rels +2 -0
  141. package/treb-export/template/base/xl/sharedStrings.xml +2 -0
  142. package/treb-export/template/base/xl/styles.xml +2 -0
  143. package/treb-export/template/base/xl/theme/theme1.xml +2 -0
  144. package/treb-export/template/base/xl/workbook.xml +2 -0
  145. package/treb-export/template/base/xl/worksheets/sheet1.xml +2 -0
  146. package/treb-export/template/base.xlsx +0 -0
  147. package/treb-format/package.json +8 -0
  148. package/treb-format/src/format.test.ts +213 -0
  149. package/treb-format/src/format.ts +942 -0
  150. package/treb-format/src/format_cache.ts +199 -0
  151. package/treb-format/src/format_parser.ts +723 -0
  152. package/treb-format/src/index.ts +25 -0
  153. package/treb-format/src/number_format_section.ts +100 -0
  154. package/treb-format/src/value_parser.ts +337 -0
  155. package/treb-grid/package.json +5 -0
  156. package/treb-grid/src/editors/autocomplete.ts +394 -0
  157. package/treb-grid/src/editors/autocomplete_matcher.ts +260 -0
  158. package/treb-grid/src/editors/formula_bar.ts +473 -0
  159. package/treb-grid/src/editors/formula_editor_base.ts +910 -0
  160. package/treb-grid/src/editors/overlay_editor.ts +511 -0
  161. package/treb-grid/src/index.ts +37 -0
  162. package/treb-grid/src/layout/base_layout.ts +2618 -0
  163. package/treb-grid/src/layout/grid_layout.ts +299 -0
  164. package/treb-grid/src/layout/rectangle_cache.ts +86 -0
  165. package/treb-grid/src/render/selection-renderer.ts +414 -0
  166. package/treb-grid/src/render/svg_header_overlay.ts +93 -0
  167. package/treb-grid/src/render/svg_selection_block.ts +187 -0
  168. package/treb-grid/src/render/tile_renderer.ts +2122 -0
  169. package/treb-grid/src/types/annotation.ts +216 -0
  170. package/treb-grid/src/types/border_constants.ts +34 -0
  171. package/treb-grid/src/types/clipboard_data.ts +31 -0
  172. package/treb-grid/src/types/data_model.ts +334 -0
  173. package/treb-grid/src/types/drag_mask.ts +81 -0
  174. package/treb-grid/src/types/grid.ts +7743 -0
  175. package/treb-grid/src/types/grid_base.ts +3644 -0
  176. package/treb-grid/src/types/grid_command.ts +470 -0
  177. package/treb-grid/src/types/grid_events.ts +124 -0
  178. package/treb-grid/src/types/grid_options.ts +97 -0
  179. package/treb-grid/src/types/grid_selection.ts +60 -0
  180. package/treb-grid/src/types/named_range.ts +369 -0
  181. package/treb-grid/src/types/scale-control.ts +202 -0
  182. package/treb-grid/src/types/serialize_options.ts +72 -0
  183. package/treb-grid/src/types/set_range_options.ts +52 -0
  184. package/treb-grid/src/types/sheet.ts +3099 -0
  185. package/treb-grid/src/types/sheet_types.ts +95 -0
  186. package/treb-grid/src/types/tab_bar.ts +464 -0
  187. package/treb-grid/src/types/tile.ts +59 -0
  188. package/treb-grid/src/types/update_flags.ts +75 -0
  189. package/treb-grid/src/util/dom_utilities.ts +44 -0
  190. package/treb-grid/src/util/fontmetrics2.ts +179 -0
  191. package/treb-grid/src/util/ua.ts +104 -0
  192. package/treb-logo.svg +18 -0
  193. package/treb-parser/package.json +5 -0
  194. package/treb-parser/src/csv-parser.ts +122 -0
  195. package/treb-parser/src/index.ts +25 -0
  196. package/treb-parser/src/md-parser.ts +526 -0
  197. package/treb-parser/src/parser-types.ts +397 -0
  198. package/treb-parser/src/parser.test.ts +298 -0
  199. package/treb-parser/src/parser.ts +2673 -0
  200. package/treb-utils/package.json +5 -0
  201. package/treb-utils/src/dispatch.ts +57 -0
  202. package/treb-utils/src/event_source.ts +147 -0
  203. package/treb-utils/src/ievent_source.ts +33 -0
  204. package/treb-utils/src/index.ts +31 -0
  205. package/treb-utils/src/measurement.ts +174 -0
  206. package/treb-utils/src/resizable.ts +160 -0
  207. package/treb-utils/src/scale.ts +137 -0
  208. package/treb-utils/src/serialize_html.ts +124 -0
  209. package/treb-utils/src/template.ts +70 -0
  210. package/treb-utils/src/validate_uri.ts +61 -0
  211. package/tsconfig.json +10 -0
  212. package/tsproject.json +30 -0
  213. package/util/license-plugin-esbuild.js +86 -0
  214. package/util/list-css-vars.sh +46 -0
  215. package/README-esm.md +0 -37
  216. package/treb-bundle.css +0 -2
  217. package/treb-bundle.mjs +0 -15
@@ -0,0 +1,399 @@
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-2023 trebco, llc.
18
+ * info@treb.app
19
+ *
20
+ */
21
+
22
+ import type { FunctionMap } from '../descriptors';
23
+ import { CellValue, UnionValue, ValueType } from 'treb-base-types';
24
+ import { FlattenUnboxed } from '../utilities';
25
+
26
+ // use a single, static object for base functions
27
+
28
+ /**
29
+ * some random web resources, more or less helpful:
30
+ *
31
+ * http://www.ultimatecalculators.com/future_value_annuity_calculator.html
32
+ * https://financeformulas.net/Annuity-Due-Payment-from-Present-Value.html
33
+ * http://www.tvmcalcs.com/tvm/formulas/regular_annuity_formulas
34
+ */
35
+
36
+ /**
37
+ * this function is broken out because we use it in the rate function
38
+ * (to search). we could reasonably use any of them (we probably should
39
+ * use the one most likely to be zero -- FV maybe?)
40
+ *
41
+ * this is now used in a couple of functions, so it makes sense to leave
42
+ * it broken out irrespective of what we use for Rate.
43
+ *
44
+ */
45
+ const payment_function = (rate: number, periods: number, pv = 0, fv = 0, type = 0): number => {
46
+ if (type) {
47
+ return -(pv * (rate / (1 - Math.pow(1 + rate, -periods)))) / (1 + rate)
48
+ - (fv * (1 / ((1 + rate) * ((Math.pow(1 + rate, periods) -1)/rate))));
49
+ }
50
+ return -(pv * rate * Math.pow(1 + rate, periods) + fv * rate) / (Math.pow(1 + rate, periods) - 1);
51
+ }
52
+
53
+ /** broken out for use in ipmt, ppmt functions */
54
+ const fv_function = (rate: number, periods: number, payment: number, pv = 0, type = 0): number => {
55
+ if (type) {
56
+ return (1 + rate) * -payment / rate * (Math.pow(1 + rate, periods) - 1) - pv * Math.pow(1 + rate, periods);
57
+ }
58
+ return -payment / rate * (Math.pow(1 + rate, periods) - 1) - pv * Math.pow(1 + rate, periods);
59
+ };
60
+
61
+ /** ppmt is calculated as payment less interest payment */
62
+ const ipmt_function = (rate: number, period: number, periods: number, pv = 0, fv = 0, type = 0): number => {
63
+
64
+ // invalid
65
+ if (period < 1) { return NaN; }
66
+
67
+ // if payment is at the start of the period, there's no interest in payment 1
68
+ if (period === 1 && type) {
69
+ return 0;
70
+ }
71
+
72
+ const total_payment = payment_function(rate, periods, pv, fv, type);
73
+ const interest = fv_function(rate, period - 1, total_payment, pv, type) * rate;
74
+
75
+ // for payments at start of period, after period 1, we need to discount
76
+ return type ? interest / (1 + rate) : interest;
77
+
78
+ };
79
+
80
+ const ppmt_function = (rate: number, period: number, periods: number, pv = 0, fv = 0, type = 0): number => {
81
+ return payment_function(rate, periods, pv, fv, type) -
82
+ ipmt_function(rate, period, periods, pv, fv, type);
83
+ };
84
+
85
+ export const FinanceFunctionLibrary: FunctionMap = {
86
+
87
+ /**
88
+ * Excel's NPV function is somewhat broken because it assumes the first
89
+ * (usually negative) cashflow is in year 1, not year 0. so the thing to
90
+ * do is just use it on the future cashflows and add the initial outlay
91
+ * as a scalar value.
92
+ */
93
+ NPV: {
94
+ description: 'Returns the present value of a series of future cashflows',
95
+ arguments: [
96
+ { name: 'Rate' },
97
+ { name: 'Cashflow' },
98
+ ],
99
+ fn: (rate = 0, ...args: any[]): UnionValue => {
100
+
101
+ let result = 0;
102
+
103
+ const flat = FlattenUnboxed(args);
104
+ for (let i = 0; i < flat.length; i++) {
105
+ const arg = flat[i];
106
+ if (typeof arg === 'number') {
107
+ result += Math.pow(1 + rate, -(i + 1)) * arg;
108
+ }
109
+ }
110
+
111
+ return {
112
+ type: ValueType.number, value: result,
113
+ }
114
+ }
115
+ },
116
+
117
+ IRR: {
118
+ description: 'Calculates the internal rate of return of a series of cashflows',
119
+ arguments: [
120
+ { name: 'Cashflows' },
121
+ { name: 'Guess', default: .1 },
122
+ ],
123
+ fn: (args: CellValue[], guess = .1): UnionValue => {
124
+
125
+ const flat = FlattenUnboxed(args).map(value => typeof value === 'number' ? value : 0);
126
+
127
+ const step = .1; // initial step
128
+
129
+ const bounds = [
130
+ {found: false, value: 0},
131
+ {found: false, value: 0},
132
+ ];
133
+
134
+ // FIXME: parameterize max step count, resolution?
135
+
136
+ for (let i = 0; i < 50; i++) {
137
+
138
+ // calculate npv
139
+ let npv = 0;
140
+ for (let j = 0; j < flat.length; j++) { npv += Math.pow(1 + guess, -(j + 1)) * flat[j]; }
141
+
142
+ if (Math.abs(npv) <= 0.00125) { // resolution
143
+ // console.info(`** found in ${i + 1} steps`)
144
+ return {
145
+ type: ValueType.number,
146
+ value: guess,
147
+ }
148
+ }
149
+
150
+ // search space is unbounded, unfortunately. we can expand exponentially
151
+ // until we have bounds, at which point it's a standard bounded binary search
152
+
153
+ // ...or we can expand linearly, using a reasonable initial step size?
154
+
155
+ if (npv > 0) {
156
+ bounds[0].value = bounds[0].found ? Math.max(bounds[0].value, guess) : guess;
157
+ bounds[0].found = true;
158
+ if (!bounds[1].found) {
159
+ guess += step;
160
+ continue;
161
+ }
162
+ }
163
+ else {
164
+ bounds[1].value = bounds[1].found ? Math.min(bounds[1].value, guess) : guess;
165
+ bounds[1].found = true;
166
+ if (!bounds[0].found) {
167
+ guess -= step;
168
+ continue;
169
+ }
170
+ }
171
+
172
+ guess = bounds[0].value + (bounds[1].value - bounds[0].value) / 2;
173
+
174
+ }
175
+
176
+ return {
177
+ type: ValueType.error,
178
+ value: 'NUM',
179
+ }
180
+ },
181
+ },
182
+
183
+ CUMPRINC: {
184
+ description: 'Returns cumulative principal paid on a loan between two periods',
185
+ arguments: [
186
+ { name: 'Rate', },
187
+ { name: 'Periods', },
188
+ { name: 'Present Value' },
189
+ { name: 'Start Period' },
190
+ { name: 'End Period' },
191
+ { name: 'Type', default: 0 },
192
+ ],
193
+ fn: (rate: number, periods: number, pv: number, start: number, end: number, type = 0): UnionValue => {
194
+ let accum = 0;
195
+ for (let i = start; i <= end; i++ ) {
196
+ accum += ppmt_function(rate, i, periods, pv, 0, type);
197
+ }
198
+ return { type: ValueType.number, value: accum };
199
+ },
200
+
201
+ },
202
+
203
+ CUMIPMT: {
204
+ description: 'Returns cumulative interest paid on a loan between two periods',
205
+ arguments: [
206
+ { name: 'Rate', },
207
+ { name: 'Periods', },
208
+ { name: 'Present Value' },
209
+ { name: 'Start Period' },
210
+ { name: 'End Period' },
211
+ { name: 'Type', default: 0 },
212
+ ],
213
+ fn: (rate: number, periods: number, pv: number, start: number, end: number, type = 0): UnionValue => {
214
+ let accum = 0;
215
+ for (let i = start; i <= end; i++ ) {
216
+ accum += ipmt_function(rate, i, periods, pv, 0, type);
217
+ }
218
+ return { type: ValueType.number, value: accum };
219
+ },
220
+
221
+ },
222
+
223
+ IPMT: {
224
+ description: 'Returns the interest portion of a payment',
225
+ arguments: [
226
+ { name: 'Rate', },
227
+ { name: 'Period', },
228
+ { name: 'Periods', },
229
+ { name: 'Present Value', default: 0 },
230
+ { name: 'Future Value', default: 0 },
231
+ { name: 'Type', default: 0 },
232
+ ],
233
+ fn: (rate: number, period: number, periods: number, pv = 0, fv = 0, type = 0): UnionValue => {
234
+ return { type: ValueType.number, value: ipmt_function(rate, period, periods, pv, fv, type) };
235
+ }
236
+ },
237
+
238
+ PPMT: {
239
+ description: 'Returns the principal portion of a payment',
240
+ arguments: [
241
+ { name: 'Rate', },
242
+ { name: 'Period', },
243
+ { name: 'Periods', },
244
+ { name: 'Present Value', default: 0 },
245
+ { name: 'Future Value', default: 0 },
246
+ { name: 'Type', default: 0 },
247
+ ],
248
+ fn: (rate: number, period: number, periods: number, pv = 0, fv = 0, type = 0): UnionValue => {
249
+ return { type: ValueType.number, value: ppmt_function(rate, period, periods, pv, fv, type) };
250
+ }
251
+ },
252
+
253
+ Rate: {
254
+ description: 'Returns the interest rate of a loan',
255
+ arguments: [
256
+ { name: 'Periods', },
257
+ { name: 'Payment', },
258
+ { name: 'Present Value', default: 0 },
259
+ { name: 'Future Value', default: 0 },
260
+ { name: 'Type', default: 0 },
261
+ ],
262
+ fn: (periods: number, payment: number, pv = 0, fv = 0, type = 0): UnionValue => {
263
+
264
+ let rate = .25; // guess
265
+ const bounds = [-1, 1];
266
+
267
+ const steps = 32; // max iterations
268
+ const epsilon = 1e-6;
269
+
270
+ for (let i = 0; i < steps; i++) {
271
+
272
+ const a = payment_function(rate, periods, pv, fv, type);
273
+
274
+ if (Math.abs(a - payment) <= epsilon) {
275
+ return { type: ValueType.number, value: rate };
276
+ }
277
+
278
+ const b = payment_function(bounds[1], periods, pv, fv, type);
279
+
280
+
281
+ if ((payment >= a && payment <= b) || (payment >= b && payment <= a)) {
282
+ bounds[0] = rate;
283
+ }
284
+ else {
285
+ bounds[1] = rate;
286
+ }
287
+ rate = bounds[0] + (bounds[1] - bounds[0]) / 2;
288
+
289
+ /*
290
+ const test = payment_function(rate, periods, pv, fv, type);
291
+ console.info("R", rate, "TP", test, payment, "d", Math.abs(payment-test), bounds);
292
+
293
+ if (Math.abs(payment - test) < epsilon) {
294
+ return { type: ValueType.number, value: rate };
295
+ }
296
+
297
+ if ((test < payment && payment > 0) || (test > payment && payment < 0)) { // reduce rate
298
+ console.info("T<P");
299
+ const next_rate = (bounds[0] + rate) / 2;
300
+ bounds = [bounds[0], rate];
301
+ rate = next_rate;
302
+ }
303
+ else { // increase rate
304
+ console.info("T>=P");
305
+ const next_rate = (bounds[1] + rate) / 2;
306
+ bounds = [rate, bounds[1]];
307
+ rate = next_rate;
308
+ }
309
+ */
310
+
311
+ }
312
+
313
+ return { type: ValueType.number, value: rate };
314
+
315
+ },
316
+
317
+ },
318
+
319
+ FV: {
320
+ description: 'Returns the future value of an investment',
321
+ arguments: [
322
+ { name: 'Rate', },
323
+ { name: 'Periods', },
324
+ { name: 'Payment', },
325
+ { name: 'Present Value', default: 0 },
326
+ { name: 'Type', default: 0 },
327
+ ],
328
+ fn: (rate: number, periods: number, payment: number, pv = 0, type = 0): UnionValue => {
329
+ return { type: ValueType.number, value: fv_function(rate, periods, payment, pv, type) };
330
+ },
331
+ },
332
+
333
+ PV: {
334
+ description: 'Returns the present value of an investment',
335
+ arguments: [
336
+ { name: 'Rate', },
337
+ { name: 'Periods', },
338
+ { name: 'Payment', },
339
+ { name: 'Future Value', default: 0 },
340
+ { name: 'Type', default: 0 },
341
+ ],
342
+ fn: (rate: number, periods: number, payment: number, fv = 0, type = 0): UnionValue => {
343
+ if (type) {
344
+ payment += (fv * (1 / ((1 + rate) * ((Math.pow(1 + rate, periods) -1)/rate))));
345
+ return {
346
+ type: ValueType.number,
347
+ value: -(payment + payment / rate * (1 - Math.pow(1 + rate, -(periods - 1))))
348
+ };
349
+ }
350
+ return {
351
+ type: ValueType.number,
352
+ value: -(fv + (payment / rate * (Math.pow(1 + rate, periods) - 1))) / Math.pow(1 + rate, periods)
353
+ };
354
+ },
355
+ },
356
+
357
+ NPER: {
358
+ description: 'Returns the number of periods of an investment',
359
+ arguments: [
360
+ { name: 'Rate', },
361
+ { name: 'Payment', },
362
+ { name: 'Present Value', },
363
+ { name: 'Future Value', default: 0 },
364
+ { name: 'Type', default: 0 },
365
+ ],
366
+ fn: (rate :number, payment: number, pv = 0, fv = 0, type = 0): UnionValue => {
367
+ if (type) {
368
+ return {
369
+ type: ValueType.number,
370
+ value: 1 + (-Math.log(1 + rate * (1 - pv / -payment)) + Math.log(1 + fv * rate / (-payment * (1 + rate)))) / Math.log(1 + rate)
371
+ };
372
+ }
373
+ return {
374
+ type: ValueType.number,
375
+ value: (Math.log(Math.pow(1 - pv * rate / -payment, -1)) + Math.log(1 + fv * rate / -payment)) / Math.log(1 + rate)
376
+ };
377
+ },
378
+ },
379
+
380
+ PMT: {
381
+ description: 'Returns the periodic payment of a loan',
382
+ arguments: [
383
+ { name: 'Rate', },
384
+ { name: 'Periods', },
385
+ { name: 'Present Value', },
386
+ { name: 'Future Value', default: 0 },
387
+ { name: 'Type', default: 0 },
388
+ ],
389
+ fn: (rate: number, periods: number, pv: number, fv = 0, type = 0): UnionValue => {
390
+ return {
391
+ type: ValueType.number,
392
+ value: payment_function(rate, periods, pv, fv, type),
393
+ };
394
+ },
395
+ }
396
+
397
+
398
+ };
399
+
@@ -0,0 +1,102 @@
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-2023 trebco, llc.
18
+ * info@treb.app
19
+ *
20
+ */
21
+
22
+ import type { FunctionMap } from '../descriptors';
23
+ import { UnionValue, ValueType } from 'treb-base-types';
24
+ import * as Utils from '../utilities';
25
+
26
+ export const InformationFunctionLibrary: FunctionMap = {
27
+
28
+ IsBlank: {
29
+ description: 'Returns true if the reference is blank',
30
+ arguments: [{
31
+ name: 'Reference',
32
+ metadata: true,
33
+ }],
34
+ fn: Utils.ApplyAsArray((ref: UnionValue): UnionValue => {
35
+ return {
36
+ type: ValueType.boolean,
37
+ value: !ref?.value || typeof ref.value.value === 'undefined',
38
+ };
39
+ }),
40
+ },
41
+
42
+ IsNumber: {
43
+ description: 'Returns true if the reference is a number',
44
+ arguments: [{
45
+ name: 'Reference',
46
+ metadata: true,
47
+ }],
48
+ fn: Utils.ApplyAsArray((ref: UnionValue): UnionValue => {
49
+ return {
50
+ type: ValueType.boolean,
51
+ value: ref?.value && typeof ref.value.value === 'number',
52
+ };
53
+ }),
54
+ },
55
+
56
+ IsLogical: {
57
+ description: 'Returns true if the reference is a logical TRUE or FALSE',
58
+ arguments: [{
59
+ name: 'Reference',
60
+ metadata: true,
61
+ }],
62
+ fn: Utils.ApplyAsArray((ref: UnionValue): UnionValue => {
63
+ return {
64
+ type: ValueType.boolean,
65
+ value: ref?.value && typeof ref.value.value === 'boolean',
66
+ };
67
+ }),
68
+ },
69
+
70
+ IsText: {
71
+ description: 'Returns true if the reference is text',
72
+ arguments: [{
73
+ name: 'Reference',
74
+ metadata: true,
75
+ }],
76
+ fn: Utils.ApplyAsArray((ref: UnionValue): UnionValue => {
77
+ return {
78
+ type: ValueType.boolean,
79
+ value: ref?.value && typeof ref.value.value === 'string'
80
+ };
81
+ }),
82
+ },
83
+
84
+ /* needs more data
85
+ ISFORMULA: {
86
+ description: 'Returns true if the reference is a formula',
87
+ arguments: [{
88
+ name: 'Reference',
89
+ metadata: true,
90
+ }],
91
+ fn: (ref: UnionValue): UnionValue => {
92
+ console.info("RR", ref);
93
+ return {
94
+ type: ValueType.boolean,
95
+ value: ref?.value && typeof ref.value.value === 'string' && ref.value.value[0] === '=',
96
+ };
97
+ },
98
+ },
99
+ */
100
+
101
+ };
102
+
@@ -0,0 +1,182 @@
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-2023 trebco, llc.
18
+ * info@treb.app
19
+ *
20
+ */
21
+
22
+ import type { FunctionMap } from '../descriptors';
23
+ import { Complex, UnionValue, ValueType, ComplexOrReal } from 'treb-base-types';
24
+ import { ValueError } from '../function-error';
25
+ import * as ComplexMath from '../complex-math';
26
+
27
+ import type { ComplexMatrixType } from '../complex-math';
28
+
29
+ /**
30
+ * given a range of data, ensure it's an array, check dimensions, and
31
+ * convert all real entries to complex (if possible).
32
+ */
33
+ const ComplexMatrix = (input: UnionValue): ComplexMatrixType => {
34
+
35
+ let a: UnionValue[][] = [];
36
+
37
+ // ensure array
38
+
39
+ if (input.type === ValueType.array) {
40
+ a = input.value;
41
+ }
42
+ else {
43
+ a = [[input.value]];
44
+ }
45
+
46
+ // if (!Array.isArray(a)) { a = [[a]]; }
47
+
48
+ const m = a.length;
49
+ const n = m ? a[0].length : 0;
50
+ const array: Complex[][] = [];
51
+
52
+ // 0-length
53
+ if (!m || !n) {
54
+ return { m, n, array };
55
+ }
56
+
57
+ for (let i = 0; i < m; i++) {
58
+ const row: Complex[] = [];
59
+ for (let j = 0; j < n; j++) {
60
+ const ref = a[i][j];
61
+ if (ref.type === ValueType.complex) {
62
+ row.push({...ref.value});
63
+ }
64
+ else if (ref.type === ValueType.number) {
65
+ row.push({real: ref.value, imaginary: 0});
66
+ }
67
+ else if (ref.type === ValueType.undefined || ref.value === '') {
68
+ row.push({real: 0, imaginary: 0});
69
+ }
70
+ else {
71
+ return {m, n, error: true, array: []};
72
+ }
73
+ }
74
+ array.push(row);
75
+ }
76
+
77
+ return { m, n, array };
78
+
79
+ }
80
+
81
+ export const MatrixFunctionLibrary: FunctionMap = {
82
+
83
+ MDeterm: {
84
+ description: 'Returns the determinant of a matrix',
85
+ arguments: [
86
+ { name: 'matrix', boxed: true },
87
+ ],
88
+ fn: (a: UnionValue): UnionValue => {
89
+
90
+ const matrix = ComplexMatrix(a);
91
+
92
+ if (!matrix.array || !matrix.m || !matrix.n || matrix.m !== matrix.n || matrix.error) {
93
+ return ValueError();
94
+ }
95
+
96
+ const result = ComplexMath.ComplexDeterminant(matrix);
97
+
98
+ if (!result) {
99
+ return ValueError();
100
+ }
101
+
102
+ return ComplexOrReal(result);
103
+
104
+ },
105
+ },
106
+
107
+ MInverse: {
108
+ description: 'Returns the inverse matrix',
109
+ arguments: [
110
+ { name: 'matrix', boxed: true },
111
+ ],
112
+ fn: (a: UnionValue): UnionValue => {
113
+ const matrix = ComplexMatrix(a);
114
+
115
+ if (!matrix.array || !matrix.m || !matrix.n || matrix.m !== matrix.n || matrix.error) {
116
+ return ValueError();
117
+ }
118
+
119
+ // check singular
120
+ const det = ComplexMath.ComplexDeterminant(matrix);
121
+ if (det && (det.real === 0 && det?.imaginary === 0)) {
122
+ return ValueError();
123
+ }
124
+
125
+ const inverse = ComplexMath.MatrixInverse(matrix);
126
+
127
+ if (!inverse) {
128
+ return ValueError();
129
+ }
130
+
131
+ return {
132
+ type: ValueType.array,
133
+ value: inverse.map(row => row.map(value => ComplexOrReal(value))),
134
+ }
135
+
136
+ // return inverse.map(row => row.map(value => ComplexOrReal(value)));
137
+
138
+ },
139
+ },
140
+
141
+ MMult: {
142
+ description: 'Returns the dot product of A and B',
143
+ arguments: [
144
+ { name: 'A', boxed: true },
145
+ { name: 'B', boxed: true },
146
+ ],
147
+ fn: (a: UnionValue, b: UnionValue): UnionValue => {
148
+
149
+ const A = ComplexMatrix(a);
150
+ const B = ComplexMatrix(b);
151
+
152
+ // check data
153
+ if (!A.array || A.error || !B.array || B.error) {
154
+ return ValueError();
155
+ }
156
+
157
+ // check sizes
158
+ if (A.m !== B.n) {
159
+ return ValueError();
160
+ }
161
+
162
+ // NOTE the swap here. the input arrays are column-major,
163
+ // so we either need to transpose three times, or we can
164
+ // swap.
165
+
166
+ const product = ComplexMath.ComplexProduct(B, A);
167
+
168
+ // convert to reals where possible
169
+
170
+ return {
171
+ type: ValueType.array,
172
+ value: product.map(row => row.map(value => ComplexOrReal(value))),
173
+ };
174
+
175
+ // return product.map(row => row.map(value => ComplexOrReal(value)));
176
+
177
+ },
178
+ }
179
+
180
+
181
+
182
+ }