@milaboratories/pl-model-common 1.19.5 → 1.19.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/drivers/pframe/data_types.d.ts +4 -4
- package/dist/drivers/pframe/data_types.d.ts.map +1 -1
- package/dist/drivers/pframe/index.d.ts +1 -0
- package/dist/drivers/pframe/index.d.ts.map +1 -1
- package/dist/drivers/pframe/linker_columns.d.ts +43 -0
- package/dist/drivers/pframe/linker_columns.d.ts.map +1 -0
- package/dist/drivers/pframe/spec/spec.d.ts +164 -12
- package/dist/drivers/pframe/spec/spec.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +990 -586
- package/dist/index.mjs.map +1 -1
- package/dist/json.d.ts +3 -3
- package/dist/json.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/drivers/pframe/data_types.ts +26 -29
- package/src/drivers/pframe/index.ts +2 -0
- package/src/drivers/pframe/linker_columns.test.ts +286 -0
- package/src/drivers/pframe/linker_columns.ts +290 -0
- package/src/drivers/pframe/spec/spec.test.ts +182 -0
- package/src/drivers/pframe/spec/spec.ts +404 -22
- package/src/json.ts +3 -3
package/dist/json.d.ts
CHANGED
|
@@ -3,14 +3,14 @@ type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
|
3
3
|
[key: string]: JsonValue;
|
|
4
4
|
};
|
|
5
5
|
type NotAssignableToJson = bigint | symbol | Function;
|
|
6
|
-
export type JsonCompatible<T> = unknown extends T ?
|
|
6
|
+
export type JsonCompatible<T> = unknown extends T ? unknown : {
|
|
7
7
|
[P in keyof T]: T[P] extends JsonValue ? T[P] : T[P] extends NotAssignableToJson ? never : JsonCompatible<T[P]>;
|
|
8
8
|
};
|
|
9
|
-
export type StringifiedJson<T> = JsonCompatible<T> extends never ? never : string & {
|
|
9
|
+
export type StringifiedJson<T = unknown> = JsonCompatible<T> extends never ? never : string & {
|
|
10
10
|
__json_stringified: T;
|
|
11
11
|
};
|
|
12
12
|
export declare function stringifyJson<T>(value: JsonCompatible<T>): StringifiedJson<T>;
|
|
13
|
-
export type CanonicalizedJson<T> = JsonCompatible<T> extends never ? never : string & {
|
|
13
|
+
export type CanonicalizedJson<T = unknown> = JsonCompatible<T> extends never ? never : string & {
|
|
14
14
|
__json_canonicalized: T;
|
|
15
15
|
};
|
|
16
16
|
export declare function canonicalizeJson<T>(value: JsonCompatible<T>): CanonicalizedJson<T>;
|
package/dist/json.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAEA,KAAK,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AAElE,KAAK,SAAS,GAAG,aAAa,GAAG,SAAS,EAAE,GAAG;IAC7C,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B,CAAC;AAGF,KAAK,mBAAmB,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEtD,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,OAAO,SAAS,CAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAEA,KAAK,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AAElE,KAAK,SAAS,GAAG,aAAa,GAAG,SAAS,EAAE,GAAG;IAC7C,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B,CAAC;AAGF,KAAK,mBAAmB,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEtD,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,OAAO,SAAS,CAAC,GAAG,OAAO,GAAG;KAC3D,CAAC,IAAI,MAAM,CAAC,GACb,CAAC,CAAC,CAAC,CAAC,SAAS,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,GAC3B,CAAC,CAAC,CAAC,CAAC,SAAS,mBAAmB,GAAG,KAAK,GACtC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,GAAG,OAAO,IAAI,cAAc,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG;IAC5F,kBAAkB,EAAE,CAAC,CAAC;CACvB,CAAC;AAEF,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAE7E;AAED,MAAM,MAAM,iBAAiB,CAAC,CAAC,GAAG,OAAO,IAAI,cAAc,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG;IAC9F,oBAAoB,EAAE,CAAC,CAAC;CACzB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAElF;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,CAEhF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pl-model-common",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.7",
|
|
4
4
|
"description": "Platforma SDK Model",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"typescript": "~5.6.3",
|
|
27
27
|
"vite": "^6.3.5",
|
|
28
28
|
"vitest": "^2.1.9",
|
|
29
|
-
"@
|
|
30
|
-
"@
|
|
29
|
+
"@milaboratories/build-configs": "1.0.5",
|
|
30
|
+
"@platforma-sdk/eslint-config": "1.0.3"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"type-check": "tsc --noEmit --composite false",
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { Branded } from '../../branding';
|
|
2
|
-
import {
|
|
3
|
-
type ValueType,
|
|
4
|
-
type ValueTypeBytes,
|
|
5
|
-
} from './spec/spec';
|
|
2
|
+
import { ValueType } from './spec/spec';
|
|
6
3
|
|
|
7
4
|
export type PVectorDataInt = Int32Array;
|
|
8
5
|
export type PVectorDataLong = BigInt64Array;
|
|
@@ -11,12 +8,12 @@ export type PVectorDataDouble = Float64Array;
|
|
|
11
8
|
export type PVectorDataString = (null | string)[];
|
|
12
9
|
export type PVectorDataBytes = (null | Uint8Array)[];
|
|
13
10
|
export type PVectorDataTyped<DataType extends ValueType> =
|
|
14
|
-
DataType extends
|
|
15
|
-
DataType extends
|
|
16
|
-
DataType extends
|
|
17
|
-
DataType extends
|
|
18
|
-
DataType extends
|
|
19
|
-
DataType extends
|
|
11
|
+
DataType extends typeof ValueType.Int ? PVectorDataInt :
|
|
12
|
+
DataType extends typeof ValueType.Long ? PVectorDataLong :
|
|
13
|
+
DataType extends typeof ValueType.Float ? PVectorDataFloat :
|
|
14
|
+
DataType extends typeof ValueType.Double ? PVectorDataDouble :
|
|
15
|
+
DataType extends typeof ValueType.String ? PVectorDataString :
|
|
16
|
+
DataType extends typeof ValueType.Bytes ? PVectorDataBytes :
|
|
20
17
|
never;
|
|
21
18
|
export type PVectorData = PVectorDataTyped<ValueType>;
|
|
22
19
|
|
|
@@ -62,17 +59,17 @@ function isValueNA(vector: PTableVector, row: number): boolean {
|
|
|
62
59
|
const valueType = vector.type;
|
|
63
60
|
const value = vector.data[row];
|
|
64
61
|
switch (valueType) {
|
|
65
|
-
case
|
|
62
|
+
case ValueType.Int:
|
|
66
63
|
return (value as PVectorDataInt[number]) === -2147483648;
|
|
67
|
-
case
|
|
64
|
+
case ValueType.Long:
|
|
68
65
|
return (value as PVectorDataLong[number]) === -9007199254740991n;
|
|
69
|
-
case
|
|
66
|
+
case ValueType.Float:
|
|
70
67
|
return Number.isNaN((value as PVectorDataFloat[number]));
|
|
71
|
-
case
|
|
68
|
+
case ValueType.Double:
|
|
72
69
|
return Number.isNaN((value as PVectorDataDouble[number]));
|
|
73
|
-
case
|
|
70
|
+
case ValueType.String:
|
|
74
71
|
return (value as PVectorDataString[number]) === null;
|
|
75
|
-
case
|
|
72
|
+
case ValueType.Bytes:
|
|
76
73
|
return (value as PVectorDataBytes[number]) === null;
|
|
77
74
|
default:
|
|
78
75
|
throw Error(`unsupported data type: ${valueType satisfies never}`);
|
|
@@ -95,7 +92,7 @@ export function isPTableNA(value: unknown): value is PTableNA {
|
|
|
95
92
|
return value === PTableNA;
|
|
96
93
|
}
|
|
97
94
|
|
|
98
|
-
export type ValueTypeSupported = Exclude<ValueType,
|
|
95
|
+
export type ValueTypeSupported = Exclude<ValueType, typeof ValueType.Bytes>;
|
|
99
96
|
|
|
100
97
|
export type PTableValueInt = number;
|
|
101
98
|
export type PTableValueLong = number;
|
|
@@ -103,11 +100,11 @@ export type PTableValueFloat = number;
|
|
|
103
100
|
export type PTableValueDouble = number;
|
|
104
101
|
export type PTableValueString = string;
|
|
105
102
|
export type PTableValueData<DataType extends ValueTypeSupported> =
|
|
106
|
-
DataType extends
|
|
107
|
-
DataType extends
|
|
108
|
-
DataType extends
|
|
109
|
-
DataType extends
|
|
110
|
-
DataType extends
|
|
103
|
+
DataType extends typeof ValueType.Int ? PTableValueInt :
|
|
104
|
+
DataType extends typeof ValueType.Long ? PTableValueLong :
|
|
105
|
+
DataType extends typeof ValueType.Float ? PTableValueFloat :
|
|
106
|
+
DataType extends typeof ValueType.Double ? PTableValueDouble :
|
|
107
|
+
DataType extends typeof ValueType.String ? PTableValueString :
|
|
111
108
|
never;
|
|
112
109
|
export type PTableValueDataBranded<DataType extends ValueTypeSupported> = Branded<PTableValueData<DataType>, DataType>;
|
|
113
110
|
export type PTableValue<
|
|
@@ -157,8 +154,8 @@ function pTableValueImpl<
|
|
|
157
154
|
dataType?: DataType;
|
|
158
155
|
},
|
|
159
156
|
) {
|
|
160
|
-
const valueType
|
|
161
|
-
if (valueType ===
|
|
157
|
+
const valueType = column.type;
|
|
158
|
+
if (valueType === ValueType.Bytes) {
|
|
162
159
|
throw Error('Bytes not yet supported');
|
|
163
160
|
}
|
|
164
161
|
|
|
@@ -176,15 +173,15 @@ function pTableValueImpl<
|
|
|
176
173
|
|
|
177
174
|
const value = column.data[row]!;
|
|
178
175
|
switch (valueType) {
|
|
179
|
-
case
|
|
176
|
+
case ValueType.Int:
|
|
180
177
|
return value as PVectorDataInt[number];
|
|
181
|
-
case
|
|
178
|
+
case ValueType.Long:
|
|
182
179
|
return Number(value as PVectorDataLong[number]);
|
|
183
|
-
case
|
|
180
|
+
case ValueType.Float:
|
|
184
181
|
return value as PVectorDataFloat[number];
|
|
185
|
-
case
|
|
182
|
+
case ValueType.Double:
|
|
186
183
|
return value as PVectorDataDouble[number];
|
|
187
|
-
case
|
|
184
|
+
case ValueType.String:
|
|
188
185
|
return (value as PVectorDataString[number])!;
|
|
189
186
|
}
|
|
190
187
|
}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Annotation,
|
|
3
|
+
AxisSpec,
|
|
4
|
+
AxisSpecNormalized,
|
|
5
|
+
getArrayFromAxisTree,
|
|
6
|
+
getAxesTree,
|
|
7
|
+
getNormalizedAxesList,
|
|
8
|
+
getSetFromAxisTree,
|
|
9
|
+
PColumnIdAndSpec,
|
|
10
|
+
ValueType,
|
|
11
|
+
} from './spec/index';
|
|
12
|
+
import { PObjectId } from '../../pool';
|
|
13
|
+
import { stringifyJson } from '../../json'
|
|
14
|
+
import {
|
|
15
|
+
describe,
|
|
16
|
+
expect,
|
|
17
|
+
test,
|
|
18
|
+
} from 'vitest';
|
|
19
|
+
import { LinkerMap } from './linker_columns';
|
|
20
|
+
|
|
21
|
+
function makeTestAxis(params: {
|
|
22
|
+
name: string;
|
|
23
|
+
parents?: AxisSpec[];
|
|
24
|
+
}): AxisSpec {
|
|
25
|
+
return {
|
|
26
|
+
type: ValueType.Int,
|
|
27
|
+
name: params.name,
|
|
28
|
+
annotations: {
|
|
29
|
+
[Annotation.Label]: `${params.name} axis`,
|
|
30
|
+
...(params.parents && params.parents.length > 0
|
|
31
|
+
? { [Annotation.Parents]: stringifyJson(params.parents) }
|
|
32
|
+
: {}
|
|
33
|
+
),
|
|
34
|
+
} satisfies Annotation,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function makeLinkerColumn(params: {
|
|
39
|
+
name: string;
|
|
40
|
+
from: AxisSpec[];
|
|
41
|
+
to: AxisSpec[];
|
|
42
|
+
}): PColumnIdAndSpec {
|
|
43
|
+
return {
|
|
44
|
+
columnId: params.name as PObjectId,
|
|
45
|
+
spec: {
|
|
46
|
+
kind: 'PColumn',
|
|
47
|
+
valueType: ValueType.String,
|
|
48
|
+
name: params.name,
|
|
49
|
+
axesSpec: [...params.from, ...params.to],
|
|
50
|
+
annotations: {
|
|
51
|
+
[Annotation.Label]: `${params.name} column`,
|
|
52
|
+
[Annotation.IsLinkerColumn]: stringifyJson(true),
|
|
53
|
+
} satisfies Annotation,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Returns all permutations of initial array */
|
|
59
|
+
function allPermutations<T>(arr: T[]): T[][] {
|
|
60
|
+
switch (arr.length) {
|
|
61
|
+
case 0: return [];
|
|
62
|
+
case 1: return [arr];
|
|
63
|
+
case 2: return [arr, [arr[1], arr[0]]];
|
|
64
|
+
default: return arr.reduce(
|
|
65
|
+
(acc, item, i) => acc.concat(
|
|
66
|
+
allPermutations<T>([...arr.slice(0, i), ...arr.slice(i + 1)])
|
|
67
|
+
.map(val => [item, ...val])
|
|
68
|
+
),
|
|
69
|
+
[] as T[][],
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
describe('Linker columns', () => {
|
|
75
|
+
test('Search in linker columns map', () => {
|
|
76
|
+
const [axis1, axis2, axis3, axis4, axis5] = getNormalizedAxesList([
|
|
77
|
+
makeTestAxis({ name: 'id1' }),
|
|
78
|
+
makeTestAxis({ name: 'id2' }),
|
|
79
|
+
makeTestAxis({ name: 'id3' }),
|
|
80
|
+
makeTestAxis({ name: 'id4' }),
|
|
81
|
+
makeTestAxis({ name: 'id5' })
|
|
82
|
+
]);
|
|
83
|
+
const linkerMap = LinkerMap.fromColumns([
|
|
84
|
+
makeLinkerColumn({ name: 'c12', from: [axis1], to: [axis2] }),
|
|
85
|
+
makeLinkerColumn({ name: 'c13', from: [axis1], to: [axis3] }),
|
|
86
|
+
makeLinkerColumn({ name: 'c45', from: [axis4], to: [axis5] }),
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
let testCase = (params: {
|
|
90
|
+
from: AxisSpecNormalized[];
|
|
91
|
+
to: AxisSpecNormalized[];
|
|
92
|
+
expected: string[];
|
|
93
|
+
}) => {
|
|
94
|
+
const linkers = linkerMap.getLinkerColumnsForAxes({
|
|
95
|
+
from: params.from,
|
|
96
|
+
to: params.to,
|
|
97
|
+
throwWhenNoLinkExists: false,
|
|
98
|
+
});
|
|
99
|
+
expect(linkers.map(item => item.spec.name).sort()).toEqual(params.expected);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
testCase({ from: [axis2], to: [axis3], expected: ['c12', 'c13'] });
|
|
103
|
+
testCase({ from: [axis1], to: [axis2], expected: ['c12'] });
|
|
104
|
+
testCase({ from: [axis1], to: [axis4], expected: []});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('Search in linker columns map with parents', () => {
|
|
108
|
+
const axisC = makeTestAxis({ name: 'c' });
|
|
109
|
+
const axisB = makeTestAxis({ name: 'b' });
|
|
110
|
+
const axisA = makeTestAxis({ name: 'a', parents: [axisB]});
|
|
111
|
+
|
|
112
|
+
const linkerMap = LinkerMap.fromColumns([
|
|
113
|
+
makeLinkerColumn({ name: 'abc', from: [axisA, axisB], to: [axisC] })
|
|
114
|
+
]);
|
|
115
|
+
|
|
116
|
+
let testCase = (params: {
|
|
117
|
+
from: AxisSpecNormalized[];
|
|
118
|
+
to: AxisSpecNormalized[];
|
|
119
|
+
expected: string[];
|
|
120
|
+
}) => {
|
|
121
|
+
const linkers = linkerMap.getLinkerColumnsForAxes({
|
|
122
|
+
from: params.from,
|
|
123
|
+
to: params.to,
|
|
124
|
+
throwWhenNoLinkExists: false,
|
|
125
|
+
});
|
|
126
|
+
expect(linkers.map(item => item.spec.name).sort()).toEqual(params.expected);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
testCase({ from: getNormalizedAxesList([axisA, axisB]), to: getNormalizedAxesList([axisC]), expected: ['abc'] });
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
test('Axis tree - without parents', () => {
|
|
133
|
+
const [axisA, axisB] = getNormalizedAxesList([
|
|
134
|
+
makeTestAxis({ name: 'a' }),
|
|
135
|
+
makeTestAxis({ name: 'b' })
|
|
136
|
+
]);
|
|
137
|
+
const tree = getAxesTree(axisA);
|
|
138
|
+
expect(getSetFromAxisTree(tree).size).toBe(1);
|
|
139
|
+
expect(getArrayFromAxisTree(tree).length).toBe(1);
|
|
140
|
+
|
|
141
|
+
expect(LinkerMap.getAxesGroups([axisA, axisB]).length).toBe(2);
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test('Axis tree - with parents', () => {
|
|
145
|
+
const axisD = makeTestAxis({ name: 'd' });
|
|
146
|
+
const axisC = makeTestAxis({ name: 'c', parents: [axisD] });
|
|
147
|
+
const axisB = makeTestAxis({ name: 'b', parents: [axisC] });
|
|
148
|
+
const axisA = makeTestAxis({ name: 'a', parents: [axisB] });
|
|
149
|
+
const [axisDn, axisCn, axisBn, axisAn] = getNormalizedAxesList([axisD, axisC, axisB, axisA])
|
|
150
|
+
|
|
151
|
+
const tree = getAxesTree(axisAn);
|
|
152
|
+
expect(getSetFromAxisTree(tree).size).toBe(4);
|
|
153
|
+
expect(getArrayFromAxisTree(tree).length).toBe(4);
|
|
154
|
+
|
|
155
|
+
for (const group of allPermutations([axisAn, axisBn, axisCn, axisDn])) {
|
|
156
|
+
expect(LinkerMap.getAxesGroups(group).length).toBe(1);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const axisD2 = makeTestAxis({ name: 'd' });
|
|
160
|
+
const axisC2 = makeTestAxis({ name: 'c', parents: [axisD2] });
|
|
161
|
+
const axisB2 = makeTestAxis({ name: 'b' });
|
|
162
|
+
const axisA2 = makeTestAxis({ name: 'a', parents: [axisB2] });
|
|
163
|
+
const normalized2 = getNormalizedAxesList([axisD2, axisC2, axisB2, axisA2])
|
|
164
|
+
|
|
165
|
+
for (const group of allPermutations(normalized2)) {
|
|
166
|
+
expect(LinkerMap.getAxesGroups(group).length).toBe(2);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const axisD3 = makeTestAxis({ name: 'd' });
|
|
170
|
+
const axisC3 = makeTestAxis({ name: 'c' });
|
|
171
|
+
const axisB3 = makeTestAxis({ name: 'b' });
|
|
172
|
+
const axisA3 = makeTestAxis({ name: 'a', parents: [axisB3] });
|
|
173
|
+
const normalized3 = getNormalizedAxesList([axisD3, axisC3, axisB3, axisA3])
|
|
174
|
+
|
|
175
|
+
for (const group of allPermutations(normalized3)) {
|
|
176
|
+
expect(LinkerMap.getAxesGroups(group).length).toBe(3);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const axisD4 = makeTestAxis({ name: 'd' });
|
|
180
|
+
const axisC4 = makeTestAxis({ name: 'c' });
|
|
181
|
+
const axisB4 = makeTestAxis({ name: 'b' });
|
|
182
|
+
const axisA4 = makeTestAxis({ name: 'a' });
|
|
183
|
+
const normalized4 = getNormalizedAxesList([axisD4, axisC4, axisB4, axisA4])
|
|
184
|
+
|
|
185
|
+
for (const group of allPermutations(normalized4)) {
|
|
186
|
+
expect(LinkerMap.getAxesGroups(group).length).toBe(4);
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
test('Generate partial trees', () => {
|
|
191
|
+
// Axes graph of parents (A, E - roots, C, B, D - parents) in some column:
|
|
192
|
+
// A - C
|
|
193
|
+
// \_ B _ D
|
|
194
|
+
// E/
|
|
195
|
+
//
|
|
196
|
+
// If the column is not a linker: trees to search linkers should be:
|
|
197
|
+
// 1 C
|
|
198
|
+
// 2 D
|
|
199
|
+
// 3 B - D
|
|
200
|
+
// 4 A - C
|
|
201
|
+
// \_ B - D
|
|
202
|
+
// 5 E - B - D
|
|
203
|
+
|
|
204
|
+
// If the axes are in a linker: trees must be in the linkers map:
|
|
205
|
+
|
|
206
|
+
// 1 A - C
|
|
207
|
+
// \_ B _ D
|
|
208
|
+
// 2 E - B - D
|
|
209
|
+
|
|
210
|
+
const axisD = makeTestAxis({ name: 'd' });
|
|
211
|
+
const axisC = makeTestAxis({ name: 'c' });
|
|
212
|
+
const axisB = makeTestAxis({ name: 'b', parents: [axisD] });
|
|
213
|
+
const axisA = makeTestAxis({ name: 'a', parents: [axisB, axisC] });
|
|
214
|
+
const axisE = makeTestAxis({ name: 'e', parents: [axisB, axisC] });
|
|
215
|
+
const axisF = makeTestAxis({ name: 'f' });
|
|
216
|
+
const axisH = makeTestAxis({ name: 'h' });
|
|
217
|
+
|
|
218
|
+
const group1 = [axisA, axisB, axisC, axisD, axisE];
|
|
219
|
+
const group2 = [axisF];
|
|
220
|
+
const group3 = [axisH];
|
|
221
|
+
const group1Normalized = getNormalizedAxesList(group1);
|
|
222
|
+
const group2Normalized = getNormalizedAxesList(group2);
|
|
223
|
+
const [axisAn, axisBn, axisCn, axisDn, axisEn] = group1Normalized;
|
|
224
|
+
|
|
225
|
+
const linker1 = makeLinkerColumn({ name: 'linker1', from: group1, to: group2 });
|
|
226
|
+
const linker2 = makeLinkerColumn({ name: 'linker2', from: group2, to: group3 });
|
|
227
|
+
|
|
228
|
+
const roots = LinkerMap.getAxesRoots(group1Normalized);
|
|
229
|
+
|
|
230
|
+
expect(roots).toEqual([axisAn, axisEn]);
|
|
231
|
+
|
|
232
|
+
const groups = LinkerMap.getAxesGroups([...group1Normalized, ...group2Normalized]);
|
|
233
|
+
expect(groups.length).toBe(2);
|
|
234
|
+
expect(groups[0]).toEqual(group1Normalized);
|
|
235
|
+
expect(groups[1]).toEqual(group2Normalized);
|
|
236
|
+
|
|
237
|
+
const linkersMap = LinkerMap.fromColumns([linker1, linker2]);
|
|
238
|
+
|
|
239
|
+
expect(
|
|
240
|
+
new Set(linkersMap.getReachableByLinkersAxesFromAxes(group2Normalized).map(a => a.name))
|
|
241
|
+
).toEqual(
|
|
242
|
+
new Set(([...group1, ...group3]).map(a => a.name))
|
|
243
|
+
);
|
|
244
|
+
expect(linkersMap.getReachableByLinkersAxesFromAxes([axisDn])).toEqual([]);
|
|
245
|
+
expect(linkersMap.getReachableByLinkersAxesFromAxes([axisBn])).toEqual([]);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test('Order of parents should not matter', () => {
|
|
249
|
+
const axisA = makeTestAxis({ name: 'a' });
|
|
250
|
+
const axisB = makeTestAxis({ name: 'b' });
|
|
251
|
+
const axisC1 = makeTestAxis({ name: 'c', parents: [axisA, axisB] });
|
|
252
|
+
const axisC2 = makeTestAxis({ name: 'c', parents: [axisB, axisA] });
|
|
253
|
+
const axisD = makeTestAxis({ name: 'd' });
|
|
254
|
+
|
|
255
|
+
const [a, b, c1, c2, d] = getNormalizedAxesList([axisA, axisB, axisC1, axisC2, axisD]);
|
|
256
|
+
const linkerMap = LinkerMap.fromColumns([
|
|
257
|
+
makeLinkerColumn({ name: 'linker1', from: [axisA, axisB, axisC1], to: [axisD] })
|
|
258
|
+
]);
|
|
259
|
+
|
|
260
|
+
expect(linkerMap.getReachableByLinkersAxesFromAxes([c2])).not.toHaveLength(0);
|
|
261
|
+
expect(linkerMap.getReachableByLinkersAxesFromAxes([c1])).not.toHaveLength(0);
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
test('Non-linkable axes', () => {
|
|
265
|
+
const axisA = makeTestAxis({ name: 'a' });
|
|
266
|
+
const axisB = makeTestAxis({ name: 'b' });
|
|
267
|
+
const axisC = makeTestAxis({ name: 'c', parents: [axisA, axisB] });
|
|
268
|
+
const axisD = makeTestAxis({ name: 'd' });
|
|
269
|
+
const axisE = makeTestAxis({ name: 'e' });
|
|
270
|
+
|
|
271
|
+
const axesList = getNormalizedAxesList([axisA, axisB, axisC, axisD, axisE]);
|
|
272
|
+
const linkerMap = LinkerMap.fromColumns([
|
|
273
|
+
makeLinkerColumn({ name: 'linker1', from: [axisA, axisB, axisC], to: [axisD] })
|
|
274
|
+
]);
|
|
275
|
+
|
|
276
|
+
expect(linkerMap.getNonLinkableAxes(
|
|
277
|
+
getNormalizedAxesList([axisA, axisB, axisC, axisD]),
|
|
278
|
+
getNormalizedAxesList([axisC, axisE])
|
|
279
|
+
).map(v => v.name)).toEqual(['e']);
|
|
280
|
+
|
|
281
|
+
expect(linkerMap.getNonLinkableAxes(
|
|
282
|
+
[],
|
|
283
|
+
getNormalizedAxesList([axisA, axisB, axisC, axisE])
|
|
284
|
+
).map(v => v.name)).toEqual(['a', 'b', 'c', 'e']);
|
|
285
|
+
})
|
|
286
|
+
});
|