@fluidframework/matrix 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.3.1.0.125672
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/.eslintrc.js +23 -11
- package/.mocharc.js +2 -2
- package/README.md +21 -21
- package/api-extractor.json +2 -2
- package/bench/bsp-set-optimizations.md +5 -5
- package/bench/src/index.ts +38 -20
- package/bench/src/read/map.ts +16 -10
- package/bench/src/read/nativearray.ts +16 -10
- package/bench/src/read/test.ts +17 -19
- package/bench/src/read/tiled.ts +240 -181
- package/bench/src/util.ts +19 -18
- package/bench/tsconfig.json +8 -13
- package/dist/bspSet.d.ts.map +1 -1
- package/dist/bspSet.js.map +1 -1
- package/dist/handlecache.d.ts.map +1 -1
- package/dist/handlecache.js +1 -3
- package/dist/handlecache.js.map +1 -1
- package/dist/handletable.d.ts.map +1 -1
- package/dist/handletable.js +7 -3
- package/dist/handletable.js.map +1 -1
- package/dist/matrix.d.ts +2 -1
- package/dist/matrix.d.ts.map +1 -1
- package/dist/matrix.js +39 -24
- package/dist/matrix.js.map +1 -1
- package/dist/ops.d.ts.map +1 -1
- package/dist/ops.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/permutationvector.d.ts.map +1 -1
- package/dist/permutationvector.js +17 -10
- package/dist/permutationvector.js.map +1 -1
- package/dist/productSet.d.ts.map +1 -1
- package/dist/productSet.js +6 -3
- package/dist/productSet.js.map +1 -1
- package/dist/range.d.ts.map +1 -1
- package/dist/range.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js.map +1 -1
- package/dist/sparsearray2d.d.ts.map +1 -1
- package/dist/sparsearray2d.js +12 -12
- package/dist/sparsearray2d.js.map +1 -1
- package/dist/split.d.ts.map +1 -1
- package/dist/split.js +5 -3
- package/dist/split.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/undoprovider.d.ts.map +1 -1
- package/dist/undoprovider.js.map +1 -1
- package/lib/bspSet.d.ts.map +1 -1
- package/lib/bspSet.js.map +1 -1
- package/lib/handlecache.d.ts.map +1 -1
- package/lib/handlecache.js +1 -3
- package/lib/handlecache.js.map +1 -1
- package/lib/handletable.d.ts.map +1 -1
- package/lib/handletable.js +7 -3
- package/lib/handletable.js.map +1 -1
- package/lib/matrix.d.ts +2 -1
- package/lib/matrix.d.ts.map +1 -1
- package/lib/matrix.js +40 -25
- package/lib/matrix.js.map +1 -1
- package/lib/ops.d.ts.map +1 -1
- package/lib/ops.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/permutationvector.d.ts.map +1 -1
- package/lib/permutationvector.js +17 -10
- package/lib/permutationvector.js.map +1 -1
- package/lib/productSet.d.ts.map +1 -1
- package/lib/productSet.js +6 -3
- package/lib/productSet.js.map +1 -1
- package/lib/range.d.ts.map +1 -1
- package/lib/range.js.map +1 -1
- package/lib/runtime.d.ts.map +1 -1
- package/lib/runtime.js.map +1 -1
- package/lib/serialization.d.ts.map +1 -1
- package/lib/serialization.js.map +1 -1
- package/lib/sparsearray2d.d.ts.map +1 -1
- package/lib/sparsearray2d.js +12 -12
- package/lib/sparsearray2d.js.map +1 -1
- package/lib/split.d.ts.map +1 -1
- package/lib/split.js +5 -3
- package/lib/split.js.map +1 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js.map +1 -1
- package/lib/undoprovider.d.ts.map +1 -1
- package/lib/undoprovider.js +1 -1
- package/lib/undoprovider.js.map +1 -1
- package/package.json +23 -20
- package/prettier.config.cjs +1 -1
- package/src/bspSet.ts +507 -434
- package/src/handlecache.ts +114 -112
- package/src/handletable.ts +66 -62
- package/src/matrix.ts +781 -696
- package/src/ops.ts +11 -11
- package/src/packageVersion.ts +1 -1
- package/src/permutationvector.ts +425 -368
- package/src/productSet.ts +852 -788
- package/src/range.ts +8 -8
- package/src/runtime.ts +35 -35
- package/src/serialization.ts +13 -9
- package/src/sparsearray2d.ts +196 -192
- package/src/split.ts +111 -90
- package/src/types.ts +3 -3
- package/src/undoprovider.ts +161 -144
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +8 -12
package/src/productSet.ts
CHANGED
|
@@ -4,38 +4,44 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
7
|
+
BspSet,
|
|
8
|
+
empty,
|
|
9
|
+
dense,
|
|
10
|
+
Empty,
|
|
11
|
+
Dense,
|
|
12
|
+
combineCmp,
|
|
13
|
+
SetOperations,
|
|
14
|
+
intersectUntyped,
|
|
15
|
+
compareUntyped,
|
|
16
|
+
Cachable,
|
|
17
|
+
UntypedBspSet,
|
|
18
|
+
unionUntyped,
|
|
19
|
+
exceptUntyped,
|
|
20
|
+
lazy,
|
|
21
|
+
UntypedSparse,
|
|
22
|
+
fromUntyped,
|
|
23
|
+
meetsUntyped,
|
|
24
|
+
Pair,
|
|
25
25
|
} from "./bspSet";
|
|
26
26
|
|
|
27
27
|
type Restrict<T, Props extends (keyof T)[]> = { [Prop in Props[number]]: T[Prop] };
|
|
28
28
|
|
|
29
|
-
export type Product<T> = {
|
|
29
|
+
export type Product<T> = {
|
|
30
|
+
readonly [dim in keyof T]: T[dim] extends BspSet<infer _TKey, infer _TId> ? T[dim] : never;
|
|
31
|
+
};
|
|
30
32
|
|
|
31
33
|
type UntypedProduct<T> = {
|
|
32
|
-
|
|
34
|
+
readonly [dim in keyof T]?: T[dim] extends BspSet<infer TKey, infer _TId>
|
|
35
|
+
? UntypedSparse<TKey>
|
|
36
|
+
: never;
|
|
33
37
|
};
|
|
34
38
|
|
|
35
39
|
type Probabilities<T> = { readonly [dim in keyof T]?: number };
|
|
36
40
|
|
|
37
41
|
type ProductOperations<T> = {
|
|
38
|
-
|
|
42
|
+
readonly [dim in keyof T]: T[dim] extends BspSet<infer TKey, infer TId>
|
|
43
|
+
? SetOperations<TKey, TId>
|
|
44
|
+
: never;
|
|
39
45
|
};
|
|
40
46
|
|
|
41
47
|
/** Given a cartesian product, a subspace is a subset of said space, such that it is also a cartesian product
|
|
@@ -49,9 +55,9 @@ type ProductOperations<T> = {
|
|
|
49
55
|
* For the actual definition and properties, please read the document about *Operations on Cartesian Products*.
|
|
50
56
|
*/
|
|
51
57
|
interface Subspace<T> {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
readonly isSubspace: true;
|
|
59
|
+
// isCoSubspace: boolean;
|
|
60
|
+
readonly bounds: UntypedProduct<T>;
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
// type CoSubspace<T> = {
|
|
@@ -61,109 +67,109 @@ interface Subspace<T> {
|
|
|
61
67
|
// };
|
|
62
68
|
|
|
63
69
|
interface Union<T> {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
readonly isSubspace: false;
|
|
71
|
+
// readonly isCoSubspace: false;
|
|
72
|
+
readonly left: UntypedSparseProduct<T>;
|
|
73
|
+
readonly right: UntypedSparseProduct<T>;
|
|
74
|
+
readonly bounds: UntypedProduct<T>;
|
|
75
|
+
readonly subspaceCount: number;
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
type UntypedSparseProduct<T> = Subspace<T> | Union<T>; // | CoSubspace<T>;
|
|
73
79
|
|
|
74
80
|
interface SparseProduct<T> {
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
readonly productOperations: ProductOperations<T>;
|
|
82
|
+
readonly root: UntypedSparseProduct<T>;
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
interface Box<T> {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
box: UntypedProduct<T>;
|
|
87
|
+
probabilities: Probabilities<T>;
|
|
88
|
+
children?: Pair<Box<T>>;
|
|
89
|
+
depth: number;
|
|
84
90
|
}
|
|
85
91
|
|
|
86
92
|
const tops: { [poKey in string]?: Box<unknown> } = {};
|
|
87
93
|
const top = <T>(productOperations: ProductOperations<T>): Box<T> => {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
const dims: [keyof T, ProductOperations<T>[keyof T]["id"]][] = [];
|
|
95
|
+
for (const dimStr of Object.keys(productOperations)) {
|
|
96
|
+
const dim = dimStr as keyof T;
|
|
97
|
+
dims.push([dim, productOperations[dim].id]);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const poKey = JSON.stringify(dims.sort());
|
|
101
|
+
let currTop = tops[poKey];
|
|
102
|
+
if (currTop === undefined) {
|
|
103
|
+
currTop = { box: {}, probabilities: {}, depth: 1 };
|
|
104
|
+
tops[poKey] = currTop;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return currTop;
|
|
102
108
|
};
|
|
103
109
|
|
|
104
110
|
function subspace<T>(bounds: UntypedProduct<T>): Subspace<T> | Dense {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
let isDense = true;
|
|
112
|
+
for (const dim of Object.keys(bounds)) {
|
|
113
|
+
if (Object.prototype.hasOwnProperty.call(bounds, dim)) {
|
|
114
|
+
isDense = false;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (isDense) {
|
|
119
|
+
return dense;
|
|
120
|
+
}
|
|
121
|
+
return { isSubspace: true as const, bounds };
|
|
116
122
|
}
|
|
117
123
|
|
|
118
124
|
function getUntypedSubspaceCount<T>(set: UntypedSparseProduct<T>) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
if (set.isSubspace) {
|
|
126
|
+
return 1;
|
|
127
|
+
}
|
|
128
|
+
return set.subspaceCount;
|
|
123
129
|
}
|
|
124
130
|
|
|
125
131
|
const union = <T>(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
132
|
+
left: UntypedSparseProduct<T>,
|
|
133
|
+
right: UntypedSparseProduct<T>,
|
|
134
|
+
bounds: UntypedProduct<T>,
|
|
129
135
|
): Union<T> => ({
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
isSubspace: false as const,
|
|
137
|
+
left,
|
|
138
|
+
right,
|
|
139
|
+
bounds,
|
|
140
|
+
subspaceCount: getUntypedSubspaceCount(left) + getUntypedSubspaceCount(right),
|
|
135
141
|
});
|
|
136
142
|
|
|
137
143
|
function sparseProduct<T>(
|
|
138
|
-
|
|
139
|
-
|
|
144
|
+
productOperations: ProductOperations<T>,
|
|
145
|
+
root: UntypedSparseProduct<T> | Dense,
|
|
140
146
|
): SparseProduct<T> | Dense {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
147
|
+
if (root === dense) {
|
|
148
|
+
return root;
|
|
149
|
+
}
|
|
150
|
+
if (root.isSubspace) {
|
|
151
|
+
let hasSparseDimensions = false;
|
|
152
|
+
for (const dim of Object.keys(root.bounds)) {
|
|
153
|
+
if (Object.prototype.hasOwnProperty.call(productOperations, dim)) {
|
|
154
|
+
hasSparseDimensions = true;
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (!hasSparseDimensions) {
|
|
159
|
+
return dense;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return { productOperations, root };
|
|
157
163
|
}
|
|
158
164
|
|
|
159
165
|
type UntypedProductSet<T> = Empty | Dense | UntypedSparseProduct<T>;
|
|
160
166
|
export type ProductSet<T> = Empty | Dense | SparseProduct<T>;
|
|
161
167
|
|
|
162
168
|
function toBspSet<T>(set: UntypedBspSet<T> | undefined) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
169
|
+
if (set === undefined) {
|
|
170
|
+
return dense;
|
|
171
|
+
}
|
|
172
|
+
return set;
|
|
167
173
|
}
|
|
168
174
|
|
|
169
175
|
/** An object that contains all downcasts. The operations in here are generally of the kind that need dynamic
|
|
@@ -171,804 +177,862 @@ function toBspSet<T>(set: UntypedBspSet<T> | undefined) {
|
|
|
171
177
|
* more careful review whenever a change occurs, because we get less support from the type system and we are
|
|
172
178
|
* downcasting. */
|
|
173
179
|
const unsafe = {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
180
|
+
unzip<T>(product: Product<T>): ProductSet<T> {
|
|
181
|
+
const productOperations: { [dim in keyof T]?: SetOperations<unknown, unknown> } = {};
|
|
182
|
+
const root: { [dim in keyof T]?: UntypedSparse<unknown> } = {};
|
|
183
|
+
for (const dimStr of Object.keys(product)) {
|
|
184
|
+
const dim = dimStr as keyof T;
|
|
185
|
+
if (Object.prototype.hasOwnProperty.call(product, dim)) {
|
|
186
|
+
const set: BspSet<unknown, unknown> = product[dim];
|
|
187
|
+
if (set === empty) {
|
|
188
|
+
return empty;
|
|
189
|
+
}
|
|
190
|
+
if (set === dense) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
productOperations[dim] = set.setOperations;
|
|
195
|
+
root[dim] = set.root;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return sparseProduct(
|
|
200
|
+
productOperations as ProductOperations<T>,
|
|
201
|
+
subspace(root as UntypedProduct<T>),
|
|
202
|
+
);
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
combineProduct<T>(
|
|
206
|
+
productOperations: ProductOperations<T>,
|
|
207
|
+
left: UntypedProduct<T>,
|
|
208
|
+
right: UntypedProduct<T>,
|
|
209
|
+
combineFunc: <Key extends Cachable<Key>, Id>(
|
|
210
|
+
setOperations: SetOperations<Key, Id>,
|
|
211
|
+
left: UntypedBspSet<Key>,
|
|
212
|
+
right: UntypedBspSet<Key>,
|
|
213
|
+
) => UntypedBspSet<Key>,
|
|
214
|
+
) {
|
|
215
|
+
const res: { [dim in keyof T]?: UntypedSparse<unknown> } = {};
|
|
216
|
+
for (const dimStr of Object.keys(productOperations)) {
|
|
217
|
+
const dim = dimStr as keyof T;
|
|
218
|
+
if (Object.prototype.hasOwnProperty.call(productOperations, dim)) {
|
|
219
|
+
const combined = combineFunc<unknown, unknown>(
|
|
220
|
+
productOperations[dim],
|
|
221
|
+
toBspSet(left[dim]),
|
|
222
|
+
toBspSet(right[dim]),
|
|
223
|
+
);
|
|
224
|
+
if (combined === empty) {
|
|
225
|
+
return combined;
|
|
226
|
+
}
|
|
227
|
+
if (combined === dense) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
res[dim] = combined;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return res as UntypedProduct<T>;
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
238
|
+
restrict<T extends object, Props extends (keyof T)[]>(object: T, ...props: Props) {
|
|
239
|
+
const res: Partial<Restrict<T, Props>> = {};
|
|
240
|
+
for (const key of props) {
|
|
241
|
+
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
|
242
|
+
const prop = object[key];
|
|
243
|
+
res[key] = prop;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return res as Restrict<T, Props>;
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
fromUntypedProduct<T, Props extends (keyof T)[]>(
|
|
251
|
+
productOperations: ProductOperations<Restrict<T, Props>>,
|
|
252
|
+
bounds: UntypedProduct<Restrict<T, Props>>,
|
|
253
|
+
dims: Props,
|
|
254
|
+
) {
|
|
255
|
+
const product: { [dim in Props[number]]?: BspSet<unknown, unknown> } = {};
|
|
256
|
+
for (const dim of dims) {
|
|
257
|
+
const bound: UntypedSparse<unknown> | undefined = bounds[dim];
|
|
258
|
+
product[dim] = fromUntyped(productOperations[dim], bound !== undefined ? bound : dense);
|
|
259
|
+
}
|
|
260
|
+
return product as Product<Restrict<T, Props>>;
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
denseProduct<T, Props extends (keyof T)[]>(dims: Props): Product<Restrict<T, Props>> {
|
|
264
|
+
const top_inner: { [dim in Props[number]]?: Dense } = {};
|
|
265
|
+
for (const dim of dims) {
|
|
266
|
+
top_inner[dim] = dense;
|
|
267
|
+
}
|
|
268
|
+
return top_inner as Product<Restrict<T, Props>>;
|
|
269
|
+
},
|
|
261
270
|
};
|
|
262
271
|
|
|
263
272
|
export const createFromProduct = unsafe.unzip.bind(unsafe);
|
|
264
273
|
|
|
265
274
|
type Compatible<T, U> = { [dim in keyof T & keyof U]: T[dim] };
|
|
266
275
|
|
|
267
|
-
function joinBounds<T>(
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
276
|
+
function joinBounds<T>(
|
|
277
|
+
productOperations: ProductOperations<T>,
|
|
278
|
+
left: UntypedProduct<T>,
|
|
279
|
+
right: UntypedProduct<T>,
|
|
280
|
+
) {
|
|
281
|
+
const join = unsafe.combineProduct(productOperations, left, right, unionUntyped);
|
|
282
|
+
if (join === empty) {
|
|
283
|
+
throw new Error("broken invariant: the union of two non-empty products cannot be empty");
|
|
284
|
+
}
|
|
272
285
|
|
|
273
|
-
|
|
286
|
+
return join;
|
|
274
287
|
}
|
|
275
288
|
|
|
276
289
|
function compareSubspace<T>(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
290
|
+
productOperations: ProductOperations<T>,
|
|
291
|
+
left: UntypedProduct<T>,
|
|
292
|
+
right: UntypedProduct<T>,
|
|
280
293
|
) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
294
|
+
let cmp: ReturnType<typeof combineCmp> = 0;
|
|
295
|
+
for (const dimStr of Object.keys(productOperations)) {
|
|
296
|
+
const dim = dimStr as keyof T;
|
|
297
|
+
if (Object.prototype.hasOwnProperty.call(productOperations, dim)) {
|
|
298
|
+
const lProj = toBspSet(left[dim]);
|
|
299
|
+
const rProj = toBspSet(right[dim]);
|
|
300
|
+
const setOperations = productOperations[dim];
|
|
301
|
+
|
|
302
|
+
cmp = combineCmp(cmp, compareUntyped<unknown, unknown>(setOperations, lProj, rProj));
|
|
303
|
+
|
|
304
|
+
if (cmp === undefined) {
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return cmp;
|
|
298
311
|
}
|
|
299
312
|
|
|
300
313
|
const tryUnionSubspaces = (() => {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
314
|
+
const cache: { left?: unknown; right?: unknown; res?: unknown } = {};
|
|
315
|
+
return <T>(
|
|
316
|
+
productOperations: ProductOperations<T>,
|
|
317
|
+
left: Subspace<T>,
|
|
318
|
+
right: Subspace<T>,
|
|
319
|
+
): Subspace<T> | Dense | Empty | undefined => {
|
|
320
|
+
if (left === cache.left && right === cache.right) {
|
|
321
|
+
return cache.res as ReturnType<typeof tryUnionSubspaces>;
|
|
322
|
+
}
|
|
323
|
+
cache.left = left;
|
|
324
|
+
cache.right = right;
|
|
325
|
+
|
|
326
|
+
const cmp = compareSubspace(productOperations, left.bounds, right.bounds);
|
|
327
|
+
if (cmp !== undefined) {
|
|
328
|
+
return (cache.res = cmp <= 0 ? right : left);
|
|
329
|
+
}
|
|
330
|
+
let differentDimension: keyof T | undefined;
|
|
331
|
+
|
|
332
|
+
// because Object.keys only returns string[], we need to downcast
|
|
333
|
+
const po_keys = Object.keys(productOperations) as (keyof T)[];
|
|
334
|
+
for (const dim of po_keys) {
|
|
335
|
+
if (Object.prototype.hasOwnProperty.call(productOperations, dim)) {
|
|
336
|
+
const cmp_inner = compareUntyped<unknown, unknown>(
|
|
337
|
+
productOperations[dim],
|
|
338
|
+
toBspSet(left.bounds[dim]),
|
|
339
|
+
toBspSet(right.bounds[dim]),
|
|
340
|
+
);
|
|
341
|
+
if (cmp_inner !== 0) {
|
|
342
|
+
if (differentDimension !== undefined) {
|
|
343
|
+
return (cache.res = undefined);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
differentDimension = dim;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (differentDimension !== undefined) {
|
|
352
|
+
const newDim = unionUntyped<unknown, unknown>(
|
|
353
|
+
productOperations[differentDimension],
|
|
354
|
+
toBspSet(left.bounds[differentDimension]),
|
|
355
|
+
toBspSet(right.bounds[differentDimension]),
|
|
356
|
+
);
|
|
357
|
+
if (newDim === empty) {
|
|
358
|
+
return (cache.res = empty);
|
|
359
|
+
}
|
|
360
|
+
if (newDim === dense) {
|
|
361
|
+
// we are actually deleting the `differentDimension`, so the variable
|
|
362
|
+
// `deleted` must be there. Hence disabling the rule here.
|
|
363
|
+
const { [differentDimension]: deleted, ...leftBoundsWithoutDifferentDimension } =
|
|
364
|
+
left.bounds;
|
|
365
|
+
return (cache.res = subspace<unknown>(leftBoundsWithoutDifferentDimension));
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const newBounds: UntypedProduct<T> = {
|
|
369
|
+
...left.bounds,
|
|
370
|
+
[differentDimension]: newDim,
|
|
371
|
+
};
|
|
372
|
+
return (cache.res = subspace(newBounds));
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return (cache.res = undefined);
|
|
376
|
+
};
|
|
363
377
|
})();
|
|
364
378
|
|
|
365
379
|
function combineChildren<T>(
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
380
|
+
productOperations: ProductOperations<T>,
|
|
381
|
+
left: UntypedProductSet<T>,
|
|
382
|
+
right: UntypedProductSet<T>,
|
|
369
383
|
): UntypedProductSet<T> {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
384
|
+
if (right === empty) {
|
|
385
|
+
return left;
|
|
386
|
+
}
|
|
387
|
+
if (right === dense) {
|
|
388
|
+
return right;
|
|
389
|
+
}
|
|
390
|
+
if (left === empty) {
|
|
391
|
+
return right;
|
|
392
|
+
}
|
|
393
|
+
if (left === dense) {
|
|
394
|
+
return left;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (!left.isSubspace || !right.isSubspace) {
|
|
398
|
+
return union<T>(left, right, joinBounds(productOperations, left.bounds, right.bounds));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const combinedSubspace = tryUnionSubspaces<T>(productOperations, left, right);
|
|
402
|
+
|
|
403
|
+
if (combinedSubspace !== undefined) {
|
|
404
|
+
return combinedSubspace;
|
|
405
|
+
}
|
|
406
|
+
return union(left, right, joinBounds(productOperations, left.bounds, right.bounds));
|
|
393
407
|
}
|
|
394
408
|
|
|
395
409
|
function projectUntyped<T, Props extends (keyof T)[]>(
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
410
|
+
productOperations: ProductOperations<T>,
|
|
411
|
+
set: UntypedSparseProduct<T>,
|
|
412
|
+
...dims: Props
|
|
399
413
|
): UntypedProductSet<Restrict<T, Props>> {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
414
|
+
const bounds = unsafe.restrict(set.bounds, ...dims);
|
|
415
|
+
if (set.isSubspace) {
|
|
416
|
+
return subspace(bounds);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const lChild = projectUntyped(productOperations, set.left, ...dims);
|
|
420
|
+
if (lChild === dense) {
|
|
421
|
+
return dense;
|
|
422
|
+
}
|
|
423
|
+
const rChild = projectUntyped(productOperations, set.right, ...dims);
|
|
424
|
+
return combineChildren(productOperations, lChild, rChild);
|
|
411
425
|
}
|
|
412
426
|
|
|
413
427
|
export function project<T, Props extends (keyof T)[]>(
|
|
414
|
-
|
|
415
|
-
|
|
428
|
+
set: ProductSet<T>,
|
|
429
|
+
...dims: Props
|
|
416
430
|
): ProductSet<Restrict<T, Props>> {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
431
|
+
if (set === dense || set === empty) {
|
|
432
|
+
return set;
|
|
433
|
+
}
|
|
434
|
+
const productOperations = unsafe.restrict(set.productOperations, ...dims);
|
|
435
|
+
const root = projectUntyped(productOperations, set.root, ...dims);
|
|
436
|
+
if (root === empty) {
|
|
437
|
+
return root;
|
|
438
|
+
}
|
|
439
|
+
return sparseProduct(productOperations, root);
|
|
426
440
|
}
|
|
427
441
|
|
|
428
442
|
function splitBox<T>(productOperations: ProductOperations<T>, currentBox: Box<T>): Pair<Box<T>> {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
443
|
+
if (currentBox.children !== undefined) {
|
|
444
|
+
return currentBox.children;
|
|
445
|
+
}
|
|
446
|
+
const { box, probabilities } = currentBox;
|
|
447
|
+
let biggestDim: keyof T | undefined;
|
|
448
|
+
let biggestDimKey;
|
|
449
|
+
let currentProb = 0;
|
|
450
|
+
// because Object.keys only returns string[], we need to downcast
|
|
451
|
+
const po_keys = Object.keys(productOperations) as (keyof T)[];
|
|
452
|
+
for (const dim of po_keys) {
|
|
453
|
+
if (Object.prototype.hasOwnProperty.call(productOperations, dim)) {
|
|
454
|
+
const prob: number | undefined = probabilities[dim];
|
|
455
|
+
const setOperations_inner = productOperations[dim];
|
|
456
|
+
if (prob === undefined) {
|
|
457
|
+
biggestDim = dim;
|
|
458
|
+
biggestDimKey = setOperations_inner.top;
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (prob > currentProb) {
|
|
463
|
+
const dimensionSet = toBspSet(box[dim]);
|
|
464
|
+
if (dimensionSet === empty) {
|
|
465
|
+
throw new Error("the key split can never return empty");
|
|
466
|
+
}
|
|
467
|
+
let key = setOperations_inner.top;
|
|
468
|
+
if (dimensionSet !== dense) {
|
|
469
|
+
if (!dimensionSet.isExact) {
|
|
470
|
+
throw new Error("the key can always be represented exactly");
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
key = dimensionSet.key;
|
|
474
|
+
}
|
|
475
|
+
if (!setOperations_inner.canSplit(key)) {
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
biggestDim = dim;
|
|
479
|
+
currentProb = prob;
|
|
480
|
+
biggestDimKey = key;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (biggestDim === undefined || biggestDimKey === undefined) {
|
|
486
|
+
throw new Error("there has to be at least one dimension");
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const setOperations = productOperations[biggestDim];
|
|
490
|
+
|
|
491
|
+
const [[leftDim, leftProb], [rightDim, rightProb]] = setOperations.split(biggestDimKey);
|
|
492
|
+
const res: ReturnType<typeof splitBox> = [
|
|
493
|
+
{
|
|
494
|
+
box: {
|
|
495
|
+
...box,
|
|
496
|
+
[biggestDim]: lazy<unknown, unknown>(setOperations, setOperations.top, leftDim),
|
|
497
|
+
},
|
|
498
|
+
probabilities: { ...probabilities, [biggestDim]: leftProb },
|
|
499
|
+
depth: currentBox.depth + 1,
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
box: {
|
|
503
|
+
...box,
|
|
504
|
+
[biggestDim]: lazy<unknown, unknown>(setOperations, setOperations.top, rightDim),
|
|
505
|
+
},
|
|
506
|
+
probabilities: { ...probabilities, [biggestDim]: rightProb },
|
|
507
|
+
depth: currentBox.depth + 1,
|
|
508
|
+
},
|
|
509
|
+
];
|
|
510
|
+
if (currentBox.depth < 10) {
|
|
511
|
+
currentBox.children = res;
|
|
512
|
+
}
|
|
513
|
+
return res;
|
|
492
514
|
}
|
|
493
515
|
|
|
494
516
|
function restrictByBounds<T>(
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
517
|
+
productOperations: ProductOperations<T>,
|
|
518
|
+
set: UntypedProductSet<T>,
|
|
519
|
+
leftBounds: UntypedProduct<T>,
|
|
520
|
+
rightBounds: UntypedProduct<T>,
|
|
499
521
|
): Pair<UntypedProductSet<T>> {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
522
|
+
if (set === empty) {
|
|
523
|
+
return [empty, empty];
|
|
524
|
+
}
|
|
525
|
+
if (set === dense) {
|
|
526
|
+
return [subspace(leftBounds), subspace(rightBounds)];
|
|
527
|
+
}
|
|
528
|
+
const cmp = compareSubspace(productOperations, set.bounds, leftBounds);
|
|
529
|
+
|
|
530
|
+
// the set is fully contained in the left half, i.e. we know the pair.
|
|
531
|
+
if (cmp !== undefined && cmp <= 0) {
|
|
532
|
+
return [set, empty];
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const newLeftBounds = unsafe.combineProduct(
|
|
536
|
+
productOperations,
|
|
537
|
+
set.bounds,
|
|
538
|
+
leftBounds,
|
|
539
|
+
intersectUntyped,
|
|
540
|
+
);
|
|
541
|
+
|
|
542
|
+
// if we know, that the left set is completely empty, then the whole set is in the right bounds.
|
|
543
|
+
if (newLeftBounds === empty) {
|
|
544
|
+
return [empty, set];
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const newRightBounds = unsafe.combineProduct(
|
|
548
|
+
productOperations,
|
|
549
|
+
set.bounds,
|
|
550
|
+
rightBounds,
|
|
551
|
+
intersectUntyped,
|
|
552
|
+
);
|
|
553
|
+
if (set.isSubspace) {
|
|
554
|
+
return [
|
|
555
|
+
subspace(newLeftBounds),
|
|
556
|
+
newRightBounds === empty ? empty : subspace(newRightBounds),
|
|
557
|
+
];
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const [ll, lr] = restrictByBounds(productOperations, set.left, leftBounds, rightBounds);
|
|
561
|
+
const [rl, rr] = restrictByBounds(productOperations, set.right, leftBounds, rightBounds);
|
|
562
|
+
return [combineChildren(productOperations, ll, rl), combineChildren(productOperations, lr, rr)];
|
|
528
563
|
}
|
|
529
564
|
|
|
530
565
|
const splitByBox = <T>(
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
566
|
+
productOperations: ProductOperations<T>,
|
|
567
|
+
set: UntypedProductSet<T>,
|
|
568
|
+
{ box: leftBounds }: Box<T>,
|
|
569
|
+
{ box: rightBounds }: Box<T>,
|
|
535
570
|
): Pair<UntypedProductSet<T>, UntypedProductSet<T>> => {
|
|
536
|
-
|
|
571
|
+
return restrictByBounds(productOperations, set, leftBounds, rightBounds);
|
|
537
572
|
};
|
|
538
573
|
|
|
539
574
|
function recurse<T>(
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
575
|
+
productOperations: ProductOperations<T>,
|
|
576
|
+
left: UntypedProductSet<T>,
|
|
577
|
+
right: UntypedProductSet<T>,
|
|
578
|
+
currentBox: Box<T>,
|
|
579
|
+
visitFunc: (
|
|
580
|
+
productOperations: ProductOperations<T>,
|
|
581
|
+
left: UntypedProductSet<T>,
|
|
582
|
+
right: UntypedProductSet<T>,
|
|
583
|
+
box: Box<T>,
|
|
584
|
+
) => UntypedProductSet<T>,
|
|
550
585
|
) {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
586
|
+
const [leftBox, rightBox] = splitBox(productOperations, currentBox);
|
|
587
|
+
const [ll, lr] = splitByBox(productOperations, left, leftBox, rightBox);
|
|
588
|
+
const [rl, rr] = splitByBox(productOperations, right, leftBox, rightBox);
|
|
589
|
+
|
|
590
|
+
const lChild = visitFunc(productOperations, ll, rl, leftBox);
|
|
591
|
+
if (lChild === dense) {
|
|
592
|
+
return dense;
|
|
593
|
+
}
|
|
594
|
+
const rChild = visitFunc(productOperations, lr, rr, rightBox);
|
|
595
|
+
return combineChildren(productOperations, lChild, rChild);
|
|
561
596
|
}
|
|
562
597
|
|
|
563
598
|
function unionUntypedProduct<T>(
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
599
|
+
productOperations: ProductOperations<T>,
|
|
600
|
+
left: UntypedProductSet<T>,
|
|
601
|
+
right: UntypedProductSet<T>,
|
|
602
|
+
currentBox: Box<T>,
|
|
568
603
|
): UntypedProductSet<T> {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
604
|
+
if (right === empty) {
|
|
605
|
+
return left;
|
|
606
|
+
}
|
|
607
|
+
if (left === empty) {
|
|
608
|
+
return right;
|
|
609
|
+
}
|
|
610
|
+
if (left === dense) {
|
|
611
|
+
return left;
|
|
612
|
+
}
|
|
613
|
+
if (right === dense) {
|
|
614
|
+
return right;
|
|
615
|
+
}
|
|
616
|
+
if (left.isSubspace && right.isSubspace) {
|
|
617
|
+
const combinedSubspace = tryUnionSubspaces(productOperations, left, right);
|
|
618
|
+
if (combinedSubspace !== undefined) {
|
|
619
|
+
return combinedSubspace;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
return recurse(productOperations, left, right, currentBox, unionUntypedProduct);
|
|
589
624
|
}
|
|
590
625
|
|
|
591
626
|
export function unionProduct<T extends Compatible<U, T>, U extends Compatible<T, U>>(
|
|
592
|
-
|
|
593
|
-
|
|
627
|
+
left: ProductSet<T>,
|
|
628
|
+
right: ProductSet<U>,
|
|
594
629
|
): ProductSet<T & U> {
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
630
|
+
if (right === empty) {
|
|
631
|
+
return left;
|
|
632
|
+
}
|
|
633
|
+
if (right === dense) {
|
|
634
|
+
return right;
|
|
635
|
+
}
|
|
636
|
+
if (left === empty) {
|
|
637
|
+
return right;
|
|
638
|
+
}
|
|
639
|
+
if (left === dense) {
|
|
640
|
+
return left;
|
|
641
|
+
}
|
|
642
|
+
const productOperations = { ...left.productOperations, ...right.productOperations };
|
|
643
|
+
const res = unionUntypedProduct(
|
|
644
|
+
productOperations,
|
|
645
|
+
left.root,
|
|
646
|
+
right.root,
|
|
647
|
+
top(productOperations),
|
|
648
|
+
);
|
|
649
|
+
if (res === empty) {
|
|
650
|
+
return res;
|
|
651
|
+
}
|
|
652
|
+
return sparseProduct(productOperations, res);
|
|
613
653
|
}
|
|
614
654
|
|
|
615
655
|
function intersectUntypedProduct<T>(
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
656
|
+
productOperations: ProductOperations<T>,
|
|
657
|
+
left: UntypedProductSet<T>,
|
|
658
|
+
right: UntypedProductSet<T>,
|
|
659
|
+
currentBox: Box<T>,
|
|
620
660
|
): UntypedProductSet<T> {
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
661
|
+
if (left === empty || right === empty) {
|
|
662
|
+
return empty;
|
|
663
|
+
}
|
|
664
|
+
if (left === dense) {
|
|
665
|
+
return right;
|
|
666
|
+
}
|
|
667
|
+
if (right === dense) {
|
|
668
|
+
return left;
|
|
669
|
+
}
|
|
670
|
+
if (left.isSubspace && right.isSubspace) {
|
|
671
|
+
const res = unsafe.combineProduct(
|
|
672
|
+
productOperations,
|
|
673
|
+
left.bounds,
|
|
674
|
+
right.bounds,
|
|
675
|
+
intersectUntyped,
|
|
676
|
+
);
|
|
677
|
+
if (res === empty) {
|
|
678
|
+
return empty;
|
|
679
|
+
}
|
|
680
|
+
return subspace(res);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
return recurse(productOperations, left, right, currentBox, intersectUntypedProduct);
|
|
639
684
|
}
|
|
640
685
|
|
|
641
686
|
export function intersectProduct<T extends Compatible<U, T>, U extends Compatible<T, U>>(
|
|
642
|
-
|
|
643
|
-
|
|
687
|
+
left: ProductSet<T>,
|
|
688
|
+
right: ProductSet<U>,
|
|
644
689
|
): ProductSet<T & U> {
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
690
|
+
if (left === empty) {
|
|
691
|
+
return left;
|
|
692
|
+
}
|
|
693
|
+
if (right === empty) {
|
|
694
|
+
return right;
|
|
695
|
+
}
|
|
696
|
+
if (left === dense) {
|
|
697
|
+
return right;
|
|
698
|
+
}
|
|
699
|
+
if (right === dense) {
|
|
700
|
+
return left;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const productOperations = { ...left.productOperations, ...right.productOperations };
|
|
704
|
+
const res = intersectUntypedProduct(
|
|
705
|
+
productOperations,
|
|
706
|
+
left.root,
|
|
707
|
+
right.root,
|
|
708
|
+
top(productOperations),
|
|
709
|
+
);
|
|
710
|
+
if (res === empty) {
|
|
711
|
+
return res;
|
|
712
|
+
}
|
|
713
|
+
return sparseProduct(productOperations, res);
|
|
664
714
|
}
|
|
665
715
|
|
|
666
716
|
function tryExceptSubspaces<T>(
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
717
|
+
productOperations: ProductOperations<T>,
|
|
718
|
+
left: Subspace<T>,
|
|
719
|
+
right: Subspace<T>,
|
|
670
720
|
): Subspace<T> | Dense | Empty | undefined {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
721
|
+
const cmp = compareSubspace(productOperations, left.bounds, right.bounds);
|
|
722
|
+
if (cmp === 0 || cmp === -1) {
|
|
723
|
+
return empty;
|
|
724
|
+
}
|
|
725
|
+
let notContainedDimension: keyof T | undefined;
|
|
726
|
+
// because Object.keys only returns string[], we need to downcast
|
|
727
|
+
const po_keys = Object.keys(productOperations) as (keyof T)[];
|
|
728
|
+
for (const dim of po_keys) {
|
|
729
|
+
if (Object.prototype.hasOwnProperty.call(productOperations, dim)) {
|
|
730
|
+
const cmp_inner = compareUntyped<unknown, unknown>(
|
|
731
|
+
productOperations[dim],
|
|
732
|
+
toBspSet(left.bounds[dim]),
|
|
733
|
+
toBspSet(right.bounds[dim]),
|
|
734
|
+
);
|
|
735
|
+
if (cmp_inner === undefined || cmp_inner > 0) {
|
|
736
|
+
if (notContainedDimension !== undefined) {
|
|
737
|
+
return undefined;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
notContainedDimension = dim;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (notContainedDimension !== undefined) {
|
|
746
|
+
const newDim = exceptUntyped<unknown, unknown>(
|
|
747
|
+
productOperations[notContainedDimension],
|
|
748
|
+
toBspSet(left.bounds[notContainedDimension]),
|
|
749
|
+
toBspSet(right.bounds[notContainedDimension]),
|
|
750
|
+
);
|
|
751
|
+
|
|
752
|
+
if (newDim === empty) {
|
|
753
|
+
return empty;
|
|
754
|
+
}
|
|
755
|
+
if (newDim === dense) {
|
|
756
|
+
// we are actually deleting the `differentDimension`, so the variable
|
|
757
|
+
// `deleted` must be there. Hence disabling the rule here.
|
|
758
|
+
const { [notContainedDimension]: deleted, ...leftBoundsWithoutDifferentDimension } =
|
|
759
|
+
left.bounds;
|
|
760
|
+
return subspace<unknown>(leftBoundsWithoutDifferentDimension);
|
|
761
|
+
}
|
|
762
|
+
const newBounds: UntypedProduct<T> = {
|
|
763
|
+
...left.bounds,
|
|
764
|
+
[notContainedDimension]: newDim,
|
|
765
|
+
};
|
|
766
|
+
return subspace(newBounds);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
return undefined;
|
|
719
770
|
}
|
|
720
771
|
|
|
721
772
|
function exceptUntypedProduct<T>(
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
773
|
+
productOperations: ProductOperations<T>,
|
|
774
|
+
left: UntypedProductSet<T>,
|
|
775
|
+
right: UntypedProductSet<T>,
|
|
776
|
+
currentBox: Box<T>,
|
|
726
777
|
): UntypedProductSet<T> {
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
778
|
+
if (left === empty) {
|
|
779
|
+
return left;
|
|
780
|
+
}
|
|
781
|
+
if (right === dense) {
|
|
782
|
+
return empty;
|
|
783
|
+
}
|
|
784
|
+
if (right === empty) {
|
|
785
|
+
return left;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
if (left === dense) {
|
|
789
|
+
return recurse(productOperations, left, right, currentBox, exceptUntypedProduct);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
if (left.isSubspace && right.isSubspace) {
|
|
793
|
+
const combinedSubspace = tryExceptSubspaces(productOperations, left, right);
|
|
794
|
+
if (combinedSubspace !== undefined) {
|
|
795
|
+
return combinedSubspace;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
return recurse(productOperations, left, right, currentBox, exceptUntypedProduct);
|
|
749
800
|
}
|
|
750
801
|
|
|
751
802
|
export function exceptProduct<T extends Compatible<U, T>, U extends Compatible<T, U>>(
|
|
752
|
-
|
|
753
|
-
|
|
803
|
+
left: ProductSet<T>,
|
|
804
|
+
right: ProductSet<U>,
|
|
754
805
|
): ProductSet<T & U> {
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
806
|
+
if (left === empty) {
|
|
807
|
+
return left;
|
|
808
|
+
}
|
|
809
|
+
if (right === empty) {
|
|
810
|
+
return left;
|
|
811
|
+
}
|
|
812
|
+
if (right === dense) {
|
|
813
|
+
return empty;
|
|
814
|
+
}
|
|
815
|
+
if (left === dense) {
|
|
816
|
+
const res_inner = exceptUntypedProduct(
|
|
817
|
+
right.productOperations,
|
|
818
|
+
dense,
|
|
819
|
+
right.root,
|
|
820
|
+
top(right.productOperations),
|
|
821
|
+
);
|
|
822
|
+
if (res_inner === empty) {
|
|
823
|
+
return res_inner;
|
|
824
|
+
}
|
|
825
|
+
return sparseProduct(right.productOperations, res_inner);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
const productOperations = { ...left.productOperations, ...right.productOperations };
|
|
829
|
+
const res = exceptUntypedProduct(
|
|
830
|
+
productOperations,
|
|
831
|
+
left.root,
|
|
832
|
+
right.root,
|
|
833
|
+
top(productOperations),
|
|
834
|
+
);
|
|
835
|
+
if (res === empty) {
|
|
836
|
+
return res;
|
|
837
|
+
}
|
|
838
|
+
return sparseProduct(productOperations, res);
|
|
779
839
|
}
|
|
780
840
|
|
|
781
841
|
function compareUntypedProduct<T>(
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
842
|
+
productOperations: ProductOperations<T>,
|
|
843
|
+
left: UntypedProductSet<T>,
|
|
844
|
+
right: UntypedProductSet<T>,
|
|
845
|
+
boundingBox: Box<T>,
|
|
786
846
|
): -1 | 0 | 1 | undefined {
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
847
|
+
if (left === right) {
|
|
848
|
+
return 0;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
if (left === empty) {
|
|
852
|
+
return -1;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (right === empty) {
|
|
856
|
+
return 1;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
if (left === dense) {
|
|
860
|
+
if (right === dense) {
|
|
861
|
+
return 0;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
return 1;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
if (right === dense) {
|
|
868
|
+
return -1;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
if (left.isSubspace) {
|
|
872
|
+
if (right.isSubspace) {
|
|
873
|
+
return compareSubspace(productOperations, left.bounds, right.bounds);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
const [leftBox, rightBox] = splitBox(productOperations, boundingBox);
|
|
878
|
+
const [ll, lr] = splitByBox(productOperations, left, leftBox, rightBox);
|
|
879
|
+
const [rl, rr] = splitByBox(productOperations, right, leftBox, rightBox);
|
|
880
|
+
|
|
881
|
+
const leftCmp = compareUntypedProduct(productOperations, ll, rl, leftBox);
|
|
882
|
+
if (leftCmp === undefined) {
|
|
883
|
+
return undefined;
|
|
884
|
+
}
|
|
885
|
+
return combineCmp(leftCmp, compareUntypedProduct(productOperations, lr, rr, rightBox));
|
|
826
886
|
}
|
|
827
887
|
|
|
828
888
|
export function compareProduct<T extends Compatible<U, T>, U extends Compatible<T, U>>(
|
|
829
|
-
|
|
830
|
-
|
|
889
|
+
left: ProductSet<T>,
|
|
890
|
+
right: ProductSet<U>,
|
|
831
891
|
) {
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
892
|
+
if (left === right) {
|
|
893
|
+
return 0;
|
|
894
|
+
}
|
|
835
895
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
896
|
+
if (left === empty) {
|
|
897
|
+
return -1;
|
|
898
|
+
}
|
|
839
899
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
900
|
+
if (right === empty) {
|
|
901
|
+
return 1;
|
|
902
|
+
}
|
|
843
903
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
904
|
+
if (left === dense) {
|
|
905
|
+
if (right === dense) {
|
|
906
|
+
return 0;
|
|
907
|
+
}
|
|
848
908
|
|
|
849
|
-
|
|
850
|
-
|
|
909
|
+
return 1;
|
|
910
|
+
}
|
|
851
911
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
912
|
+
if (right === dense) {
|
|
913
|
+
return -1;
|
|
914
|
+
}
|
|
855
915
|
|
|
856
|
-
|
|
857
|
-
|
|
916
|
+
const productOperations = { ...left.productOperations, ...right.productOperations };
|
|
917
|
+
return compareUntypedProduct(productOperations, left.root, right.root, top(productOperations));
|
|
858
918
|
}
|
|
859
919
|
|
|
860
|
-
function meetsSubspace<T>(
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
920
|
+
function meetsSubspace<T>(
|
|
921
|
+
productOperations: ProductOperations<T>,
|
|
922
|
+
left: UntypedProduct<T>,
|
|
923
|
+
right: UntypedProduct<T>,
|
|
924
|
+
) {
|
|
925
|
+
for (const dimStr of Object.keys(productOperations)) {
|
|
926
|
+
const dim = dimStr as keyof T;
|
|
927
|
+
if (Object.prototype.hasOwnProperty.call(productOperations, dim)) {
|
|
928
|
+
const lProj = toBspSet(left[dim]);
|
|
929
|
+
const rProj = toBspSet(right[dim]);
|
|
930
|
+
const setOperations = productOperations[dim];
|
|
931
|
+
if (!meetsUntyped<unknown, unknown>(setOperations, lProj, rProj)) {
|
|
932
|
+
return false;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
return true;
|
|
874
938
|
}
|
|
875
939
|
|
|
876
940
|
function meetsUntypedProduct<T>(
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
941
|
+
productOperations: ProductOperations<T>,
|
|
942
|
+
left: UntypedProductSet<T>,
|
|
943
|
+
right: UntypedProductSet<T>,
|
|
944
|
+
boundingBox: Box<T>,
|
|
881
945
|
): boolean {
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
946
|
+
if (left === empty || right === empty) {
|
|
947
|
+
return false;
|
|
948
|
+
}
|
|
949
|
+
if (left === dense || right === dense) {
|
|
950
|
+
return true;
|
|
951
|
+
}
|
|
952
|
+
if (!meetsSubspace(productOperations, left.bounds, right.bounds)) {
|
|
953
|
+
return false;
|
|
954
|
+
}
|
|
955
|
+
if (left.isSubspace && right.isSubspace) {
|
|
956
|
+
return true;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
const [leftBox, rightBox] = splitBox(productOperations, boundingBox);
|
|
960
|
+
const [ll, lr] = splitByBox(productOperations, left, leftBox, rightBox);
|
|
961
|
+
const [rl, rr] = splitByBox(productOperations, right, leftBox, rightBox);
|
|
962
|
+
|
|
963
|
+
return (
|
|
964
|
+
meetsUntypedProduct(productOperations, ll, rl, leftBox) ||
|
|
965
|
+
meetsUntypedProduct(productOperations, lr, rr, rightBox)
|
|
966
|
+
);
|
|
903
967
|
}
|
|
904
968
|
|
|
905
969
|
export function meetsProduct<T extends Compatible<U, T>, U extends Compatible<T, U>>(
|
|
906
|
-
|
|
907
|
-
|
|
970
|
+
left: ProductSet<T>,
|
|
971
|
+
right: ProductSet<U>,
|
|
908
972
|
) {
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
973
|
+
if (left === empty || right === empty) {
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
if (left === dense || right === dense) {
|
|
977
|
+
return true;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
const productOperations = { ...left.productOperations, ...right.productOperations };
|
|
981
|
+
return meetsUntypedProduct(productOperations, left.root, right.root, top(productOperations));
|
|
918
982
|
}
|
|
919
983
|
|
|
920
984
|
export const complementProduct = <T>(set: ProductSet<T>) => exceptProduct(dense, set);
|
|
921
985
|
|
|
922
986
|
export const symmetricDiffProduct = <T>(left: ProductSet<T>, right: ProductSet<T>) =>
|
|
923
|
-
|
|
987
|
+
unionProduct(exceptProduct(left, right), exceptProduct(right, left));
|
|
924
988
|
|
|
925
989
|
export function getSubspaces<T>(set: ProductSet<T>) {
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
990
|
+
if (set === empty || set === dense) {
|
|
991
|
+
return [];
|
|
992
|
+
}
|
|
993
|
+
const res: UntypedProduct<T>[] = [];
|
|
994
|
+
function loop(root: UntypedSparseProduct<T>) {
|
|
995
|
+
if (root.isSubspace) {
|
|
996
|
+
res.push(root.bounds);
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
loop(root.left);
|
|
1001
|
+
loop(root.right);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
loop(set.root);
|
|
1005
|
+
return res;
|
|
942
1006
|
}
|
|
943
1007
|
|
|
944
1008
|
export function forEachProduct<T, Props extends (keyof T)[]>(
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1009
|
+
set: ProductSet<T>,
|
|
1010
|
+
f: (product: Product<Restrict<T, Props>>) => boolean,
|
|
1011
|
+
...dims: Props
|
|
948
1012
|
): boolean {
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1013
|
+
const newSet = project(set, ...dims);
|
|
1014
|
+
if (newSet === empty) {
|
|
1015
|
+
return true;
|
|
1016
|
+
}
|
|
1017
|
+
if (newSet === dense) {
|
|
1018
|
+
return f(unsafe.denseProduct(dims));
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
const { productOperations, root } = newSet;
|
|
1022
|
+
|
|
1023
|
+
function loop(root_inner: UntypedSparseProduct<T>): boolean {
|
|
1024
|
+
if (root_inner.isSubspace) {
|
|
1025
|
+
return f(unsafe.fromUntypedProduct(productOperations, root_inner.bounds, dims));
|
|
1026
|
+
}
|
|
1027
|
+
return loop(root_inner.left) && loop(root_inner.right);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
return loop(root);
|
|
967
1031
|
}
|
|
968
1032
|
|
|
969
1033
|
export function getSubspaceCount<T>(set: ProductSet<T>) {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1034
|
+
if (set === empty || set === dense) {
|
|
1035
|
+
return 0;
|
|
1036
|
+
}
|
|
1037
|
+
return getUntypedSubspaceCount(set.root);
|
|
974
1038
|
}
|