@actuarial-ts/data 0.6.0 → 0.7.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/README.md +3 -3
- package/dist/compactDiagnosticJson.d.ts +24 -0
- package/dist/compactDiagnosticJson.d.ts.map +1 -0
- package/dist/compactDiagnosticJson.js +200 -0
- package/dist/compactDiagnosticJson.js.map +1 -0
- package/dist/diagnosticInput.d.ts +55 -4
- package/dist/diagnosticInput.d.ts.map +1 -1
- package/dist/diagnosticInput.js +499 -35
- package/dist/diagnosticInput.js.map +1 -1
- package/dist/diagnosticPreparedReview.d.ts +72 -6
- package/dist/diagnosticPreparedReview.d.ts.map +1 -1
- package/dist/diagnosticPreparedReview.js +749 -38
- package/dist/diagnosticPreparedReview.js.map +1 -1
- package/dist/exposure.d.ts.map +1 -1
- package/dist/exposure.js +25 -9
- package/dist/exposure.js.map +1 -1
- package/dist/lossRun.d.ts.map +1 -1
- package/dist/lossRun.js +31 -8
- package/dist/lossRun.js.map +1 -1
- package/dist/review.d.ts +1 -2
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +33 -4
- package/dist/review.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -3
- package/src/compactDiagnosticJson.ts +216 -0
- package/src/diagnosticInput.ts +746 -51
- package/src/diagnosticPreparedReview.ts +1189 -37
- package/src/exposure.ts +61 -16
- package/src/lossRun.ts +55 -13
- package/src/review.ts +177 -40
- package/src/version.ts +1 -1
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createDiagnosticIdentityArray,
|
|
3
|
+
createDiagnosticIdentityObject,
|
|
4
|
+
createDiagnosticIdentityValue,
|
|
5
|
+
DiagnosticValidationError,
|
|
6
|
+
type DiagnosticIdentityDocument,
|
|
7
|
+
} from "@actuarial-ts/core";
|
|
8
|
+
|
|
9
|
+
/** Private column-backed snapshots for SDK-constructed finding records. No I/O. */
|
|
10
|
+
const CHUNK = 4096;
|
|
11
|
+
|
|
12
|
+
/** Internal capacity guard, exported only from this private module for tests. */
|
|
13
|
+
export function assertCompactFindingCapacity(
|
|
14
|
+
count: number,
|
|
15
|
+
addition = 1,
|
|
16
|
+
): void {
|
|
17
|
+
if (
|
|
18
|
+
!Number.isSafeInteger(count) ||
|
|
19
|
+
!Number.isSafeInteger(addition) ||
|
|
20
|
+
count < 0 ||
|
|
21
|
+
addition < 0 ||
|
|
22
|
+
count + addition > 0xffff_ffff
|
|
23
|
+
)
|
|
24
|
+
throw new DiagnosticValidationError([
|
|
25
|
+
{
|
|
26
|
+
domain: "input",
|
|
27
|
+
code: "expression-limit",
|
|
28
|
+
path: "$",
|
|
29
|
+
message: "Compact finding index capacity exceeded",
|
|
30
|
+
},
|
|
31
|
+
]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface Nodes {
|
|
35
|
+
kind: Uint8Array;
|
|
36
|
+
start: Uint32Array;
|
|
37
|
+
length: Uint32Array;
|
|
38
|
+
number: Float64Array;
|
|
39
|
+
}
|
|
40
|
+
export class CompactDiagnosticJson {
|
|
41
|
+
private nodes: Nodes[] = [];
|
|
42
|
+
private edges: Uint32Array[] = [];
|
|
43
|
+
private strings: string[] = [];
|
|
44
|
+
private stringIds = new Map<string, number>();
|
|
45
|
+
private primitiveIds = new Map<string | number, number>();
|
|
46
|
+
private smallNodes = new Map<string, number>();
|
|
47
|
+
private nodeCount = 0;
|
|
48
|
+
private edgeCount = 0;
|
|
49
|
+
private sealed = false;
|
|
50
|
+
private stringId(value: string): number {
|
|
51
|
+
let id = this.stringIds.get(value);
|
|
52
|
+
if (id === undefined) {
|
|
53
|
+
assertCompactFindingCapacity(this.strings.length);
|
|
54
|
+
id = this.strings.length;
|
|
55
|
+
this.strings.push(value);
|
|
56
|
+
this.stringIds.set(value, id);
|
|
57
|
+
}
|
|
58
|
+
return id;
|
|
59
|
+
}
|
|
60
|
+
add(value: unknown): number {
|
|
61
|
+
if (this.sealed) throw new Error("Finding snapshot table is sealed");
|
|
62
|
+
let kind: number;
|
|
63
|
+
let numeric = 0;
|
|
64
|
+
let primitive: string | number | undefined;
|
|
65
|
+
const edges: number[] = [];
|
|
66
|
+
if (value === null) {
|
|
67
|
+
kind = 0;
|
|
68
|
+
primitive = "null";
|
|
69
|
+
} else if (typeof value === "boolean") {
|
|
70
|
+
kind = 1;
|
|
71
|
+
numeric = value ? 1 : 0;
|
|
72
|
+
primitive = `bool/${numeric}`;
|
|
73
|
+
} else if (typeof value === "number") {
|
|
74
|
+
kind = 2;
|
|
75
|
+
numeric = value;
|
|
76
|
+
primitive = Object.is(value, -0) ? "-0" : value;
|
|
77
|
+
} else if (typeof value === "string") {
|
|
78
|
+
kind = 3;
|
|
79
|
+
numeric = this.stringId(value);
|
|
80
|
+
primitive = `string/${numeric}`;
|
|
81
|
+
} else if (value === undefined) {
|
|
82
|
+
kind = 7;
|
|
83
|
+
primitive = "undefined";
|
|
84
|
+
} else if (Array.isArray(value)) {
|
|
85
|
+
kind = 4;
|
|
86
|
+
for (const child of value) edges.push(this.add(child));
|
|
87
|
+
} else if (typeof value === "object") {
|
|
88
|
+
kind = Object.getPrototypeOf(value) === null ? 6 : 5;
|
|
89
|
+
for (const key of Object.keys(value))
|
|
90
|
+
edges.push(
|
|
91
|
+
this.stringId(key),
|
|
92
|
+
this.add((value as Record<string, unknown>)[key]),
|
|
93
|
+
);
|
|
94
|
+
} else throw new Error("Unsupported SDK finding snapshot value");
|
|
95
|
+
const signature =
|
|
96
|
+
primitive === undefined && edges.length <= 32
|
|
97
|
+
? `${kind}/${edges.join(",")}`
|
|
98
|
+
: undefined;
|
|
99
|
+
const previous =
|
|
100
|
+
primitive === undefined
|
|
101
|
+
? signature === undefined
|
|
102
|
+
? undefined
|
|
103
|
+
: this.smallNodes.get(signature)
|
|
104
|
+
: this.primitiveIds.get(primitive);
|
|
105
|
+
if (previous !== undefined) return previous;
|
|
106
|
+
assertCompactFindingCapacity(this.nodeCount);
|
|
107
|
+
assertCompactFindingCapacity(this.edgeCount, edges.length);
|
|
108
|
+
const id = this.nodeCount++;
|
|
109
|
+
const row = id % CHUNK;
|
|
110
|
+
if (row === 0)
|
|
111
|
+
this.nodes.push({
|
|
112
|
+
kind: new Uint8Array(CHUNK),
|
|
113
|
+
start: new Uint32Array(CHUNK),
|
|
114
|
+
length: new Uint32Array(CHUNK),
|
|
115
|
+
number: new Float64Array(CHUNK),
|
|
116
|
+
});
|
|
117
|
+
const block = this.nodes[Math.floor(id / CHUNK)]!;
|
|
118
|
+
block.kind[row] = kind;
|
|
119
|
+
block.start[row] = this.edgeCount;
|
|
120
|
+
block.length[row] = edges.length;
|
|
121
|
+
block.number[row] = numeric;
|
|
122
|
+
for (const child of edges) {
|
|
123
|
+
if (this.edgeCount % CHUNK === 0) this.edges.push(new Uint32Array(CHUNK));
|
|
124
|
+
this.edges[Math.floor(this.edgeCount / CHUNK)]![this.edgeCount % CHUNK] =
|
|
125
|
+
child;
|
|
126
|
+
this.edgeCount++;
|
|
127
|
+
}
|
|
128
|
+
if (primitive !== undefined) this.primitiveIds.set(primitive, id);
|
|
129
|
+
else if (signature !== undefined && this.smallNodes.size < 100_000)
|
|
130
|
+
this.smallNodes.set(signature, id);
|
|
131
|
+
return id;
|
|
132
|
+
}
|
|
133
|
+
seal(): void {
|
|
134
|
+
this.sealed = true;
|
|
135
|
+
this.stringIds.clear();
|
|
136
|
+
this.primitiveIds.clear();
|
|
137
|
+
this.smallNodes.clear();
|
|
138
|
+
}
|
|
139
|
+
private edge(index: number): number {
|
|
140
|
+
return this.edges[Math.floor(index / CHUNK)]![index % CHUNK]!;
|
|
141
|
+
}
|
|
142
|
+
length(id: number): number {
|
|
143
|
+
return this.nodes[Math.floor(id / CHUNK)]!.length[id % CHUNK]!;
|
|
144
|
+
}
|
|
145
|
+
property(id: number | undefined, key: string): number | undefined {
|
|
146
|
+
if (id === undefined) return undefined;
|
|
147
|
+
const block = this.nodes[Math.floor(id / CHUNK)]!;
|
|
148
|
+
const row = id % CHUNK;
|
|
149
|
+
for (let offset = 0; offset < block.length[row]!; offset += 2) {
|
|
150
|
+
const edge = block.start[row]! + offset;
|
|
151
|
+
if (this.strings[this.edge(edge)] === key) return this.edge(edge + 1);
|
|
152
|
+
}
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
arrayItem(id: number, index: number): number {
|
|
156
|
+
const block = this.nodes[Math.floor(id / CHUNK)]!;
|
|
157
|
+
return this.edge(block.start[id % CHUNK]! + index);
|
|
158
|
+
}
|
|
159
|
+
identityDocument(id: number): DiagnosticIdentityDocument {
|
|
160
|
+
if (!this.sealed) throw new Error("Finding snapshot table is not sealed");
|
|
161
|
+
const block = this.nodes[Math.floor(id / CHUNK)]!;
|
|
162
|
+
const row = id % CHUNK;
|
|
163
|
+
const kind = block.kind[row]!;
|
|
164
|
+
const start = block.start[row]!;
|
|
165
|
+
const length = block.length[row]!;
|
|
166
|
+
if (kind === 4)
|
|
167
|
+
return createDiagnosticIdentityArray(length, (index) =>
|
|
168
|
+
this.identityDocument(this.edge(start + index)),
|
|
169
|
+
);
|
|
170
|
+
if (kind === 5 || kind === 6) {
|
|
171
|
+
const fields: Record<string, DiagnosticIdentityDocument> =
|
|
172
|
+
Object.create(null);
|
|
173
|
+
for (let offset = 0; offset < length; offset += 2)
|
|
174
|
+
fields[this.strings[this.edge(start + offset)]!] =
|
|
175
|
+
this.identityDocument(this.edge(start + offset + 1));
|
|
176
|
+
return createDiagnosticIdentityObject(fields);
|
|
177
|
+
}
|
|
178
|
+
return createDiagnosticIdentityValue(this.read(id));
|
|
179
|
+
}
|
|
180
|
+
read(id: number, sourceCountsOnly = false): unknown {
|
|
181
|
+
const block = this.nodes[Math.floor(id / CHUNK)]!;
|
|
182
|
+
const row = id % CHUNK;
|
|
183
|
+
const kind = block.kind[row]!;
|
|
184
|
+
const start = block.start[row]!;
|
|
185
|
+
const length = block.length[row]!;
|
|
186
|
+
if (kind === 0) return null;
|
|
187
|
+
if (kind === 1) return block.number[row] === 1;
|
|
188
|
+
if (kind === 2) return block.number[row];
|
|
189
|
+
if (kind === 3) return this.strings[block.number[row]!];
|
|
190
|
+
if (kind === 7) return undefined;
|
|
191
|
+
if (kind === 4)
|
|
192
|
+
return Object.freeze(
|
|
193
|
+
Array.from({ length }, (_, index) =>
|
|
194
|
+
this.read(this.edge(start + index), sourceCountsOnly),
|
|
195
|
+
),
|
|
196
|
+
);
|
|
197
|
+
const result: Record<string, unknown> =
|
|
198
|
+
kind === 6 ? Object.create(null) : {};
|
|
199
|
+
for (let offset = 0; offset < length; offset += 2) {
|
|
200
|
+
const key = this.strings[this.edge(start + offset)]!;
|
|
201
|
+
const child = this.edge(start + offset + 1);
|
|
202
|
+
Object.defineProperty(
|
|
203
|
+
result,
|
|
204
|
+
sourceCountsOnly && key === "sources" ? "sourceCount" : key,
|
|
205
|
+
{
|
|
206
|
+
value:
|
|
207
|
+
sourceCountsOnly && key === "sources"
|
|
208
|
+
? this.length(child)
|
|
209
|
+
: this.read(child, sourceCountsOnly),
|
|
210
|
+
enumerable: true,
|
|
211
|
+
},
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return Object.freeze(result);
|
|
215
|
+
}
|
|
216
|
+
}
|