@milaboratories/pl-model-common 1.33.0 → 1.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/drivers/pframe/linker_columns.cjs +1 -1
- package/dist/drivers/pframe/linker_columns.cjs.map +1 -1
- package/dist/drivers/pframe/linker_columns.js +1 -1
- package/dist/drivers/pframe/linker_columns.js.map +1 -1
- package/package.json +2 -2
- package/src/drivers/pframe/linker_columns.test.ts +17 -13
- package/src/drivers/pframe/linker_columns.ts +3 -3
|
@@ -35,7 +35,7 @@ var LinkerMap = class LinkerMap {
|
|
|
35
35
|
keyAxesSpec: spec,
|
|
36
36
|
linkWith: /* @__PURE__ */ new Map()
|
|
37
37
|
});
|
|
38
|
-
for (const [
|
|
38
|
+
for (const [keyRight] of rightKeyVariants) for (const [keyLeft] of leftKeyVariants) result.get(keyRight)?.linkWith.set(keyLeft, linker);
|
|
39
39
|
}
|
|
40
40
|
return new this(result);
|
|
41
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linker_columns.cjs","names":["parseJson","readAnnotationJson","Annotation","getNormalizedAxesList","getArrayFromAxisTree","getAxesTree","canonicalizeJson","getAxisId"],"sources":["../../../src/drivers/pframe/linker_columns.ts"],"sourcesContent":["import { canonicalizeJson, parseJson, type CanonicalizedJson } from \"../../json\";\nimport {\n Annotation,\n readAnnotationJson,\n type AxisSpec,\n type PColumnIdAndSpec,\n type AxisSpecNormalized,\n type AxisId,\n getAxisId,\n getNormalizedAxesList,\n getArrayFromAxisTree,\n getAxesTree,\n} from \"./spec/spec\";\n\ntype LinkerKey = CanonicalizedJson<AxisId[]>;\nexport type CompositeLinkerMap = Map<\n LinkerKey,\n {\n keyAxesSpec: AxisSpecNormalized[]; // axis specs - source for the key\n linkWith: Map<LinkerKey, PColumnIdAndSpec>; // for every axis (possibly in group with parents - available by linkers another axes and corresponding linkers)\n }\n>;\n\ninterface LinkersData {\n data: CompositeLinkerMap;\n}\nexport class LinkerMap implements LinkersData {\n /** Graph of linkers connected by axes (single or grouped by parents) */\n readonly data: CompositeLinkerMap;\n\n constructor(linkerMap: CompositeLinkerMap) {\n this.data = linkerMap;\n }\n\n get keys() {\n return this.data.keys();\n }\n\n get keyAxesIds() {\n return [...this.data.keys()].map(parseJson);\n }\n\n static fromColumns(columns: PColumnIdAndSpec[]) {\n const result: CompositeLinkerMap = new Map();\n for (const linker of columns.filter(\n (l) => !!readAnnotationJson(l.spec, Annotation.IsLinkerColumn),\n )) {\n const groups = LinkerMap.getAxesGroups(getNormalizedAxesList(linker.spec.axesSpec)); // split input axes into groups by parent links from annotation\n\n if (groups.length !== 2) {\n continue; // not a valid linker column\n }\n const [left, right] = groups;\n\n // In case of group:\n // A - C\n // \\_ B _ D\n // E/\n // put 2 variants as keys:\n // A - C\n // \\_ B _ D\n // and\n // E - B - D\n const leftKeyVariants: [LinkerKey, AxisSpecNormalized[]][] = LinkerMap.getAxesRoots(left).map(\n (axis) => {\n const axes = getArrayFromAxisTree(getAxesTree(axis));\n const key = canonicalizeJson(axes.map(getAxisId));\n return [key, axes];\n },\n );\n const rightKeyVariants: [LinkerKey, AxisSpecNormalized[]][] = LinkerMap.getAxesRoots(\n right,\n ).map((axis) => {\n const axes = getArrayFromAxisTree(getAxesTree(axis));\n const key = canonicalizeJson(axes.map(getAxisId));\n return [key, axes];\n });\n\n for (const [keyLeft, spec] of leftKeyVariants) {\n if (!result.has(keyLeft)) {\n result.set(keyLeft, { keyAxesSpec: spec, linkWith: new Map() });\n }\n }\n for (const [keyRight, spec] of rightKeyVariants) {\n if (!result.has(keyRight)) {\n result.set(keyRight, { keyAxesSpec: spec, linkWith: new Map() });\n }\n }\n for (const [keyLeft] of leftKeyVariants) {\n for (const [keyRight] of rightKeyVariants) {\n result.get(keyLeft)?.linkWith.set(keyRight, linker);\n }\n }\n }\n return new this(result);\n }\n\n /** Get all available nodes of linker graphs if start from sourceAxesKeys */\n searchAvailableAxesKeys(sourceAxesKeys: LinkerKey[]): Set<LinkerKey> {\n const startKeys = new Set(sourceAxesKeys);\n const allAvailableKeys = new Set<LinkerKey>();\n let nextKeys = sourceAxesKeys;\n while (nextKeys.length) {\n const next: LinkerKey[] = [];\n for (const key of nextKeys) {\n const node = this.data.get(key);\n if (!node) continue;\n for (const availableKey of node.linkWith.keys()) {\n if (!allAvailableKeys.has(availableKey) && !startKeys.has(availableKey)) {\n next.push(availableKey);\n allAvailableKeys.add(availableKey);\n }\n }\n }\n nextKeys = next;\n }\n return allAvailableKeys;\n }\n\n /** Get all linker columns that are necessary to reach endKey from startKey */\n searchLinkerPath(startKey: LinkerKey, endKey: LinkerKey): PColumnIdAndSpec[] {\n const previous: Record<LinkerKey, LinkerKey> = {};\n let nextIds = new Set([startKey]);\n const visited = new Set([startKey]);\n while (nextIds.size) {\n const next = new Set<LinkerKey>();\n for (const nextId of nextIds) {\n const node = this.data.get(nextId);\n if (!node) continue;\n for (const availableId of node.linkWith.keys()) {\n previous[availableId] = nextId;\n if (availableId === endKey) {\n const ids: LinkerKey[] = [];\n let current = endKey;\n while (previous[current] !== startKey) {\n ids.push(current);\n current = previous[current];\n }\n ids.push(current);\n // Edge (previous[id] -> id) is stored at the \"from\" node in one-directional map\n return ids.map((id: LinkerKey) => this.data.get(previous[id])!.linkWith.get(id)!);\n } else if (!visited.has(availableId)) {\n next.add(availableId);\n visited.add(availableId);\n }\n }\n }\n nextIds = next;\n }\n return [];\n }\n\n getLinkerColumnsForAxes({\n from: sourceAxes,\n to: targetAxes,\n throwWhenNoLinkExists = true,\n }: {\n from: AxisSpecNormalized[];\n to: AxisSpecNormalized[];\n throwWhenNoLinkExists?: boolean;\n }): PColumnIdAndSpec[] {\n // start keys - all possible keys in linker map using sourceAxes (for example, all axes of block's columns or all axes of columns in data-inputs)\n const startKeys: LinkerKey[] = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n\n return Array.from(\n new Map(\n LinkerMap.getAxesRoots(targetAxes)\n .map(LinkerMap.getLinkerKeyFromAxisSpec) // target keys contain all axes to be linked; if some of target axes has parents they must be in the key\n .flatMap((targetKey) => {\n const linkers = startKeys\n .map((startKey) => this.searchLinkerPath(startKey, targetKey))\n .reduce(\n (shortestPath, path) =>\n (shortestPath.length && shortestPath.length < path.length) || !path.length\n ? shortestPath\n : path,\n [] as PColumnIdAndSpec[],\n )\n .map((linker) => [linker.columnId, linker] as const);\n if (!linkers.length && throwWhenNoLinkExists) {\n throw Error(`Unable to find linker column for ${targetKey}`);\n }\n return linkers;\n }),\n ).values(),\n );\n }\n\n /** Get list of axisSpecs from keys of linker columns map */\n getAxesListFromKeysList(keys: LinkerKey[]): AxisSpecNormalized[] {\n return Array.from(\n new Map(\n keys\n .flatMap((key) => this.data.get(key)?.keyAxesSpec ?? [])\n .map((axis) => [canonicalizeJson(getAxisId(axis)), axis]),\n ).values(),\n );\n }\n\n /** Get axes of target axes that are impossible to be linked to source axes with current linker map */\n getNonLinkableAxes(\n sourceAxes: AxisSpecNormalized[],\n targetAxes: AxisSpecNormalized[],\n ): AxisSpecNormalized[] {\n const startKeys = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n // target keys contain all axes to be linked; if some of target axes has parents they must be in the key\n const targetKeys = targetAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n\n const axes = Array.from(\n new Map(\n targetAxes\n .filter((_targetAxis, idx) => {\n const targetKey = targetKeys[idx];\n return !startKeys.some((startKey) => this.searchLinkerPath(startKey, targetKey).length);\n })\n .flatMap((axis) =>\n getArrayFromAxisTree(getAxesTree(axis)).map((axis) => [\n canonicalizeJson(getAxisId(axis)),\n axis,\n ]),\n ),\n ).values(),\n );\n return axes;\n }\n\n /** Get all axes that can be connected to sourceAxes by linkers */\n getReachableByLinkersAxesFromAxesNormalized(\n sourceAxes: AxisSpecNormalized[],\n matchAxisIdFn?: (axisIdOfLinker: AxisId, axisIdOfSource: AxisId) => boolean,\n ): AxisSpecNormalized[] {\n let startKeys: CanonicalizedJson<AxisId[]>[] = [];\n\n if (matchAxisIdFn) {\n const sourceAxisIdsGrouped: AxisId[][] = sourceAxes.map((axis) =>\n getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId),\n );\n for (const sourceAxisIdsGroup of sourceAxisIdsGrouped) {\n const matched = this.keyAxesIds.find((keyIds: AxisId[]) =>\n keyIds.every((linkerKeyAxisId) =>\n sourceAxisIdsGroup.find((sourceAxisId) => matchAxisIdFn(linkerKeyAxisId, sourceAxisId)),\n ),\n );\n if (matched) {\n startKeys.push(canonicalizeJson(matched));\n }\n }\n } else {\n startKeys = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n }\n\n const availableKeys = this.searchAvailableAxesKeys(startKeys);\n return this.getAxesListFromKeysList([...availableKeys]);\n }\n\n getReachableByLinkersAxesFromAxes(\n sourceAxes: AxisSpec[],\n matchAxisIdFn?: (axisIdOfLinker: AxisId, axisIdOfSource: AxisId) => boolean,\n ): AxisSpecNormalized[] {\n return this.getReachableByLinkersAxesFromAxesNormalized(\n getNormalizedAxesList(sourceAxes),\n matchAxisIdFn,\n );\n }\n\n static getLinkerKeyFromAxisSpec(axis: AxisSpecNormalized): LinkerKey {\n return canonicalizeJson(getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId));\n }\n\n /** Split array of axes into several arrays by parents: axes of one group are parents for each other.\n There are no order inside every group. */\n static getAxesGroups(axesSpec: AxisSpecNormalized[]): AxisSpecNormalized[][] {\n switch (axesSpec.length) {\n case 0:\n return [];\n case 1:\n return [[axesSpec[0]]];\n default:\n break;\n }\n\n const axisKeys = axesSpec.map((spec) => canonicalizeJson(getAxisId(spec)));\n const axisParentsIdxs = axesSpec.map(\n (spec) =>\n new Set(\n spec.parentAxesSpec\n .map((spec) => canonicalizeJson(getAxisId(spec)))\n .map((el) => {\n const idx = axisKeys.indexOf(el);\n if (idx === -1) {\n throw new Error(\n `malformed axesSpec: ${JSON.stringify(axesSpec)}, unable to locate parent ${el}`,\n );\n }\n return idx;\n }),\n ),\n );\n\n const allIdxs = [...axesSpec.keys()];\n const groups: number[][] = []; // groups of axis indexes\n\n const usedIdxs = new Set<number>();\n let nextFreeEl = allIdxs.find((idx) => !usedIdxs.has(idx));\n while (nextFreeEl !== undefined) {\n const currentGroup = [nextFreeEl];\n usedIdxs.add(nextFreeEl);\n\n let nextElsOfCurrentGroup = [nextFreeEl];\n while (nextElsOfCurrentGroup.length) {\n const next = new Set<number>();\n for (const groupIdx of nextElsOfCurrentGroup) {\n const groupElementParents = axisParentsIdxs[groupIdx];\n allIdxs.forEach((idx) => {\n if (idx === groupIdx || usedIdxs.has(idx)) {\n return;\n }\n const parents = axisParentsIdxs[idx];\n if (parents.has(groupIdx) || groupElementParents.has(idx)) {\n currentGroup.push(idx);\n next.add(idx);\n usedIdxs.add(idx);\n }\n });\n }\n nextElsOfCurrentGroup = [...next];\n }\n\n groups.push([...currentGroup]);\n nextFreeEl = allIdxs.find((idx) => !usedIdxs.has(idx));\n }\n\n return groups.map((group) => group.map((idx) => axesSpec[idx]));\n }\n\n /** Get all axes that are not parents of any other axis */\n static getAxesRoots(axes: AxisSpecNormalized[]): AxisSpecNormalized[] {\n const parentsSet = new Set(\n axes.flatMap((axis) => axis.parentAxesSpec).map((spec) => canonicalizeJson(getAxisId(spec))),\n );\n return axes.filter((axis) => !parentsSet.has(canonicalizeJson(getAxisId(axis))));\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"linker_columns.cjs","names":["parseJson","readAnnotationJson","Annotation","getNormalizedAxesList","getArrayFromAxisTree","getAxesTree","canonicalizeJson","getAxisId"],"sources":["../../../src/drivers/pframe/linker_columns.ts"],"sourcesContent":["import { canonicalizeJson, parseJson, type CanonicalizedJson } from \"../../json\";\nimport {\n Annotation,\n readAnnotationJson,\n type AxisSpec,\n type PColumnIdAndSpec,\n type AxisSpecNormalized,\n type AxisId,\n getAxisId,\n getNormalizedAxesList,\n getArrayFromAxisTree,\n getAxesTree,\n} from \"./spec/spec\";\n\ntype LinkerKey = CanonicalizedJson<AxisId[]>;\nexport type CompositeLinkerMap = Map<\n LinkerKey,\n {\n keyAxesSpec: AxisSpecNormalized[]; // axis specs - source for the key\n linkWith: Map<LinkerKey, PColumnIdAndSpec>; // for every axis (possibly in group with parents - available by linkers another axes and corresponding linkers)\n }\n>;\n\ninterface LinkersData {\n data: CompositeLinkerMap;\n}\nexport class LinkerMap implements LinkersData {\n /** Graph of linkers connected by axes (single or grouped by parents) */\n readonly data: CompositeLinkerMap;\n\n constructor(linkerMap: CompositeLinkerMap) {\n this.data = linkerMap;\n }\n\n get keys() {\n return this.data.keys();\n }\n\n get keyAxesIds() {\n return [...this.data.keys()].map(parseJson);\n }\n\n static fromColumns(columns: PColumnIdAndSpec[]) {\n const result: CompositeLinkerMap = new Map();\n for (const linker of columns.filter(\n (l) => !!readAnnotationJson(l.spec, Annotation.IsLinkerColumn),\n )) {\n const groups = LinkerMap.getAxesGroups(getNormalizedAxesList(linker.spec.axesSpec)); // split input axes into groups by parent links from annotation\n\n if (groups.length !== 2) {\n continue; // not a valid linker column\n }\n const [left, right] = groups;\n\n // In case of group:\n // A - C\n // \\_ B _ D\n // E/\n // put 2 variants as keys:\n // A - C\n // \\_ B _ D\n // and\n // E - B - D\n const leftKeyVariants: [LinkerKey, AxisSpecNormalized[]][] = LinkerMap.getAxesRoots(left).map(\n (axis) => {\n const axes = getArrayFromAxisTree(getAxesTree(axis));\n const key = canonicalizeJson(axes.map(getAxisId));\n return [key, axes];\n },\n );\n const rightKeyVariants: [LinkerKey, AxisSpecNormalized[]][] = LinkerMap.getAxesRoots(\n right,\n ).map((axis) => {\n const axes = getArrayFromAxisTree(getAxesTree(axis));\n const key = canonicalizeJson(axes.map(getAxisId));\n return [key, axes];\n });\n\n for (const [keyLeft, spec] of leftKeyVariants) {\n if (!result.has(keyLeft)) {\n result.set(keyLeft, { keyAxesSpec: spec, linkWith: new Map() });\n }\n }\n for (const [keyRight, spec] of rightKeyVariants) {\n if (!result.has(keyRight)) {\n result.set(keyRight, { keyAxesSpec: spec, linkWith: new Map() });\n }\n }\n for (const [keyRight] of rightKeyVariants) {\n for (const [keyLeft] of leftKeyVariants) {\n result.get(keyRight)?.linkWith.set(keyLeft, linker);\n }\n }\n }\n return new this(result);\n }\n\n /** Get all available nodes of linker graphs if start from sourceAxesKeys */\n searchAvailableAxesKeys(sourceAxesKeys: LinkerKey[]): Set<LinkerKey> {\n const startKeys = new Set(sourceAxesKeys);\n const allAvailableKeys = new Set<LinkerKey>();\n let nextKeys = sourceAxesKeys;\n while (nextKeys.length) {\n const next: LinkerKey[] = [];\n for (const key of nextKeys) {\n const node = this.data.get(key);\n if (!node) continue;\n for (const availableKey of node.linkWith.keys()) {\n if (!allAvailableKeys.has(availableKey) && !startKeys.has(availableKey)) {\n next.push(availableKey);\n allAvailableKeys.add(availableKey);\n }\n }\n }\n nextKeys = next;\n }\n return allAvailableKeys;\n }\n\n /** Get all linker columns that are necessary to reach endKey from startKey */\n searchLinkerPath(startKey: LinkerKey, endKey: LinkerKey): PColumnIdAndSpec[] {\n const previous: Record<LinkerKey, LinkerKey> = {};\n let nextIds = new Set([startKey]);\n const visited = new Set([startKey]);\n while (nextIds.size) {\n const next = new Set<LinkerKey>();\n for (const nextId of nextIds) {\n const node = this.data.get(nextId);\n if (!node) continue;\n for (const availableId of node.linkWith.keys()) {\n previous[availableId] = nextId;\n if (availableId === endKey) {\n const ids: LinkerKey[] = [];\n let current = endKey;\n while (previous[current] !== startKey) {\n ids.push(current);\n current = previous[current];\n }\n ids.push(current);\n // Edge (previous[id] -> id) is stored at the \"from\" node in one-directional map\n return ids.map((id: LinkerKey) => this.data.get(previous[id])!.linkWith.get(id)!);\n } else if (!visited.has(availableId)) {\n next.add(availableId);\n visited.add(availableId);\n }\n }\n }\n nextIds = next;\n }\n return [];\n }\n\n getLinkerColumnsForAxes({\n from: sourceAxes,\n to: targetAxes,\n throwWhenNoLinkExists = true,\n }: {\n from: AxisSpecNormalized[];\n to: AxisSpecNormalized[];\n throwWhenNoLinkExists?: boolean;\n }): PColumnIdAndSpec[] {\n // start keys - all possible keys in linker map using sourceAxes (for example, all axes of block's columns or all axes of columns in data-inputs)\n const startKeys: LinkerKey[] = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n\n return Array.from(\n new Map(\n LinkerMap.getAxesRoots(targetAxes)\n .map(LinkerMap.getLinkerKeyFromAxisSpec) // target keys contain all axes to be linked; if some of target axes has parents they must be in the key\n .flatMap((targetKey) => {\n const linkers = startKeys\n .map((startKey) => this.searchLinkerPath(startKey, targetKey))\n .reduce(\n (shortestPath, path) =>\n (shortestPath.length && shortestPath.length < path.length) || !path.length\n ? shortestPath\n : path,\n [] as PColumnIdAndSpec[],\n )\n .map((linker) => [linker.columnId, linker] as const);\n if (!linkers.length && throwWhenNoLinkExists) {\n throw Error(`Unable to find linker column for ${targetKey}`);\n }\n return linkers;\n }),\n ).values(),\n );\n }\n\n /** Get list of axisSpecs from keys of linker columns map */\n getAxesListFromKeysList(keys: LinkerKey[]): AxisSpecNormalized[] {\n return Array.from(\n new Map(\n keys\n .flatMap((key) => this.data.get(key)?.keyAxesSpec ?? [])\n .map((axis) => [canonicalizeJson(getAxisId(axis)), axis]),\n ).values(),\n );\n }\n\n /** Get axes of target axes that are impossible to be linked to source axes with current linker map */\n getNonLinkableAxes(\n sourceAxes: AxisSpecNormalized[],\n targetAxes: AxisSpecNormalized[],\n ): AxisSpecNormalized[] {\n const startKeys = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n // target keys contain all axes to be linked; if some of target axes has parents they must be in the key\n const targetKeys = targetAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n\n const axes = Array.from(\n new Map(\n targetAxes\n .filter((_targetAxis, idx) => {\n const targetKey = targetKeys[idx];\n return !startKeys.some((startKey) => this.searchLinkerPath(startKey, targetKey).length);\n })\n .flatMap((axis) =>\n getArrayFromAxisTree(getAxesTree(axis)).map((axis) => [\n canonicalizeJson(getAxisId(axis)),\n axis,\n ]),\n ),\n ).values(),\n );\n return axes;\n }\n\n /** Get all axes that can be connected to sourceAxes by linkers */\n getReachableByLinkersAxesFromAxesNormalized(\n sourceAxes: AxisSpecNormalized[],\n matchAxisIdFn?: (axisIdOfLinker: AxisId, axisIdOfSource: AxisId) => boolean,\n ): AxisSpecNormalized[] {\n let startKeys: CanonicalizedJson<AxisId[]>[] = [];\n\n if (matchAxisIdFn) {\n const sourceAxisIdsGrouped: AxisId[][] = sourceAxes.map((axis) =>\n getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId),\n );\n for (const sourceAxisIdsGroup of sourceAxisIdsGrouped) {\n const matched = this.keyAxesIds.find((keyIds: AxisId[]) =>\n keyIds.every((linkerKeyAxisId) =>\n sourceAxisIdsGroup.find((sourceAxisId) => matchAxisIdFn(linkerKeyAxisId, sourceAxisId)),\n ),\n );\n if (matched) {\n startKeys.push(canonicalizeJson(matched));\n }\n }\n } else {\n startKeys = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n }\n\n const availableKeys = this.searchAvailableAxesKeys(startKeys);\n return this.getAxesListFromKeysList([...availableKeys]);\n }\n\n getReachableByLinkersAxesFromAxes(\n sourceAxes: AxisSpec[],\n matchAxisIdFn?: (axisIdOfLinker: AxisId, axisIdOfSource: AxisId) => boolean,\n ): AxisSpecNormalized[] {\n return this.getReachableByLinkersAxesFromAxesNormalized(\n getNormalizedAxesList(sourceAxes),\n matchAxisIdFn,\n );\n }\n\n static getLinkerKeyFromAxisSpec(axis: AxisSpecNormalized): LinkerKey {\n return canonicalizeJson(getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId));\n }\n\n /** Split array of axes into several arrays by parents: axes of one group are parents for each other.\n There are no order inside every group. */\n static getAxesGroups(axesSpec: AxisSpecNormalized[]): AxisSpecNormalized[][] {\n switch (axesSpec.length) {\n case 0:\n return [];\n case 1:\n return [[axesSpec[0]]];\n default:\n break;\n }\n\n const axisKeys = axesSpec.map((spec) => canonicalizeJson(getAxisId(spec)));\n const axisParentsIdxs = axesSpec.map(\n (spec) =>\n new Set(\n spec.parentAxesSpec\n .map((spec) => canonicalizeJson(getAxisId(spec)))\n .map((el) => {\n const idx = axisKeys.indexOf(el);\n if (idx === -1) {\n throw new Error(\n `malformed axesSpec: ${JSON.stringify(axesSpec)}, unable to locate parent ${el}`,\n );\n }\n return idx;\n }),\n ),\n );\n\n const allIdxs = [...axesSpec.keys()];\n const groups: number[][] = []; // groups of axis indexes\n\n const usedIdxs = new Set<number>();\n let nextFreeEl = allIdxs.find((idx) => !usedIdxs.has(idx));\n while (nextFreeEl !== undefined) {\n const currentGroup = [nextFreeEl];\n usedIdxs.add(nextFreeEl);\n\n let nextElsOfCurrentGroup = [nextFreeEl];\n while (nextElsOfCurrentGroup.length) {\n const next = new Set<number>();\n for (const groupIdx of nextElsOfCurrentGroup) {\n const groupElementParents = axisParentsIdxs[groupIdx];\n allIdxs.forEach((idx) => {\n if (idx === groupIdx || usedIdxs.has(idx)) {\n return;\n }\n const parents = axisParentsIdxs[idx];\n if (parents.has(groupIdx) || groupElementParents.has(idx)) {\n currentGroup.push(idx);\n next.add(idx);\n usedIdxs.add(idx);\n }\n });\n }\n nextElsOfCurrentGroup = [...next];\n }\n\n groups.push([...currentGroup]);\n nextFreeEl = allIdxs.find((idx) => !usedIdxs.has(idx));\n }\n\n return groups.map((group) => group.map((idx) => axesSpec[idx]));\n }\n\n /** Get all axes that are not parents of any other axis */\n static getAxesRoots(axes: AxisSpecNormalized[]): AxisSpecNormalized[] {\n const parentsSet = new Set(\n axes.flatMap((axis) => axis.parentAxesSpec).map((spec) => canonicalizeJson(getAxisId(spec))),\n );\n return axes.filter((axis) => !parentsSet.has(canonicalizeJson(getAxisId(axis))));\n }\n}\n"],"mappings":"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"}
|
|
@@ -35,7 +35,7 @@ var LinkerMap = class LinkerMap {
|
|
|
35
35
|
keyAxesSpec: spec,
|
|
36
36
|
linkWith: /* @__PURE__ */ new Map()
|
|
37
37
|
});
|
|
38
|
-
for (const [
|
|
38
|
+
for (const [keyRight] of rightKeyVariants) for (const [keyLeft] of leftKeyVariants) result.get(keyRight)?.linkWith.set(keyLeft, linker);
|
|
39
39
|
}
|
|
40
40
|
return new this(result);
|
|
41
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linker_columns.js","names":[],"sources":["../../../src/drivers/pframe/linker_columns.ts"],"sourcesContent":["import { canonicalizeJson, parseJson, type CanonicalizedJson } from \"../../json\";\nimport {\n Annotation,\n readAnnotationJson,\n type AxisSpec,\n type PColumnIdAndSpec,\n type AxisSpecNormalized,\n type AxisId,\n getAxisId,\n getNormalizedAxesList,\n getArrayFromAxisTree,\n getAxesTree,\n} from \"./spec/spec\";\n\ntype LinkerKey = CanonicalizedJson<AxisId[]>;\nexport type CompositeLinkerMap = Map<\n LinkerKey,\n {\n keyAxesSpec: AxisSpecNormalized[]; // axis specs - source for the key\n linkWith: Map<LinkerKey, PColumnIdAndSpec>; // for every axis (possibly in group with parents - available by linkers another axes and corresponding linkers)\n }\n>;\n\ninterface LinkersData {\n data: CompositeLinkerMap;\n}\nexport class LinkerMap implements LinkersData {\n /** Graph of linkers connected by axes (single or grouped by parents) */\n readonly data: CompositeLinkerMap;\n\n constructor(linkerMap: CompositeLinkerMap) {\n this.data = linkerMap;\n }\n\n get keys() {\n return this.data.keys();\n }\n\n get keyAxesIds() {\n return [...this.data.keys()].map(parseJson);\n }\n\n static fromColumns(columns: PColumnIdAndSpec[]) {\n const result: CompositeLinkerMap = new Map();\n for (const linker of columns.filter(\n (l) => !!readAnnotationJson(l.spec, Annotation.IsLinkerColumn),\n )) {\n const groups = LinkerMap.getAxesGroups(getNormalizedAxesList(linker.spec.axesSpec)); // split input axes into groups by parent links from annotation\n\n if (groups.length !== 2) {\n continue; // not a valid linker column\n }\n const [left, right] = groups;\n\n // In case of group:\n // A - C\n // \\_ B _ D\n // E/\n // put 2 variants as keys:\n // A - C\n // \\_ B _ D\n // and\n // E - B - D\n const leftKeyVariants: [LinkerKey, AxisSpecNormalized[]][] = LinkerMap.getAxesRoots(left).map(\n (axis) => {\n const axes = getArrayFromAxisTree(getAxesTree(axis));\n const key = canonicalizeJson(axes.map(getAxisId));\n return [key, axes];\n },\n );\n const rightKeyVariants: [LinkerKey, AxisSpecNormalized[]][] = LinkerMap.getAxesRoots(\n right,\n ).map((axis) => {\n const axes = getArrayFromAxisTree(getAxesTree(axis));\n const key = canonicalizeJson(axes.map(getAxisId));\n return [key, axes];\n });\n\n for (const [keyLeft, spec] of leftKeyVariants) {\n if (!result.has(keyLeft)) {\n result.set(keyLeft, { keyAxesSpec: spec, linkWith: new Map() });\n }\n }\n for (const [keyRight, spec] of rightKeyVariants) {\n if (!result.has(keyRight)) {\n result.set(keyRight, { keyAxesSpec: spec, linkWith: new Map() });\n }\n }\n for (const [keyLeft] of leftKeyVariants) {\n for (const [keyRight] of rightKeyVariants) {\n result.get(keyLeft)?.linkWith.set(keyRight, linker);\n }\n }\n }\n return new this(result);\n }\n\n /** Get all available nodes of linker graphs if start from sourceAxesKeys */\n searchAvailableAxesKeys(sourceAxesKeys: LinkerKey[]): Set<LinkerKey> {\n const startKeys = new Set(sourceAxesKeys);\n const allAvailableKeys = new Set<LinkerKey>();\n let nextKeys = sourceAxesKeys;\n while (nextKeys.length) {\n const next: LinkerKey[] = [];\n for (const key of nextKeys) {\n const node = this.data.get(key);\n if (!node) continue;\n for (const availableKey of node.linkWith.keys()) {\n if (!allAvailableKeys.has(availableKey) && !startKeys.has(availableKey)) {\n next.push(availableKey);\n allAvailableKeys.add(availableKey);\n }\n }\n }\n nextKeys = next;\n }\n return allAvailableKeys;\n }\n\n /** Get all linker columns that are necessary to reach endKey from startKey */\n searchLinkerPath(startKey: LinkerKey, endKey: LinkerKey): PColumnIdAndSpec[] {\n const previous: Record<LinkerKey, LinkerKey> = {};\n let nextIds = new Set([startKey]);\n const visited = new Set([startKey]);\n while (nextIds.size) {\n const next = new Set<LinkerKey>();\n for (const nextId of nextIds) {\n const node = this.data.get(nextId);\n if (!node) continue;\n for (const availableId of node.linkWith.keys()) {\n previous[availableId] = nextId;\n if (availableId === endKey) {\n const ids: LinkerKey[] = [];\n let current = endKey;\n while (previous[current] !== startKey) {\n ids.push(current);\n current = previous[current];\n }\n ids.push(current);\n // Edge (previous[id] -> id) is stored at the \"from\" node in one-directional map\n return ids.map((id: LinkerKey) => this.data.get(previous[id])!.linkWith.get(id)!);\n } else if (!visited.has(availableId)) {\n next.add(availableId);\n visited.add(availableId);\n }\n }\n }\n nextIds = next;\n }\n return [];\n }\n\n getLinkerColumnsForAxes({\n from: sourceAxes,\n to: targetAxes,\n throwWhenNoLinkExists = true,\n }: {\n from: AxisSpecNormalized[];\n to: AxisSpecNormalized[];\n throwWhenNoLinkExists?: boolean;\n }): PColumnIdAndSpec[] {\n // start keys - all possible keys in linker map using sourceAxes (for example, all axes of block's columns or all axes of columns in data-inputs)\n const startKeys: LinkerKey[] = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n\n return Array.from(\n new Map(\n LinkerMap.getAxesRoots(targetAxes)\n .map(LinkerMap.getLinkerKeyFromAxisSpec) // target keys contain all axes to be linked; if some of target axes has parents they must be in the key\n .flatMap((targetKey) => {\n const linkers = startKeys\n .map((startKey) => this.searchLinkerPath(startKey, targetKey))\n .reduce(\n (shortestPath, path) =>\n (shortestPath.length && shortestPath.length < path.length) || !path.length\n ? shortestPath\n : path,\n [] as PColumnIdAndSpec[],\n )\n .map((linker) => [linker.columnId, linker] as const);\n if (!linkers.length && throwWhenNoLinkExists) {\n throw Error(`Unable to find linker column for ${targetKey}`);\n }\n return linkers;\n }),\n ).values(),\n );\n }\n\n /** Get list of axisSpecs from keys of linker columns map */\n getAxesListFromKeysList(keys: LinkerKey[]): AxisSpecNormalized[] {\n return Array.from(\n new Map(\n keys\n .flatMap((key) => this.data.get(key)?.keyAxesSpec ?? [])\n .map((axis) => [canonicalizeJson(getAxisId(axis)), axis]),\n ).values(),\n );\n }\n\n /** Get axes of target axes that are impossible to be linked to source axes with current linker map */\n getNonLinkableAxes(\n sourceAxes: AxisSpecNormalized[],\n targetAxes: AxisSpecNormalized[],\n ): AxisSpecNormalized[] {\n const startKeys = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n // target keys contain all axes to be linked; if some of target axes has parents they must be in the key\n const targetKeys = targetAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n\n const axes = Array.from(\n new Map(\n targetAxes\n .filter((_targetAxis, idx) => {\n const targetKey = targetKeys[idx];\n return !startKeys.some((startKey) => this.searchLinkerPath(startKey, targetKey).length);\n })\n .flatMap((axis) =>\n getArrayFromAxisTree(getAxesTree(axis)).map((axis) => [\n canonicalizeJson(getAxisId(axis)),\n axis,\n ]),\n ),\n ).values(),\n );\n return axes;\n }\n\n /** Get all axes that can be connected to sourceAxes by linkers */\n getReachableByLinkersAxesFromAxesNormalized(\n sourceAxes: AxisSpecNormalized[],\n matchAxisIdFn?: (axisIdOfLinker: AxisId, axisIdOfSource: AxisId) => boolean,\n ): AxisSpecNormalized[] {\n let startKeys: CanonicalizedJson<AxisId[]>[] = [];\n\n if (matchAxisIdFn) {\n const sourceAxisIdsGrouped: AxisId[][] = sourceAxes.map((axis) =>\n getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId),\n );\n for (const sourceAxisIdsGroup of sourceAxisIdsGrouped) {\n const matched = this.keyAxesIds.find((keyIds: AxisId[]) =>\n keyIds.every((linkerKeyAxisId) =>\n sourceAxisIdsGroup.find((sourceAxisId) => matchAxisIdFn(linkerKeyAxisId, sourceAxisId)),\n ),\n );\n if (matched) {\n startKeys.push(canonicalizeJson(matched));\n }\n }\n } else {\n startKeys = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n }\n\n const availableKeys = this.searchAvailableAxesKeys(startKeys);\n return this.getAxesListFromKeysList([...availableKeys]);\n }\n\n getReachableByLinkersAxesFromAxes(\n sourceAxes: AxisSpec[],\n matchAxisIdFn?: (axisIdOfLinker: AxisId, axisIdOfSource: AxisId) => boolean,\n ): AxisSpecNormalized[] {\n return this.getReachableByLinkersAxesFromAxesNormalized(\n getNormalizedAxesList(sourceAxes),\n matchAxisIdFn,\n );\n }\n\n static getLinkerKeyFromAxisSpec(axis: AxisSpecNormalized): LinkerKey {\n return canonicalizeJson(getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId));\n }\n\n /** Split array of axes into several arrays by parents: axes of one group are parents for each other.\n There are no order inside every group. */\n static getAxesGroups(axesSpec: AxisSpecNormalized[]): AxisSpecNormalized[][] {\n switch (axesSpec.length) {\n case 0:\n return [];\n case 1:\n return [[axesSpec[0]]];\n default:\n break;\n }\n\n const axisKeys = axesSpec.map((spec) => canonicalizeJson(getAxisId(spec)));\n const axisParentsIdxs = axesSpec.map(\n (spec) =>\n new Set(\n spec.parentAxesSpec\n .map((spec) => canonicalizeJson(getAxisId(spec)))\n .map((el) => {\n const idx = axisKeys.indexOf(el);\n if (idx === -1) {\n throw new Error(\n `malformed axesSpec: ${JSON.stringify(axesSpec)}, unable to locate parent ${el}`,\n );\n }\n return idx;\n }),\n ),\n );\n\n const allIdxs = [...axesSpec.keys()];\n const groups: number[][] = []; // groups of axis indexes\n\n const usedIdxs = new Set<number>();\n let nextFreeEl = allIdxs.find((idx) => !usedIdxs.has(idx));\n while (nextFreeEl !== undefined) {\n const currentGroup = [nextFreeEl];\n usedIdxs.add(nextFreeEl);\n\n let nextElsOfCurrentGroup = [nextFreeEl];\n while (nextElsOfCurrentGroup.length) {\n const next = new Set<number>();\n for (const groupIdx of nextElsOfCurrentGroup) {\n const groupElementParents = axisParentsIdxs[groupIdx];\n allIdxs.forEach((idx) => {\n if (idx === groupIdx || usedIdxs.has(idx)) {\n return;\n }\n const parents = axisParentsIdxs[idx];\n if (parents.has(groupIdx) || groupElementParents.has(idx)) {\n currentGroup.push(idx);\n next.add(idx);\n usedIdxs.add(idx);\n }\n });\n }\n nextElsOfCurrentGroup = [...next];\n }\n\n groups.push([...currentGroup]);\n nextFreeEl = allIdxs.find((idx) => !usedIdxs.has(idx));\n }\n\n return groups.map((group) => group.map((idx) => axesSpec[idx]));\n }\n\n /** Get all axes that are not parents of any other axis */\n static getAxesRoots(axes: AxisSpecNormalized[]): AxisSpecNormalized[] {\n const parentsSet = new Set(\n axes.flatMap((axis) => axis.parentAxesSpec).map((spec) => canonicalizeJson(getAxisId(spec))),\n );\n return axes.filter((axis) => !parentsSet.has(canonicalizeJson(getAxisId(axis))));\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"linker_columns.js","names":[],"sources":["../../../src/drivers/pframe/linker_columns.ts"],"sourcesContent":["import { canonicalizeJson, parseJson, type CanonicalizedJson } from \"../../json\";\nimport {\n Annotation,\n readAnnotationJson,\n type AxisSpec,\n type PColumnIdAndSpec,\n type AxisSpecNormalized,\n type AxisId,\n getAxisId,\n getNormalizedAxesList,\n getArrayFromAxisTree,\n getAxesTree,\n} from \"./spec/spec\";\n\ntype LinkerKey = CanonicalizedJson<AxisId[]>;\nexport type CompositeLinkerMap = Map<\n LinkerKey,\n {\n keyAxesSpec: AxisSpecNormalized[]; // axis specs - source for the key\n linkWith: Map<LinkerKey, PColumnIdAndSpec>; // for every axis (possibly in group with parents - available by linkers another axes and corresponding linkers)\n }\n>;\n\ninterface LinkersData {\n data: CompositeLinkerMap;\n}\nexport class LinkerMap implements LinkersData {\n /** Graph of linkers connected by axes (single or grouped by parents) */\n readonly data: CompositeLinkerMap;\n\n constructor(linkerMap: CompositeLinkerMap) {\n this.data = linkerMap;\n }\n\n get keys() {\n return this.data.keys();\n }\n\n get keyAxesIds() {\n return [...this.data.keys()].map(parseJson);\n }\n\n static fromColumns(columns: PColumnIdAndSpec[]) {\n const result: CompositeLinkerMap = new Map();\n for (const linker of columns.filter(\n (l) => !!readAnnotationJson(l.spec, Annotation.IsLinkerColumn),\n )) {\n const groups = LinkerMap.getAxesGroups(getNormalizedAxesList(linker.spec.axesSpec)); // split input axes into groups by parent links from annotation\n\n if (groups.length !== 2) {\n continue; // not a valid linker column\n }\n const [left, right] = groups;\n\n // In case of group:\n // A - C\n // \\_ B _ D\n // E/\n // put 2 variants as keys:\n // A - C\n // \\_ B _ D\n // and\n // E - B - D\n const leftKeyVariants: [LinkerKey, AxisSpecNormalized[]][] = LinkerMap.getAxesRoots(left).map(\n (axis) => {\n const axes = getArrayFromAxisTree(getAxesTree(axis));\n const key = canonicalizeJson(axes.map(getAxisId));\n return [key, axes];\n },\n );\n const rightKeyVariants: [LinkerKey, AxisSpecNormalized[]][] = LinkerMap.getAxesRoots(\n right,\n ).map((axis) => {\n const axes = getArrayFromAxisTree(getAxesTree(axis));\n const key = canonicalizeJson(axes.map(getAxisId));\n return [key, axes];\n });\n\n for (const [keyLeft, spec] of leftKeyVariants) {\n if (!result.has(keyLeft)) {\n result.set(keyLeft, { keyAxesSpec: spec, linkWith: new Map() });\n }\n }\n for (const [keyRight, spec] of rightKeyVariants) {\n if (!result.has(keyRight)) {\n result.set(keyRight, { keyAxesSpec: spec, linkWith: new Map() });\n }\n }\n for (const [keyRight] of rightKeyVariants) {\n for (const [keyLeft] of leftKeyVariants) {\n result.get(keyRight)?.linkWith.set(keyLeft, linker);\n }\n }\n }\n return new this(result);\n }\n\n /** Get all available nodes of linker graphs if start from sourceAxesKeys */\n searchAvailableAxesKeys(sourceAxesKeys: LinkerKey[]): Set<LinkerKey> {\n const startKeys = new Set(sourceAxesKeys);\n const allAvailableKeys = new Set<LinkerKey>();\n let nextKeys = sourceAxesKeys;\n while (nextKeys.length) {\n const next: LinkerKey[] = [];\n for (const key of nextKeys) {\n const node = this.data.get(key);\n if (!node) continue;\n for (const availableKey of node.linkWith.keys()) {\n if (!allAvailableKeys.has(availableKey) && !startKeys.has(availableKey)) {\n next.push(availableKey);\n allAvailableKeys.add(availableKey);\n }\n }\n }\n nextKeys = next;\n }\n return allAvailableKeys;\n }\n\n /** Get all linker columns that are necessary to reach endKey from startKey */\n searchLinkerPath(startKey: LinkerKey, endKey: LinkerKey): PColumnIdAndSpec[] {\n const previous: Record<LinkerKey, LinkerKey> = {};\n let nextIds = new Set([startKey]);\n const visited = new Set([startKey]);\n while (nextIds.size) {\n const next = new Set<LinkerKey>();\n for (const nextId of nextIds) {\n const node = this.data.get(nextId);\n if (!node) continue;\n for (const availableId of node.linkWith.keys()) {\n previous[availableId] = nextId;\n if (availableId === endKey) {\n const ids: LinkerKey[] = [];\n let current = endKey;\n while (previous[current] !== startKey) {\n ids.push(current);\n current = previous[current];\n }\n ids.push(current);\n // Edge (previous[id] -> id) is stored at the \"from\" node in one-directional map\n return ids.map((id: LinkerKey) => this.data.get(previous[id])!.linkWith.get(id)!);\n } else if (!visited.has(availableId)) {\n next.add(availableId);\n visited.add(availableId);\n }\n }\n }\n nextIds = next;\n }\n return [];\n }\n\n getLinkerColumnsForAxes({\n from: sourceAxes,\n to: targetAxes,\n throwWhenNoLinkExists = true,\n }: {\n from: AxisSpecNormalized[];\n to: AxisSpecNormalized[];\n throwWhenNoLinkExists?: boolean;\n }): PColumnIdAndSpec[] {\n // start keys - all possible keys in linker map using sourceAxes (for example, all axes of block's columns or all axes of columns in data-inputs)\n const startKeys: LinkerKey[] = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n\n return Array.from(\n new Map(\n LinkerMap.getAxesRoots(targetAxes)\n .map(LinkerMap.getLinkerKeyFromAxisSpec) // target keys contain all axes to be linked; if some of target axes has parents they must be in the key\n .flatMap((targetKey) => {\n const linkers = startKeys\n .map((startKey) => this.searchLinkerPath(startKey, targetKey))\n .reduce(\n (shortestPath, path) =>\n (shortestPath.length && shortestPath.length < path.length) || !path.length\n ? shortestPath\n : path,\n [] as PColumnIdAndSpec[],\n )\n .map((linker) => [linker.columnId, linker] as const);\n if (!linkers.length && throwWhenNoLinkExists) {\n throw Error(`Unable to find linker column for ${targetKey}`);\n }\n return linkers;\n }),\n ).values(),\n );\n }\n\n /** Get list of axisSpecs from keys of linker columns map */\n getAxesListFromKeysList(keys: LinkerKey[]): AxisSpecNormalized[] {\n return Array.from(\n new Map(\n keys\n .flatMap((key) => this.data.get(key)?.keyAxesSpec ?? [])\n .map((axis) => [canonicalizeJson(getAxisId(axis)), axis]),\n ).values(),\n );\n }\n\n /** Get axes of target axes that are impossible to be linked to source axes with current linker map */\n getNonLinkableAxes(\n sourceAxes: AxisSpecNormalized[],\n targetAxes: AxisSpecNormalized[],\n ): AxisSpecNormalized[] {\n const startKeys = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n // target keys contain all axes to be linked; if some of target axes has parents they must be in the key\n const targetKeys = targetAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n\n const axes = Array.from(\n new Map(\n targetAxes\n .filter((_targetAxis, idx) => {\n const targetKey = targetKeys[idx];\n return !startKeys.some((startKey) => this.searchLinkerPath(startKey, targetKey).length);\n })\n .flatMap((axis) =>\n getArrayFromAxisTree(getAxesTree(axis)).map((axis) => [\n canonicalizeJson(getAxisId(axis)),\n axis,\n ]),\n ),\n ).values(),\n );\n return axes;\n }\n\n /** Get all axes that can be connected to sourceAxes by linkers */\n getReachableByLinkersAxesFromAxesNormalized(\n sourceAxes: AxisSpecNormalized[],\n matchAxisIdFn?: (axisIdOfLinker: AxisId, axisIdOfSource: AxisId) => boolean,\n ): AxisSpecNormalized[] {\n let startKeys: CanonicalizedJson<AxisId[]>[] = [];\n\n if (matchAxisIdFn) {\n const sourceAxisIdsGrouped: AxisId[][] = sourceAxes.map((axis) =>\n getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId),\n );\n for (const sourceAxisIdsGroup of sourceAxisIdsGrouped) {\n const matched = this.keyAxesIds.find((keyIds: AxisId[]) =>\n keyIds.every((linkerKeyAxisId) =>\n sourceAxisIdsGroup.find((sourceAxisId) => matchAxisIdFn(linkerKeyAxisId, sourceAxisId)),\n ),\n );\n if (matched) {\n startKeys.push(canonicalizeJson(matched));\n }\n }\n } else {\n startKeys = sourceAxes.map(LinkerMap.getLinkerKeyFromAxisSpec);\n }\n\n const availableKeys = this.searchAvailableAxesKeys(startKeys);\n return this.getAxesListFromKeysList([...availableKeys]);\n }\n\n getReachableByLinkersAxesFromAxes(\n sourceAxes: AxisSpec[],\n matchAxisIdFn?: (axisIdOfLinker: AxisId, axisIdOfSource: AxisId) => boolean,\n ): AxisSpecNormalized[] {\n return this.getReachableByLinkersAxesFromAxesNormalized(\n getNormalizedAxesList(sourceAxes),\n matchAxisIdFn,\n );\n }\n\n static getLinkerKeyFromAxisSpec(axis: AxisSpecNormalized): LinkerKey {\n return canonicalizeJson(getArrayFromAxisTree(getAxesTree(axis)).map(getAxisId));\n }\n\n /** Split array of axes into several arrays by parents: axes of one group are parents for each other.\n There are no order inside every group. */\n static getAxesGroups(axesSpec: AxisSpecNormalized[]): AxisSpecNormalized[][] {\n switch (axesSpec.length) {\n case 0:\n return [];\n case 1:\n return [[axesSpec[0]]];\n default:\n break;\n }\n\n const axisKeys = axesSpec.map((spec) => canonicalizeJson(getAxisId(spec)));\n const axisParentsIdxs = axesSpec.map(\n (spec) =>\n new Set(\n spec.parentAxesSpec\n .map((spec) => canonicalizeJson(getAxisId(spec)))\n .map((el) => {\n const idx = axisKeys.indexOf(el);\n if (idx === -1) {\n throw new Error(\n `malformed axesSpec: ${JSON.stringify(axesSpec)}, unable to locate parent ${el}`,\n );\n }\n return idx;\n }),\n ),\n );\n\n const allIdxs = [...axesSpec.keys()];\n const groups: number[][] = []; // groups of axis indexes\n\n const usedIdxs = new Set<number>();\n let nextFreeEl = allIdxs.find((idx) => !usedIdxs.has(idx));\n while (nextFreeEl !== undefined) {\n const currentGroup = [nextFreeEl];\n usedIdxs.add(nextFreeEl);\n\n let nextElsOfCurrentGroup = [nextFreeEl];\n while (nextElsOfCurrentGroup.length) {\n const next = new Set<number>();\n for (const groupIdx of nextElsOfCurrentGroup) {\n const groupElementParents = axisParentsIdxs[groupIdx];\n allIdxs.forEach((idx) => {\n if (idx === groupIdx || usedIdxs.has(idx)) {\n return;\n }\n const parents = axisParentsIdxs[idx];\n if (parents.has(groupIdx) || groupElementParents.has(idx)) {\n currentGroup.push(idx);\n next.add(idx);\n usedIdxs.add(idx);\n }\n });\n }\n nextElsOfCurrentGroup = [...next];\n }\n\n groups.push([...currentGroup]);\n nextFreeEl = allIdxs.find((idx) => !usedIdxs.has(idx));\n }\n\n return groups.map((group) => group.map((idx) => axesSpec[idx]));\n }\n\n /** Get all axes that are not parents of any other axis */\n static getAxesRoots(axes: AxisSpecNormalized[]): AxisSpecNormalized[] {\n const parentsSet = new Set(\n axes.flatMap((axis) => axis.parentAxesSpec).map((spec) => canonicalizeJson(getAxisId(spec))),\n );\n return axes.filter((axis) => !parentsSet.has(canonicalizeJson(getAxisId(axis))));\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pl-model-common",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.34.0",
|
|
4
4
|
"description": "Platforma SDK Model",
|
|
5
5
|
"files": [
|
|
6
6
|
"./dist/**/*",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"@vitest/coverage-istanbul": "^4.1.3",
|
|
27
27
|
"typescript": "~5.9.3",
|
|
28
28
|
"vitest": "^4.1.3",
|
|
29
|
-
"@milaboratories/build-configs": "2.0.0",
|
|
30
29
|
"@milaboratories/ts-configs": "1.2.3",
|
|
30
|
+
"@milaboratories/build-configs": "2.0.0",
|
|
31
31
|
"@milaboratories/ts-builder": "1.3.2"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
@@ -99,7 +99,7 @@ describe("Linker columns", () => {
|
|
|
99
99
|
};
|
|
100
100
|
|
|
101
101
|
testCase({ from: [axis2], to: [axis3], expected: [] });
|
|
102
|
-
testCase({ from: [
|
|
102
|
+
testCase({ from: [axis2], to: [axis1], expected: ["c12"] });
|
|
103
103
|
testCase({ from: [axis1], to: [axis4], expected: [] });
|
|
104
104
|
});
|
|
105
105
|
|
|
@@ -126,8 +126,8 @@ describe("Linker columns", () => {
|
|
|
126
126
|
};
|
|
127
127
|
|
|
128
128
|
testCase({
|
|
129
|
-
from: getNormalizedAxesList([
|
|
130
|
-
to: getNormalizedAxesList([
|
|
129
|
+
from: getNormalizedAxesList([axisC]),
|
|
130
|
+
to: getNormalizedAxesList([axisA, axisB]),
|
|
131
131
|
expected: ["abc"],
|
|
132
132
|
});
|
|
133
133
|
});
|
|
@@ -239,13 +239,13 @@ describe("Linker columns", () => {
|
|
|
239
239
|
|
|
240
240
|
const linkersMap = LinkerMap.fromColumns([linker1, linker2]);
|
|
241
241
|
|
|
242
|
-
//
|
|
242
|
+
// Reversed edges: from group2 we reach group1 (no forward edge to group3)
|
|
243
243
|
expect(
|
|
244
244
|
new Set(
|
|
245
245
|
linkersMap.getReachableByLinkersAxesFromAxesNormalized(group2Normalized).map((a) => a.name),
|
|
246
246
|
),
|
|
247
|
-
).toEqual(new Set(
|
|
248
|
-
// Non-root axes (axisDn, axisBn) don't match linker map keys, so no
|
|
247
|
+
).toEqual(new Set(group1.map((a) => a.name)));
|
|
248
|
+
// Non-root axes (axisDn, axisBn) don't match linker map keys, so no reachability
|
|
249
249
|
expect(linkersMap.getReachableByLinkersAxesFromAxesNormalized([axisDn])).toEqual([]);
|
|
250
250
|
expect(linkersMap.getReachableByLinkersAxesFromAxesNormalized([axisBn])).toEqual([]);
|
|
251
251
|
});
|
|
@@ -257,13 +257,17 @@ describe("Linker columns", () => {
|
|
|
257
257
|
const axisC2 = makeTestAxis({ name: "c", parents: [axisB, axisA] });
|
|
258
258
|
const axisD = makeTestAxis({ name: "d" });
|
|
259
259
|
|
|
260
|
-
const [, , c1, c2] = getNormalizedAxesList([axisA, axisB, axisC1, axisC2, axisD]);
|
|
260
|
+
const [, , c1, c2, dn] = getNormalizedAxesList([axisA, axisB, axisC1, axisC2, axisD]);
|
|
261
261
|
const linkerMap = LinkerMap.fromColumns([
|
|
262
262
|
makeLinkerColumn({ name: "linker1", from: [axisA, axisB, axisC1], to: [axisD] }),
|
|
263
263
|
]);
|
|
264
264
|
|
|
265
|
-
expect(
|
|
266
|
-
|
|
265
|
+
expect(
|
|
266
|
+
linkerMap.getLinkerColumnsForAxes({ from: [dn], to: [c2], throwWhenNoLinkExists: false }),
|
|
267
|
+
).not.toHaveLength(0);
|
|
268
|
+
expect(
|
|
269
|
+
linkerMap.getLinkerColumnsForAxes({ from: [dn], to: [c1], throwWhenNoLinkExists: false }),
|
|
270
|
+
).not.toHaveLength(0);
|
|
267
271
|
});
|
|
268
272
|
|
|
269
273
|
test("Non-linkable axes", () => {
|
|
@@ -284,7 +288,7 @@ describe("Linker columns", () => {
|
|
|
284
288
|
getNormalizedAxesList([axisA, axisB, axisC, axisE]),
|
|
285
289
|
)
|
|
286
290
|
.map((v) => v.name),
|
|
287
|
-
).toEqual(["a", "b", "
|
|
291
|
+
).toEqual(["a", "b", "e"]);
|
|
288
292
|
|
|
289
293
|
expect(
|
|
290
294
|
linkerMap
|
|
@@ -304,9 +308,9 @@ describe("Linker columns", () => {
|
|
|
304
308
|
makeLinkerColumn({ name: "linker3", from: [axisC], to: [axisD] }),
|
|
305
309
|
]);
|
|
306
310
|
|
|
307
|
-
expect(linkerMap.getReachableByLinkersAxesFromAxes([
|
|
308
|
-
getNormalizedAxesList([
|
|
311
|
+
expect(linkerMap.getReachableByLinkersAxesFromAxes([axisD])).toEqual(
|
|
312
|
+
getNormalizedAxesList([axisC, axisB, axisA]),
|
|
309
313
|
);
|
|
310
|
-
expect(linkerMap.getReachableByLinkersAxesFromAxes([
|
|
314
|
+
expect(linkerMap.getReachableByLinkersAxesFromAxes([axisA])).toEqual([]);
|
|
311
315
|
});
|
|
312
316
|
});
|
|
@@ -86,9 +86,9 @@ export class LinkerMap implements LinkersData {
|
|
|
86
86
|
result.set(keyRight, { keyAxesSpec: spec, linkWith: new Map() });
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
-
for (const [
|
|
90
|
-
for (const [
|
|
91
|
-
result.get(
|
|
89
|
+
for (const [keyRight] of rightKeyVariants) {
|
|
90
|
+
for (const [keyLeft] of leftKeyVariants) {
|
|
91
|
+
result.get(keyRight)?.linkWith.set(keyLeft, linker);
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
}
|