@datagrok/bio 2.12.15 → 2.12.17

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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Aleksandr Tanas",
6
6
  "email": "atanas@datagrok.ai"
7
7
  },
8
- "version": "2.12.15",
8
+ "version": "2.12.17",
9
9
  "description": "Bioinformatics support (import/export of sequences, conversion, visualization, analysis). [See more](https://github.com/datagrok-ai/public/blob/master/packages/Bio/README.md) for details.",
10
10
  "repository": {
11
11
  "type": "git",
@@ -34,12 +34,12 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "@biowasm/aioli": "^3.1.0",
37
- "@datagrok-libraries/bio": "^5.40.8",
37
+ "@datagrok-libraries/bio": "^5.41.0",
38
38
  "@datagrok-libraries/chem-meta": "^1.2.5",
39
- "@datagrok-libraries/math": "^1.1.1",
40
- "@datagrok-libraries/ml": "^6.6.0",
39
+ "@datagrok-libraries/math": "^1.1.5",
40
+ "@datagrok-libraries/ml": "^6.6.5",
41
41
  "@datagrok-libraries/tutorials": "^1.3.12",
42
- "@datagrok-libraries/utils": "^4.2.0",
42
+ "@datagrok-libraries/utils": "^4.2.2",
43
43
  "@webgpu/types": "^0.1.40",
44
44
  "ajv": "^8.12.0",
45
45
  "ajv-errors": "^3.0.0",
@@ -55,9 +55,9 @@
55
55
  "wu": "latest"
56
56
  },
57
57
  "devDependencies": {
58
- "@datagrok/chem": "^1.9.0",
59
- "@datagrok/dendrogram": "^1.2.27",
60
- "@datagrok/helm": "^2.1.30",
58
+ "@datagrok/chem": "^1.9.2",
59
+ "@datagrok/dendrogram": "^1.2.29",
60
+ "@datagrok/helm": "^2.1.34",
61
61
  "@types/node": "^17.0.24",
62
62
  "@types/wu": "latest",
63
63
  "@typescript-eslint/eslint-plugin": "latest",
package/src/package.ts CHANGED
@@ -3,6 +3,8 @@ import * as grok from 'datagrok-api/grok';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
 
6
+ import '@datagrok-libraries/bio/src/types/helm';
7
+
6
8
  import {Options} from '@datagrok-libraries/utils/src/type-declarations';
7
9
  import {DimReductionBaseEditor, PreprocessFunctionReturnType}
8
10
  from '@datagrok-libraries/ml/src/functionEditors/dimensionality-reduction-editor';
@@ -55,13 +57,9 @@ import {SplitToMonomersFunctionEditor} from './function-edtiors/split-to-monomer
55
57
  import {splitToMonomersUI} from './utils/split-to-monomers';
56
58
  import {MonomerCellRenderer} from './utils/monomer-cell-renderer';
57
59
  import {BioPackage, BioPackageProperties} from './package-types';
58
- // import {PackageSettingsEditorWidget} from './widgets/package-settings-editor-widget';
59
60
  import {getCompositionAnalysisWidget} from './widgets/composition-analysis-widget';
60
61
  import {MacromoleculeColumnWidget} from './utils/macromolecule-column-widget';
61
62
  import {addCopyMenuUI} from './utils/context-menu';
62
- import {getPolyToolDialog} from './utils/poly-tool/ui';
63
- import {PolyToolCsvLibHandler} from './utils/poly-tool/csv-to-json-monomer-lib-converter';
64
- import {_setPeptideColumn} from './utils/poly-tool/utils';
65
63
  import {getRegionDo} from './utils/get-region';
66
64
  import {GetRegionApp} from './apps/get-region-app';
67
65
  import {GetRegionFuncEditor} from './utils/get-region-func-editor';
@@ -77,7 +75,8 @@ import {DimReductionMethods} from '@datagrok-libraries/ml/src/multi-column-dimen
77
75
  import {
78
76
  ITSNEOptions, IUMAPOptions
79
77
  } from '@datagrok-libraries/ml/src/multi-column-dimensionality-reduction/multi-column-dim-reducer';
80
- import {CyclizedNotationProvider} from './utils/poly-tool/cyclized';
78
+ import {CyclizedNotationProvider} from './utils/cyclized';
79
+ import {getMolColumnFromHelm} from './utils/helm-to-molfile/utils';
81
80
 
82
81
  export const _package = new BioPackage();
83
82
 
@@ -685,19 +684,6 @@ export function convertDialog() {
685
684
  convert(col);
686
685
  }
687
686
 
688
- //top-menu: Bio | Convert | PolyTool
689
- //name: polyTool
690
- //description: Perform cyclization of polymers
691
- export async function polyTool(): Promise<void> {
692
- let dialog: DG.Dialog;
693
- try {
694
- dialog = await getPolyToolDialog();
695
- dialog.show();
696
- } catch (err: any) {
697
- grok.shell.warning('To run PolyTool, open a dataframe with macromolecules');
698
- }
699
- }
700
-
701
687
  //name: monomerCellRenderer
702
688
  //tags: cellRenderer
703
689
  //meta.cellType: Monomer
@@ -1010,25 +996,6 @@ export async function demoBioHelmMsaSequenceSpace(): Promise<void> {
1010
996
  await demoBio05UI();
1011
997
  }
1012
998
 
1013
- //name: polyToolColumnChoice
1014
- //input: dataframe df [Input data table]
1015
- //input: column macroMolecule
1016
- export async function polyToolColumnChoice(df: DG.DataFrame, macroMolecule: DG.Column): Promise<void> {
1017
- _setPeptideColumn(macroMolecule);
1018
- await grok.data.detectSemanticTypes(df);
1019
- }
1020
-
1021
- //name: createMonomerLibraryForPolyTool
1022
- //input: file file
1023
- export async function createMonomerLibraryForPolyTool(file: DG.FileInfo) {
1024
- const fileContent = await file.readAsString();
1025
- const libHandler = new PolyToolCsvLibHandler(file.fileName, fileContent);
1026
- const libObject = await libHandler.getJson();
1027
- const jsonFileName = file.fileName.replace(/\.csv$/, '.json');
1028
- const jsonFileContent = JSON.stringify(libObject, null, 2);
1029
- DG.Utils.download(jsonFileName, jsonFileContent);
1030
- }
1031
-
1032
999
  //name: SDF to JSON Library
1033
1000
  //input: dataframe table
1034
1001
  export async function sdfToJsonLib(table: DG.DataFrame) {
@@ -1048,6 +1015,17 @@ export async function detectMacromoleculeProbe(file: DG.FileInfo, colName: strin
1048
1015
  await detectMacromoleculeProbeDo(csv, colName, probeCount);
1049
1016
  }
1050
1017
 
1018
+ //name: getMolFromHelm
1019
+ //input: dataframe df
1020
+ //input: column helmCol
1021
+ //input: bool chiralityEngine
1022
+ //output: column result
1023
+ export async function getMolFromHelm(
1024
+ df: DG.DataFrame, helmCol: DG.Column<string>, chiralityEngine?: boolean
1025
+ ): Promise<DG.Column<string>> {
1026
+ return getMolColumnFromHelm(df, helmCol, chiralityEngine);
1027
+ }
1028
+
1051
1029
  // -- Custom notation providers --
1052
1030
 
1053
1031
  //name: applyNotationProviderForCyclized
@@ -95,7 +95,7 @@ id3,QHIRE--LT
95
95
  const monLength: number = 3;
96
96
  const charWidth: number = 7;
97
97
  const sepWidth: number = 12;
98
- const colTemp: MonomerPlacer = new MonomerPlacer(null, seqCol, () => {
98
+ const colTemp: MonomerPlacer = new MonomerPlacer(null, seqCol, _package.logger, () => {
99
99
  const sh = SeqHandler.forColumn(seqCol);
100
100
  return {
101
101
  seqHandler: sh,
@@ -23,6 +23,7 @@ import {ISeqSplitted, SeqSplittedBase} from '@datagrok-libraries/bio/src/utils/m
23
23
  import {getSplitter} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
24
24
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
25
25
  import {alphabetPolymerTypes, IMonomerLib} from '@datagrok-libraries/bio/src/types/index';
26
+ import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
26
27
 
27
28
  import {
28
29
  Temps as mmcrTemps, Tags as mmcrTags,
@@ -63,27 +64,6 @@ type RendererGridCellTemp = {
63
64
  [mmcrTemps.monomerPlacer]: MonomerPlacer
64
65
  }
65
66
 
66
- function getRendererFridCellTempTemp(gridCell: DG.GridCell): RendererGridCellTemp {
67
- /** Primarily store/get MonomerPlacer at GridColumn, fallback at (Table) Column for scatter plot tooltip */
68
- let temp: RendererGridCellTemp | null = null;
69
-
70
- let gridCol: DG.GridColumn | null = null;
71
- try { gridCol = gridCell.gridColumn; } catch { gridCol = null; }
72
- temp = gridCol && gridCol.dart ? gridCol.temp as RendererGridCellTemp : null;
73
-
74
- if (!temp) {
75
- let tableCol: DG.Column | null = null;
76
- try { tableCol = gridCell.cell.column; } catch { tableCol = null; }
77
- if (!tableCol) {
78
- const k = 42;
79
- }
80
- temp = tableCol ? tableCol.temp as RendererGridCellTemp : null;
81
- }
82
- if (temp === null)
83
- throw new Error(`Monomer placer store (GridColumn or Column) not found.`);
84
- return temp;
85
- }
86
-
87
67
  export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
88
68
  private padding: number = 5;
89
69
 
@@ -105,9 +85,9 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
105
85
  // if (gridCell.cell.column.getTag(bioTAGS.aligned) !== ALIGNMENT.SEQ_MSA)
106
86
  // return;
107
87
 
108
- const tableCol: DG.Column = gridCell.cell.column;
109
- //const tableColTemp: TempType = tableCol.temp;
110
- const seqColTemp: MonomerPlacer = getRendererFridCellTempTemp(gridCell)[mmcrTemps.monomerPlacer];
88
+ const [_gridCol, tableCol, temp] =
89
+ getGridCellRendererBack<string, MonomerPlacer>(gridCell);
90
+ const seqColTemp: MonomerPlacer = temp['rendererBack'];
111
91
  if (!seqColTemp) return; // Can do nothing without precalculated data
112
92
 
113
93
  const gridCellBounds: DG.Rect = gridCell.bounds;
@@ -121,7 +101,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
121
101
  const argsX = e.offsetX - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCellBounds.x);
122
102
  const left: number | null = seqColTemp.getPosition(gridCell.tableRowIndex!, argsX);
123
103
 
124
- const seqCList: SeqSplittedBase = SeqHandler.forColumn(seqColTemp.col)
104
+ const seqCList: SeqSplittedBase = SeqHandler.forColumn(tableCol)
125
105
  .getSplitted(gridCell.tableRowIndex!).canonicals;
126
106
  if (left !== null && left < seqCList.length) {
127
107
  const monomerSymbol: string = seqCList[left];
@@ -190,9 +170,11 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
190
170
  (!isNaN(tagMaxMonomerLength) ? tagMaxMonomerLength : _package.properties?.MaxMonomerLength) ?? 4;
191
171
  }
192
172
 
193
- let seqColTemp: MonomerPlacer = getRendererFridCellTempTemp(gridCell)[mmcrTemps.monomerPlacer];
173
+ const [gridCol, _tc, temp] =
174
+ getGridCellRendererBack<string, MonomerPlacer>(gridCell);
175
+ let seqColTemp: MonomerPlacer = temp['rendererBack'];
194
176
  if (!seqColTemp) {
195
- seqColTemp = new MonomerPlacer(grid, tableCol,
177
+ seqColTemp = new MonomerPlacer(gridCol, tableCol, _package.logger,
196
178
  () => {
197
179
  const sh = SeqHandler.forColumn(tableCol);
198
180
  return {
@@ -217,7 +199,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
217
199
  const _maxIndex = maxLengthWords.length;
218
200
 
219
201
  // Store updated seqColTemp to the col temp
220
- if (seqColTemp.updated) getRendererFridCellTempTemp(gridCell)[mmcrTemps.monomerPlacer] = seqColTemp;
202
+ if (seqColTemp.updated) temp['rendererBack'] = seqColTemp;
221
203
 
222
204
  g.save();
223
205
  try {
@@ -1,8 +1,5 @@
1
- import * as grok from 'datagrok-api/grok';
2
- import * as ui from 'datagrok-api/ui';
3
- import * as DG from 'datagrok-api/dg';
4
-
5
- import {GAP_SYMBOL, INotationProvider, ISeqSplitted, SeqSplittedBase, SplitterFunc} from '@datagrok-libraries/bio/src/utils/macromolecule/types';
1
+ import {GAP_SYMBOL, INotationProvider, ISeqSplitted, SeqSplittedBase, SplitterFunc}
2
+ from '@datagrok-libraries/bio/src/utils/macromolecule/types';
6
3
  import {getSplitterWithSeparator, StringListSeqSplitted} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
7
4
  import {GapOriginals} from '@datagrok-libraries/bio/src/utils/seq-handler';
8
5
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
@@ -33,9 +30,8 @@ export class CyclizedSeqSplitted extends StringListSeqSplitted {
33
30
  if (!this._canonicals) {
34
31
  const len = this.length;
35
32
  this._canonicals = new Array<string>(len);
36
- for (let posIdx = 0; posIdx < len; ++posIdx) {
33
+ for (let posIdx = 0; posIdx < len; ++posIdx)
37
34
  this._canonicals[posIdx] = this.getCanonical(posIdx);
38
- }
39
35
  }
40
36
  return this._canonicals;
41
37
  }
@@ -116,6 +116,14 @@ export class MonomerLib implements IMonomerLib {
116
116
  this._onChanged.next();
117
117
  }
118
118
 
119
+ getSummary(): string {
120
+ const monTypeList: string[] = this.getPolymerTypes();
121
+ const resStr: string = monTypeList.length == 0 ? 'empty' : monTypeList.map((monType) => {
122
+ return `${monType} ${this.getMonomerSymbolsByType(monType).length}`;
123
+ }).join('\n');
124
+ return resStr;
125
+ }
126
+
119
127
  getTooltip(polymerType: string, monomerSymbol: string): HTMLElement {
120
128
  // getTooltip(monomer: Monomer): HTMLElement;
121
129
  // getTooltip(monomerOrPolymerType: string | Monomer, symbol?: string): HTMLElement {
@@ -163,8 +171,12 @@ export class MonomerLib implements IMonomerLib {
163
171
  label('Source'),
164
172
  ui.divText(monomer.lib?.source ?? 'unknown', {classes: 'ui-input-text'}),
165
173
  ], {classes: 'ui-input-root'}));
166
- } else
167
- res.append(ui.divText('Monomer not found'));
174
+ } else {
175
+ res.append(ui.divV([
176
+ ui.divText(`Monomer '${monomerSymbol}' of type '${polymerType}' not found.`),
177
+ ui.divText('Open the Context Panel, then expand Manage Libraries'),
178
+ ]));
179
+ }
168
180
  return res;
169
181
  }
170
182
  }
@@ -2,14 +2,15 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
+ import * as org from 'org';
5
6
  import $ from 'cash-dom';
6
- import {fromEvent, Observable, Subject, Unsubscribable} from 'rxjs';
7
+ import {fromEvent, Unsubscribable} from 'rxjs';
7
8
 
8
- import {IHelmWebEditor, IWebEditorApp} from '@datagrok-libraries/bio/src/helm/types';
9
+ import {IHelmWebEditor} from '@datagrok-libraries/bio/src/helm/types';
9
10
  import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
10
11
  import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
11
12
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
12
- import {delay, testEvent} from '@datagrok-libraries/utils/src/test';
13
+ import {delay} from '@datagrok-libraries/utils/src/test';
13
14
 
14
15
  import {updateDivInnerHTML} from '../utils/ui-utils';
15
16
  import {helmSubstructureSearch} from '../substructure-search/substructure-search';
@@ -54,7 +55,7 @@ export class HelmBioFilter extends BioFilterBase<BioFilterProps> /* implements I
54
55
  this.logger.warning('TEST: HelmBioFilter.init().sync() waitForElementInDom ready');
55
56
  this.updateFilterPanel();
56
57
  let webEditorHost: HTMLDivElement | null;
57
- let webEditorApp: IWebEditorApp | null;
58
+ let webEditorApp: org.helm.IWebEditorApp | null;
58
59
  // TODO: Unsubscribe 'click' and 'sizeChanged'
59
60
  this.viewSubs.push(fromEvent(this._filterPanel, 'click').subscribe(() => {
60
61
  webEditorHost = ui.div();
@@ -16,7 +16,6 @@ import {TAGS as bioTAGS, NOTATION} from '@datagrok-libraries/bio/src/utils/macro
16
16
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
17
17
  import {delay, testEvent} from '@datagrok-libraries/utils/src/test';
18
18
  import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
19
- import {IHelmWebEditor, IWebEditorApp} from '@datagrok-libraries/bio/src/helm/types';
20
19
  import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
21
20
  import {IRenderer} from '@datagrok-libraries/bio/src/types/renderer';
22
21
  import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
@@ -197,7 +196,7 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
197
196
 
198
197
  this.filterSyncer.sync(logPrefix, async () => {
199
198
  if (state.props && this.bioFilter)
200
- this.bioFilter.props = state.props;
199
+ this.bioFilter.props = DG.toJs(state.props ?? {});
201
200
  });
202
201
  }
203
202
 
package/webpack.config.js CHANGED
@@ -41,6 +41,8 @@ module.exports = {
41
41
  'cash-dom': '$',
42
42
  'dayjs': 'dayjs',
43
43
  'wu': 'wu',
44
+ 'scil': 'scil',
45
+ 'org': 'org',
44
46
  },
45
47
  output: {
46
48
  filename: '[name].js',
package/dist/246.js DELETED
@@ -1,2 +0,0 @@
1
- var bio;(()=>{"use strict";var n,e,t={8960:(n,e,t)=>{var r;!function(n){n.EUCLIDEAN="EUCLIDEAN",n.MANHATTAN="MANHATTAN"}(r||(r={}));const a={[r.EUCLIDEAN]:function(n){return`\n var sum = 0.0;\n for (var i = 0u; i < ${n}; i = i + 1u) {\n sum = sum + distances[i] * distances[i] * computeInfo.weights[i] * computeInfo.weights[i];\n }\n return sqrt(sum);\n `},[r.MANHATTAN]:function(n){return`\n var sum = 0.0;\n for (var i = 0u; i < ${n}; i = i + 1u) {\n sum = sum + abs(distances[i]) * computeInfo.weights[i];\n }\n return sum;\n `}};var i;!function(n){n.HAMMING="Hamming",n.EUCLIDEAN="Euclidean",n.MANHATTAN="Manhattan",n.TANIMOTO="Tanimoto",n.LEVENSTEIN="Levenshtein",n.NEEDLEMAN_WUNSCH="Needlemann-Wunsch",n.MONOMER_CHEMICAL_DISTANCE="Monomer chemical distance",n.SOKAL="Sokal",n.COSINE="Cosine",n.ASYMMETRIC="Asymmetric",n.Difference="Difference",n.OneHot="One-Hot"}(i||(i={}));const o={[i.HAMMING]:function(n,e){return`\n let aLength: u32 = computeInfo.entrySizes[${e}][aIndex];\n let bLength: u32 = computeInfo.entrySizes[${e}][bIndex];\n let maxLength: u32 = max(aLength, bLength);\n let minLength: u32 = min(aLength, bLength);\n let sizeDiff: u32 = maxLength - minLength;\n \n let maxIntDistance = ceil(maxDistance * f32(maxLength)) - f32(sizeDiff);\n\n var diff: f32 = 0.0;\n for (var i = 0u; i < ${n}; i = i + 1u) {\n diff = diff + f32(a[i] != b[i]);\n if (diff > maxIntDistance) {\n return 1.0;\n }\n }\n diff += f32(sizeDiff);\n return diff / ${n};\n `},[i.EUCLIDEAN]:function(n,e){return`\n var dist: f32 = 0.0;\n for (var i = 0u; i < ${n}; i = i + 1u) {\n dist = dist + f32(a[i] - b[i]) * f32(a[i] - b[i]);\n }\n return sqrt(dist);\n `},[i.MANHATTAN]:function(n,e){return`\n var dist: f32 = 0.0;\n for (var i = 0u; i < ${n}; i = i + 1u) {\n dist = dist + abs(f32(a[i] - b[i]));\n }\n return dist;\n `},[i.TANIMOTO]:function(n,e){return`\n var onBitsa: u32 = 0u;\n var onBitsb: u32 = 0u;\n for (var i = 0u; i < ${n}u; i = i + 1u) {\n onBitsa = onBitsa + countOneBits(a[i]);\n onBitsb = onBitsb + countOneBits(b[i]);\n }\n\n if (onBitsa == 0u && onBitsb == 0u) {\n return 0.0;\n }\n\n let totalOnBits = onBitsa + onBitsb;\n var commonBits: u32 = 0u;\n for (var i = 0u; i < ${n}u; i = i + 1u) {\n commonBits = commonBits + countOneBits(a[i] & b[i]);\n }\n\n return 1.0 - f32(commonBits) / f32(totalOnBits - commonBits);\n `},[i.LEVENSTEIN]:function(n,e){return`\n let aLength: u32 = computeInfo.entrySizes[${e}][aIndex];\n let bLength: u32 = computeInfo.entrySizes[${e}][bIndex];\n let maxLength: u32 = max(aLength, bLength);\n let minLength: u32 = min(aLength, bLength);\n\n let maxIntDistance = ceil(maxDistance * f32(maxLength));\n\n // we will store two arrays as matrix and swap the working indices per pass.\n // this way we can reduce memory usage per computation to just O(aLength)\n // the grid will have aLength + 1 columns and bLength + 1 rows\n // this will be guaranteed by iteration, but the array sizes must be known at compile time, so we will use a fixed size of maxArraySize\n var dynamicPassMat: array<array<f32, ${n+1}u>, 2>; // initialize to 0\n \n var prevIndex: u32 = 0;\n var curIndex: u32 = 1; // we will swap these indices per pass\n\n // initialize the first row\n for (var i = 0u; i <= aLength; i = i + 1u) {\n dynamicPassMat[prevIndex][i] = f32(i);\n }\n\n // iterate over the rows\n for (var i = 1u; i <= bLength; i = i + 1u) {\n dynamicPassMat[curIndex][0] = f32(i);\n var minEntry: f32 = f32(maxLength);\n let prevRow = &dynamicPassMat[prevIndex];\n let curRow = &dynamicPassMat[curIndex];\n let bMon = u32(b[i - 1]);\n for (var j = 1u; j <= aLength; j = j + 1u) {\n var cost: f32 = f32(a[j - 1] != bMon);\n var res: f32 = min(\n min(\n (*prevRow)[j] + 1.0, // deletion\n (*curRow)[j - 1] + 1.0, // insertion\n ),\n (*prevRow)[j - 1] + cost // substitution\n );\n (*curRow)[j] = res;\n if (res < minEntry) {\n minEntry = res;\n }\n }\n // swap the indices\n let temp: u32 = prevIndex;\n prevIndex = curIndex;\n curIndex = temp;\n if (minEntry > maxIntDistance) {\n return 1.0;\n }\n }\n\n return dynamicPassMat[prevIndex][aLength] / f32(maxLength);\n `},[i.NEEDLEMAN_WUNSCH]:function(n,e){return`\n let aLength: u32 = computeInfo.entrySizes[${e}][aIndex];\n let bLength: u32 = computeInfo.entrySizes[${e}][bIndex];\n let maxLength: u32 = max(aLength, bLength);\n let minLength: u32 = min(aLength, bLength);\n \n let maxIntDistance = ceil(maxDistance * f32(maxLength));\n // we will store two arrays as matrix and swap the working indices per pass.\n // this way we can reduce memory usage per computation to just O(aLength)\n // the grid will have aLength + 1 columns and bLength + 1 rows\n // this will be guaranteed by iteration, but the array sizes must be known at compile time, so we will use a fixed size of maxArraySize\n var dynamicPassMat: array<array<f32, ${n+1}u>, 2>; // initialize to 0\n \n // we need to keep track of which operation led to the current cell\n // i.e. whether we came from the left, top or diagonal to assign gap open/gap extend penalty\n var verticalGaps: array<u32, ${n+1}u>;\n var horizontalGaps: array<u32, ${n+1}u>;\n\n let gapOpenPenalty: f32 = suppInfo.gapOpenPenalty${e};\n let gapExtensionPenalty: f32 = suppInfo.gapExtensionPenalty${e};\n var prevIndex: u32 = 0;\n var curIndex: u32 = 1; // we will swap these indices per pass\n // initialize the first row\n for (var i = 0u; i <= aLength; i = i + 1u) {\n dynamicPassMat[prevIndex][i] = gapOpenPenalty + f32(i - 1) * gapExtensionPenalty;\n dynamicPassMat[curIndex][i] = 0.0;\n }\n dynamicPassMat[0][0] = 0.0;\n\n let simMatrix = &suppInfo.similarityMatrix${e}; // using pointers make things faster\n // iterate over the rows\n for (var i = 1u; i <= bLength; i = i + 1u) {\n let prevRow = &dynamicPassMat[prevIndex];\n let curRow = &dynamicPassMat[curIndex];\n (*curRow)[0] = gapOpenPenalty + f32(i - 1) * gapExtensionPenalty;\n var minEntry: f32 = f32(maxLength);\n let monB = u32(b[i - 1]);\n for (var j = 1u; j <= aLength; j = j + 1u) {\n let monA = u32(a[j - 1]);\n \n let cost: f32 = (*prevRow)[j - 1] + 1f - (*simMatrix)[monA][monB];\n var top = (*prevRow)[j]; // deletion\n if (verticalGaps[j] > 0) {\n top = top + gapExtensionPenalty;\n } else {\n top = top + gapOpenPenalty;\n }\n var left = (*curRow)[j - 1]; // insertion\n if (horizontalGaps[j - 1] > 0) {\n left = left + gapExtensionPenalty;\n } else {\n left = left + gapOpenPenalty;\n }\n var res: f32 = min(\n min(\n top, // deletion\n left, // insertion\n ),\n cost // substitution\n );\n (*curRow)[j] = res;\n if (res < minEntry) {\n minEntry = res;\n }\n // update the horizontal and vertical gaps\n if (res == cost) {\n verticalGaps[j] = 0;\n horizontalGaps[j] = 0;\n } else if (res == left) {\n verticalGaps[j] = 0;\n horizontalGaps[j] = 1;\n } else {\n verticalGaps[j] = 1;\n horizontalGaps[j] = 0;\n }\n }\n // swap the indices\n let temp: u32 = prevIndex;\n prevIndex = curIndex;\n curIndex = temp;\n if (minEntry > maxIntDistance) {\n return 1.0;\n }\n }\n return dynamicPassMat[prevIndex][aLength] / f32(maxLength);\n \n `},[i.MONOMER_CHEMICAL_DISTANCE]:function(n,e){return`\n let aLength: u32 = computeInfo.entrySizes[${e}][aIndex];\n let bLength: u32 = computeInfo.entrySizes[${e}][bIndex];\n let maxLength: u32 = max(aLength, bLength);\n let minLength: u32 = min(aLength, bLength);\n let sizeDiff: u32 = maxLength - minLength;\n \n let maxIntDistance = ceil(maxDistance * f32(maxLength)) - f32(sizeDiff);\n\n let simMatrix = &(suppInfo.similarityMatrix${e}); // using pointers make things faster\n var diff: f32 = 0.0;\n for (var i = 0u; i < ${n}; i = i + 1u) {\n diff = diff + 1.0 - (*simMatrix)[u32(a[i])][u32(b[i])];\n if (diff > maxIntDistance) {\n return 1.0;\n }\n }\n diff += f32(sizeDiff);\n return diff / ${n};\n `},[i.SOKAL]:function(n,e){return`\n var onBitsa: u32 = 0u;\n var onBitsb: u32 = 0u;\n for (var i = 0u; i < ${n}u; i = i + 1u) {\n onBitsa = onBitsa + countOneBits(a[i]);\n onBitsb = onBitsb + countOneBits(b[i]);\n }\n let total = onBitsa + onBitsb;\n if (total == 0u) {\n return 1.0;\n }\n var commonBits: u32 = 0u;\n for (var i = 0u; i < ${n}u; i = i + 1u) {\n commonBits = commonBits + countOneBits(a[i] & b[i]);\n }\n return 1.0 - f32(commonBits) / f32(total * 2 - commonBits * 3);\n `},[i.COSINE]:function(n,e){return`\n var onBitsa: u32 = 0u;\n var onBitsb: u32 = 0u;\n for (var i = 0u; i < ${n}u; i = i + 1u) {\n onBitsa = onBitsa + countOneBits(a[i]);\n onBitsb = onBitsb + countOneBits(b[i]);\n }\n let total = onBitsa * onBitsb; // p.s. here total is taken by multiplying\n if (total == 0u) {\n return 1.0;\n }\n var commonBits: u32 = 0u;\n for (var i = 0u; i < ${n}u; i = i + 1u) {\n commonBits = commonBits + countOneBits(a[i] & b[i]);\n }\n return 1.0 - f32(commonBits) / sqrt(f32(total));\n `},[i.ASYMMETRIC]:function(n,e){return`\n var onBitsa: u32 = 0u;\n var onBitsb: u32 = 0u;\n for (var i = 0u; i < ${n}u; i = i + 1u) {\n onBitsa = onBitsa + countOneBits(a[i]);\n onBitsb = onBitsb + countOneBits(b[i]);\n }\n let min = min(onBitsa, onBitsb);\n if (min == 0u) {\n return 1.0;\n }\n var commonBits: u32 = 0u;\n for (var i = 0u; i < ${n}u; i = i + 1u) {\n commonBits = commonBits + countOneBits(a[i] & b[i]);\n }\n return 1.0 - f32(commonBits) / f32(min);\n `},[i.Difference]:function(n,e){return`\n let range = suppInfo.range${e};\n return f32(abs(f32(a[0]) - f32(b[0])) / range);\n `},[i.OneHot]:function(n,e){return`\n let aLength: u32 = computeInfo.entrySizes[${e}][aIndex];\n let bLength: u32 = computeInfo.entrySizes[${e}][bIndex];\n if (aLength != bLength) {\n return 1.0;\n }\n for (var i = 0u; i < aLength; i = i + 1u) {\n if(a[i] != b[i]) {\n return 1.0;\n }\n }\n return 0.0;\n `}},s={[i.HAMMING]:n=>Math.ceil(n/30),[i.EUCLIDEAN]:n=>Math.ceil(n/30),[i.MANHATTAN]:n=>Math.ceil(n/30),[i.TANIMOTO]:n=>Math.ceil(n/60),[i.SOKAL]:n=>Math.ceil(n/60),[i.COSINE]:n=>Math.ceil(n/60),[i.ASYMMETRIC]:n=>Math.ceil(n/60),[i.LEVENSTEIN]:n=>Math.ceil(n*n/60),[i.NEEDLEMAN_WUNSCH]:n=>Math.ceil(n*n/60),[i.MONOMER_CHEMICAL_DISTANCE]:n=>Math.ceil(n/25),[i.Difference]:n=>1,[i.OneHot]:n=>Math.ceil(n/40)},u={STRING:new Set([i.HAMMING,i.LEVENSTEIN,i.NEEDLEMAN_WUNSCH,i.MONOMER_CHEMICAL_DISTANCE,i.OneHot]),UINT32ARRAY:new Set([i.HAMMING,i.EUCLIDEAN,i.MANHATTAN,i.MONOMER_CHEMICAL_DISTANCE,i.LEVENSTEIN,i.NEEDLEMAN_WUNSCH,i.TANIMOTO,i.COSINE,i.SOKAL,i.ASYMMETRIC,i.OneHot,i.Difference]),INT32ARRAY:new Set([i.EUCLIDEAN,i.MANHATTAN,i.OneHot,i.Difference]),FLOAT32ARRAY:new Set([i.EUCLIDEAN,i.MANHATTAN,i.Difference]),NUMBER:new Set([i.EUCLIDEAN,i.MANHATTAN,i.Difference]),BITARRAY:new Set([i.TANIMOTO,i.COSINE,i.SOKAL,i.ASYMMETRIC])};var l=function(n,e,t,r){return new(t||(t=Promise))((function(a,i){function o(n){try{u(r.next(n))}catch(n){i(n)}}function s(n){try{u(r.throw(n))}catch(n){i(n)}}function u(n){var e;n.done?a(n.value):(e=n.value,e instanceof t?e:new t((function(n){n(e)}))).then(o,s)}u((r=r.apply(n,e||[])).next())}))},c=function(n,e,t,r){return new(t||(t=Promise))((function(a,i){function o(n){try{u(r.next(n))}catch(n){i(n)}}function s(n){try{u(r.throw(n))}catch(n){i(n)}}function u(n){var e;n.done?a(n.value):(e=n.value,e instanceof t?e:new t((function(n){n(e)}))).then(o,s)}u((r=r.apply(n,e||[])).next())}))};function f(n,e,t,r){return n.map(((n,r)=>`\n fn distanceScript${r}(aIndex: u32, bIndex: u32) -> f32 {\n let a = computeInfo.data${r}[aIndex];\n let b = computeInfo.data${r}[bIndex];\n let maxDistance: f32 = ${t};\n ${o[n](e[r],r)}\n }\n `)).join("\n")+"\n"+`\n fn combinedDistance(aIndex: u32, bIndex: u32) -> f32 {\n var distances: array<f32, ${n.length}>;\n ${n.map(((n,e)=>`distances[${e}] = distanceScript${e}(aIndex, bIndex);`)).join("\n")}\n ${a[r](n.length)}\n }\n \n `}var m=t(2590);async function d(n,e,t){const r=n.length,a=[],i=[];for(let o=0;o<r;o++)for(let s=o+1;s<r;s++){const r=n[o],u=n[s];e[r]?.[u]>=t&&(a.push(o),i.push(s))}return function(n,e,t){const r=new Float32Array(t.length).fill(0).map((()=>10*Math.random())),a=new Float32Array(t.length).fill(0).map((()=>10*Math.random())),i=new Float32Array(t.length).fill(0),o=new Float32Array(t.length).fill(0);for(let s=0;s<100;s++){const u=1-s/100;i.fill(0),o.fill(0);for(let t=0;t<n.length;t++){const s=n[t],l=e[t],c=r[s]-r[l],f=a[s]-a[l];Math.abs(c)>=1&&(i[s]-=u*c,i[l]+=u*c),Math.abs(f)>=1&&(o[s]-=u*f,o[l]+=u*f)}for(let n=0;n<t.length;n++){const e=Math.sqrt(i[n]*i[n]+o[n]*o[n]);e>0&&(r[n]+=i[n]/e*u,a[n]+=o[n]/e*u)}}let s=r[0],u=a[0],l=r[0],c=a[0];for(let n=1;n<t.length;n++)s=Math.min(s,r[n]),u=Math.min(u,a[n]),l=Math.max(l,r[n]),c=Math.max(c,a[n]);let f=l-s,m=c-u;0===f&&(f=l);for(let n=0;n<t.length;n++)r[n]=(r[n]-s)/f/2+.5;0===m&&(m=c);for(let n=0;n<t.length;n++)a[n]=(a[n]-u)/m/2+.5;return{embedX:r,embedY:a}}(a,i,n)}const p={expandFactor:2,maxIterations:5,inflateFactor:2,multFactor:1};class h{constructor(n={}){this._options={...p,...n}}async transform(n,e){let t=this.toObjectForm(n);if(this._options.maxIterations>0){this.addLoops(t,e),this.normalize(t);for(let n=0;n<this._options.maxIterations;n++)t=this.expand(t,e),this.inflate(t),this.normalize(t)}const{clusters:r,is:a,js:i}=this.assignClusters(t,e);this.correctClusters(r);const o=await this.layout(r,t,e);return{clusters:r,embedX:o.embedX,embedY:o.embedY,is:a,js:i}}correctClusters(n){const e={};for(const t of n)e[t]||(e[t]=0),e[t]++;const t=Object.keys(e).map(Number).sort(((n,t)=>e[n]-e[t])),r={};t.forEach(((n,e)=>r[n]=e+1));for(let e=0;e<n.length;e++)n[e]=r[n[e]]}async layout(n,e,t){const r=new Float32Array(t).fill(0),a=new Float32Array(t).fill(0),i={};n.forEach(((n,e)=>{i[n]||(i[n]=[]),i[n].push(e)}));let o=0;const s=Object.keys(i);s.sort(((n,e)=>i[e].length-i[n].length));let u=6,l=0;for(const n of s){const t=i[n],s=await d(t,e,.001);o===Math.ceil(u/1.5)&&(o=0,l+=5/u,u=Math.ceil(1.5*u));const c=o%u*5/u*1.5;for(let n=0;n<s.embedX.length;n++)r[t[n]]=5*s.embedX[n]/u+c,a[t[n]]=5*s.embedY[n]/u+l;o++}return{embedX:r,embedY:a}}mergeClusters(n,e,t){const r=n[e],a=n[t];for(let e=0;e<n.length;e++)n[e]===a&&(n[e]=r)}assignClusters(n,e){let t=0;const r=[],a=[],i=Math.floor(Math.max(Math.log10(e),2))+1,o=Math.pow(10,i),s=new Array(e).fill(-1);for(const e of Object.keys(n))for(const i of Object.keys(n[e]))Math.round(n[e][i]*o)/o>0&&n[e][i]!==Number(e)&&Number(i)>Number(e)&&(r.push(Number(e)),a.push(Number(i)),-1!==s[Number(e)]&&-1!==s[Number(i)]?s[Number(e)]!==s[Number(i)]&&this.mergeClusters(s,Number(e),Number(i)):-1!==s[Number(e)]?s[Number(i)]=s[Number(e)]:-1!==s[Number(i)]?s[Number(e)]=s[Number(i)]:(t++,s[Number(e)]=t,s[Number(i)]=t));for(let n=0;n<s.length;n++)-1===s[n]&&(t++,s[n]=t);return{clusters:s,is:new Uint32Array(r),js:new Uint32Array(a)}}toObjectForm(n){const e={};for(let t=0;t<n.i.length;t++)e[n.i[t]]||(e[n.i[t]]={}),e[n.i[t]][n.j[t]]=1-n.distance[t],e[n.j[t]]||(e[n.j[t]]={}),e[n.j[t]][n.i[t]]=1-n.distance[t];return e}addLoops(n,e){for(let t=0;t<e;t++)n[t]||(n[t]={}),n[t][t]=this._options.multFactor}normalize(n){for(const e of Object.keys(n)){const t=n[e];let r=0;for(const n of Object.keys(t))r+=t[n];if(0!==r)for(const a of Object.keys(t))n[e][a]/=r}}expand(n,e){const t={},r=Math.floor(Math.max(Math.log10(e),2))+1,a=Math.pow(10,r);for(let r=0;r<e;r++)if(n[r]){t[r]={};for(let i=r;i<e;i++){if(!n[r]?.[i])continue;const e=this.getExpandValue(n,r,i);Math.round(e*a)/a>0&&(t[r][i]=e,t[i]||(t[i]={}),t[i][r]=e)}}return t}inflate(n){for(const e of Object.keys(n)){const t=n[e];for(const r of Object.keys(t))n[e][r]=Math.pow(n[e][r],this._options.inflateFactor)}}getExpandValue(n,e,t){let r=0;const a=Object.keys(n[e]??{}),i=Object.keys(n[t]??{});for(const o of a)i.includes(o)&&(r+=n[e][o]*n[t][o]);return r}}onmessage=async n=>{const{data:e,threshold:t,weights:a,aggregationMethod:o,distanceFnArgs:d,distanceFns:p,maxIterations:g,useWebGPU:y}=n.data;console.time("sparse matrix");let A=null;if(y)try{A=await function(n,e=.8,t,a,o,m){return c(this,void 0,void 0,(function*(){const c=yield function(){return l(this,void 0,void 0,(function*(){const n=yield navigator.gpu.requestAdapter({powerPreference:"high-performance"});if(null==n)return null;const e=1e9,t=n.limits,r=t.maxBufferSize,a=t.maxStorageBufferBindingSize;try{return yield n.requestDevice({requiredLimits:{maxBufferSize:Math.min(r,e),maxStorageBufferBindingSize:Math.min(a,e)}})}catch(e){return console.error("Failed to create device with required limits",e),yield n.requestDevice()}}))}();if(!c)return null;const d=Object.values(i);if(t.some((n=>!d.includes(n))))throw new Error("Invalid distance metrics provided: "+t.join(", "));if(!Object.values(r).includes(a))throw new Error("Invalid aggregation function provided: "+a);const p=1-e;if(m.length!==n.length||m.length!==t.length||m.length!==o.length)throw new Error("Options, weigths and distance functions must be provided for each column");if(n.some((e=>e.length!==n[0].length)))throw new Error("All entry lists must be the same length");const h=n.length,g=n[0].length,y=n.map(((n,e)=>function(n,e=i.HAMMING,t,r={gapOpenPenalty:1,gapExtensionPenalty:.6}){var a,o;let l=null;const c=n.some((n=>"string"==typeof n))?(l="STRING",n.map((n=>new Uint32Array(n.split("").map((n=>n.charCodeAt(0))))))):n.some((n=>"number"==typeof n))?(l="NUMBER",n.map((n=>new Float32Array([n])))):"object"==typeof n[0]&&n.some((n=>"_data"in n&&"_length"in n))?(l="BITARRAY",n.map((n=>n._data))):n.some((n=>n instanceof Float32Array))?(l="FLOAT32ARRAY",n):n.some((n=>n instanceof Uint32Array))?(l="UINT32ARRAY",n):n.some((n=>n instanceof Int32Array))?(l="INT32ARRAY",n):void 0;if(!c||!l)throw new Error("Invalid entry type, could not determine entry type from input list");const f=c[0]instanceof Int32Array?"INT32ARRAY":c[0]instanceof Float32Array?"FLOAT32ARRAY":"UINT32ARRAY",m=new Uint32Array(c.map((n=>n.length)));if(!u[l]||!u[l].has(e))throw new Error(`Distance metric '${e}' not supported for entry type '${l}'`);const d=m.reduce(((n,e)=>Math.max(n,e)),0),p=s[e](d),h="INT32ARRAY"===f?Int32Array:"FLOAT32ARRAY"===f?Float32Array:Uint32Array,g=new h(c.length*d);c.forEach(((n,e)=>{g.set(n,e*d)}));let y="",A=0,b="FLOAT32ARRAY",E=null;if(e===i.NEEDLEMAN_WUNSCH||e===i.MONOMER_CHEMICAL_DISTANCE){let n=r.scoringMatrix&&r.alphabetIndexes?Object.keys(r.alphabetIndexes).reduce(((n,e)=>Math.max(n,e.charCodeAt(0))),0):-1;if(!r.alphabetIndexes||!r.scoringMatrix){for(let e=0;e<g.length;e++)g[e]>n&&(n=g[e]);r.scoringMatrix=new Array(n+1).fill(null).map((()=>new Array(n+1).fill(0))),r.alphabetIndexes={};for(let n=0;n<r.scoringMatrix.length;n++)r.scoringMatrix[n][n]=1,r.alphabetIndexes[String.fromCharCode(n)]=n}const e=(n+1)*(n+1),i=new Array(n+1).fill(null).map((()=>new Float32Array(n+1)));for(let e=0;e<n+1;e++)i[e][e]=1;const s=r.alphabetIndexes;for(const n of Object.keys(s))for(const e of Object.keys(s))n!==e&&(i[n.charCodeAt(0)][e.charCodeAt(0)]=r.scoringMatrix[s[n]][s[e]]);A=2+e,b="FLOAT32ARRAY",E=new Float32Array(A),E[0]=null!==(a=r.gapOpenPenalty)&&void 0!==a?a:1,E[1]=null!==(o=r.gapExtensionPenalty)&&void 0!==o?o:.6;let u=2;for(let n=0;n<i.length;n++)E.set(i[n],u),u+=i[n].length;y=`\n gapOpenPenalty${t}: f32,\n gapExtensionPenalty${t}: f32,\n similarityMatrix${t}: array<array<f32, ${n+1}>, ${n+1}>`}else if(e===i.Difference){if(!r.range||"number"!=typeof r.range||r.range<=0){const n=g.reduce(((n,e)=>Math.min(n,e)),g[0]),e=g.reduce(((n,e)=>Math.max(n,e)),g[0]);r.range=e-n}if(r.range<=0)throw new Error("Invalid range for difference distance metric: "+r.range);A=1,b="FLOAT32ARRAY",E=new Float32Array([r.range]),y=`\n range${t}: f32`}const w=g instanceof Int32Array?"i32":g instanceof Float32Array?"f32":"u32",I=`data${t}: array<array<${w}, ${d}>, ${c.length}>`;return{flatSourceArray:g,sourceArraySize:g.length,maxEntryLen:d,arraySizes:m,complexity:p,suppInfoBuffer:E,suppInfoSize:A,suppInfoType:b,suppInfoStructWgsl:y,entryType:l,dataTypeWGSL:w,dataStructWgsl:I,EncodedArrayConstructor:h}}(n,t[e],e,m[e])));if(0===h)throw new Error("No columns provided. Please provide at least one column of data.");1===h&&(a=r.MANHATTAN);let A=y.map((n=>n.suppInfoStructWgsl)).filter((n=>!!n&&""!=n)).join(",\n"),b=!1;A&&""!=A.trim()||(b=!0,A="\ndummy: f32\n");const E=y.map((n=>n.dataStructWgsl)).filter((n=>!!n&&""!=n)).join(",\n"),w=new Uint32Array(h*g);y.forEach(((n,e)=>{w.set(n.arraySizes,e*g)}));const I=1e4,x=100,M=y.reduce(((n,e)=>n+e.complexity),0),v=Math.ceil(1e4/M),N=Math.ceil(Math.sqrt(Math.ceil(100))),L=10*N,B=g*(g-1)/2,S=Math.ceil(B/I),T=c.createShaderModule({label:"Sparse matrix compute shader",code:`\n // each thread will perform 100 iterations at one time, comparing 100 pairs of entries.\n // in total, each thread will perform at most ${S} comparisons.\n // first is the result struct, containing is, js, and distances. each array with length of 100,\n // and also integer for how many pairs were found to be below threshold.\n struct SparseResult {\n i: array<array<u32, 100>, 10000>,\n j: array<array<u32, 100>, 10000>,\n distances: array<array<f32, 100>, 10000>,\n found: array<u32, 10000>,\n done: array<u32, 10000>\n }\n // struct for the data\n struct ComputeInfo {\n // start at cols and rows, and end at cols and rows for each thread, these will be calculated on cpu and passed to gpu.\n startAtCols: array<u32, 10000>,\n startAtRows: array<u32, 10000>,\n endAtCols: array<u32, 10000>,\n endAtRows: array<u32, 10000>,\n\n // the ACTUALLY sizes of each entry\n entrySizes: array<array<u32, ${g}>, ${h}>,\n // the weights for each entry\n weights: array<f32, ${h}>,\n // the data for each entry\n ${E} // an example of the dataWgsl would be:\n //data0: array<array<u32,20>,100>,\n //data1: array<array<u32,20>,100>\n }\n\n // struct for the supplementary information\n struct SuppInfo {\n // struct containing all the supplementary info, like scoring matrix, alphabet indexes, range, etc.\n ${A}\n };\n\n @group(0) @binding(0) var<storage, read_write> computeInfo: ComputeInfo;\n @group(0) @binding(1) var<storage, read_write> suppInfo: SuppInfo;\n @group(0) @binding(2) var<storage, read_write> results: SparseResult;\n @compute @workgroup_size(10, 10) fn calcSparseMatrix(\n @builtin(global_invocation_id) id: vec3<u32>\n ) {\n ${b?"let otherDummy = suppInfo.dummy * 2;":""} // just to make sure that the suppInfo is not optimized out\n let threadCol = id.x;\n let threadRow = id.y;\n let linearIndex = threadRow * ${L} + threadCol;\n if (linearIndex >= 10000) {\n return; // if we are out of bounds, return\n } \n var startAtCol: u32 = computeInfo.startAtCols[linearIndex];\n var startAtRow: u32 = computeInfo.startAtRows[linearIndex];\n let endAtCol: u32 = min(computeInfo.endAtCols[linearIndex], ${g}u);\n let endAtRow: u32 = min(computeInfo.endAtRows[linearIndex], ${g}u);\n let is = &results.i[linearIndex];\n let js = &results.j[linearIndex];\n let distances = &results.distances[linearIndex];\n results.found[linearIndex] = 0; // initialize the found counter\n var found: u32 = 0;\n if (results.done[linearIndex] > 0) {\n return; // if we are done, return\n }\n for (var i = 0; i < ${v}; i++) {\n if (startAtCol >= endAtCol && startAtRow >= endAtRow) {\n results.done[linearIndex] = 1;\n break;\n }\n if (found >= 100) {\n break;\n }\n let dist = combinedDistance(startAtCol, startAtRow);\n if (dist <= ${p}) {\n (*is)[found] = startAtCol;\n (*js)[found] = startAtRow;\n (*distances)[found] = dist;\n found = found + 1;\n }\n startAtCol = startAtCol + 1;\n if (startAtCol >= ${g}u) {\n startAtRow += 1;\n startAtCol = startAtRow + 1;\n }\n }\n results.found[linearIndex] = found;\n // update the startAtCols and startAtRows\n computeInfo.startAtCols[linearIndex] = startAtCol;\n computeInfo.startAtRows[linearIndex] = startAtRow;\n\n }\n\n // this will generate the distance script for each distance metric and then combine them into one\n ${f(t,y.map((n=>n.maxEntryLen)),p,a)}\n\n\n `}),O=c.createComputePipeline({label:"sparse matrix compute pipeline",layout:"auto",compute:{module:T,entryPoint:"calcSparseMatrix"}}),R=new Uint32Array(I),C=new Uint32Array(I),U=new Uint32Array(I),P=new Uint32Array(I),$=Math.floor(B/I);let j=0,_=1;console.time("GPUthreadStarts");for(let n=0;n<I;n++){const e=9999===n?B-1:(n+1)*$,t=g-2-Math.floor(Math.sqrt(-8*e+4*g*(g-1)-7)/2-.5),r=e-g*t+Math.floor((t+1)*(t+2)/2);R[n]=_,C[n]=j,U[n]=r,P[n]=t,j=t,_=r}console.timeEnd("GPUthreadStarts");const D=4e4+g*h+h+y.reduce(((n,e)=>n+e.sourceArraySize),0),z=y.reduce(((n,e)=>n+e.suppInfoSize),0),Y=1e6,G=D*Uint32Array.BYTES_PER_ELEMENT;let k=G;const F=15&G;0!==F&&(k+=16-F);const H=c.createBuffer({label:"compute info buffer",size:k,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST,mappedAtCreation:!0}),W=H.getMappedRange();let q=0;new Uint32Array(W,q,I).set(R),q+=I*Uint32Array.BYTES_PER_ELEMENT,new Uint32Array(W,q,I).set(C),q+=I*Uint32Array.BYTES_PER_ELEMENT,new Uint32Array(W,q,I).set(U),q+=I*Uint32Array.BYTES_PER_ELEMENT,new Uint32Array(W,q,I).set(P),q+=I*Uint32Array.BYTES_PER_ELEMENT,new Uint32Array(W,q,w.length).set(w),q+=w.length*Uint32Array.BYTES_PER_ELEMENT,new Float32Array(W,q,h).set(o),q+=h*Float32Array.BYTES_PER_ELEMENT;for(const n of y){const e=n.EncodedArrayConstructor,t=n.sourceArraySize;new e(W,q,t).set(n.flatSourceArray),q+=t*e.BYTES_PER_ELEMENT}H.unmap();const V=z*Uint32Array.BYTES_PER_ELEMENT;let K=V;const X=15&V;0!==X&&(K+=16-X),K=Math.max(K,16);const Z=c.createBuffer({label:"supp info buffer",size:K,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST,mappedAtCreation:!0}),J=Z.getMappedRange();let Q=0;for(const n of y)n.suppInfoBuffer&&n.suppInfoBuffer.byteLength>0&&n.suppInfoSize>0&&(new("UINT32ARRAY"===n.suppInfoType?Uint32Array:Float32Array)(J,Q,n.suppInfoBuffer.length).set(n.suppInfoBuffer),Q+=n.suppInfoBuffer.byteLength);0===Q&&new Uint32Array(J,0,4).set([1,1,1,1]),Z.unmap();const nn=302e4*Uint32Array.BYTES_PER_ELEMENT;let en=nn;const tn=15&nn;0!==tn&&(en+=16-tn);const rn=c.createBuffer({label:"results buffer",size:en,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),an=c.createBindGroup({label:"bindGroup for sparse matrix buffer",layout:O.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:H}},{binding:1,resource:{buffer:Z}},{binding:2,resource:{buffer:rn}}]}),on=c.createBuffer({label:"results out buffer",size:rn.size,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),sn=[],un=[],ln=[];let cn=!1;for(;!cn;){const n=c.createCommandEncoder({label:"distance encoder"}),e=n.beginComputePass({label:"distance compute pass"});e.setPipeline(O),e.setBindGroup(0,an),e.dispatchWorkgroups(N,N),e.end(),n.copyBufferToBuffer(rn,0,on,0,on.size);const t=n.finish();c.queue.submit([t]),yield c.queue.onSubmittedWorkDone(),yield on.mapAsync(GPUMapMode.READ);const r=on.getMappedRange();let a=0;const i=new Uint32Array(r,a,Y);a+=Y*Uint32Array.BYTES_PER_ELEMENT;const o=new Uint32Array(r,a,Y);a+=Y*Uint32Array.BYTES_PER_ELEMENT;const s=new Float32Array(r,a,Y);a+=Y*Float32Array.BYTES_PER_ELEMENT;const u=new Uint32Array(r,a,I);a+=I*Uint32Array.BYTES_PER_ELEMENT,cn=new Uint32Array(r,a,I).every((n=>1===n));const l=u.reduce(((n,e)=>n+e),0),f=new Uint32Array(l),m=new Uint32Array(l),d=new Float32Array(l);let p=0;for(let n=0;n<u.length;n++){const e=u[n];0!==e&&(f.set(i.subarray(n*x,n*x+e),p),m.set(o.subarray(n*x,n*x+e),p),d.set(s.subarray(n*x,n*x+e),p),p+=e)}sn.push(f),un.push(m),ln.push(d),on.unmap()}const fn=sn.reduce(((n,e)=>n+e.length),0),mn=new Uint32Array(fn),dn=new Uint32Array(fn),pn=new Float32Array(fn);let hn=0;for(let n=0;n<sn.length;n++)mn.set(sn[n],hn),dn.set(un[n],hn),pn.set(ln[n],hn),hn+=sn[n].length;return c.destroy(),{i:mn,j:dn,distance:pn}}))}(e,t/100,p,o,a,d)}catch(n){console.error(n)}A||(y&&console.error("WEBGPU sparse matrix calculation failed, falling back to CPU implementation"),A=await(new m._).calcMultiColumn(e,p,t/100,d,a,o)),console.timeEnd("sparse matrix");const b=await new h({maxIterations:g??5}).transform(A,e[0].length);postMessage({res:b})}},6814:(n,e,t)=>{t.d(e,{cZ:()=>a,kK:()=>r}),t(7862);const r=n=>null==n;function a(n,e,t,r){if(t>n[n.length-1])return;const a=n.findIndex((n=>t<n));n.pop(),n.splice(a,0,t),e.pop(),e.splice(a,0,r)}}},r={};function a(n){var e=r[n];if(void 0!==e)return e.exports;var i=r[n]={exports:{}};return t[n](i,i.exports,a),i.exports}a.m=t,a.x=()=>{var n=a.O(void 0,[590],(()=>a(8960)));return a.O(n)},n=[],a.O=(e,t,r,i)=>{if(!t){var o=1/0;for(c=0;c<n.length;c++){for(var[t,r,i]=n[c],s=!0,u=0;u<t.length;u++)(!1&i||o>=i)&&Object.keys(a.O).every((n=>a.O[n](t[u])))?t.splice(u--,1):(s=!1,i<o&&(o=i));if(s){n.splice(c--,1);var l=r();void 0!==l&&(e=l)}}return e}i=i||0;for(var c=n.length;c>0&&n[c-1][2]>i;c--)n[c]=n[c-1];n[c]=[t,r,i]},a.d=(n,e)=>{for(var t in e)a.o(e,t)&&!a.o(n,t)&&Object.defineProperty(n,t,{enumerable:!0,get:e[t]})},a.f={},a.e=n=>Promise.all(Object.keys(a.f).reduce(((e,t)=>(a.f[t](n,e),e)),[])),a.u=n=>n+".js",a.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"==typeof window)return window}}(),a.o=(n,e)=>Object.prototype.hasOwnProperty.call(n,e),(()=>{var n;a.g.importScripts&&(n=a.g.location+"");var e=a.g.document;if(!n&&e&&(e.currentScript&&(n=e.currentScript.src),!n)){var t=e.getElementsByTagName("script");if(t.length)for(var r=t.length-1;r>-1&&!n;)n=t[r--].src}if(!n)throw new Error("Automatic publicPath is not supported in this browser");n=n.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),a.p=n})(),(()=>{a.b=self.location+"";var n={246:1};a.f.i=(e,t)=>{n[e]||importScripts(a.p+a.u(e))};var e=self.webpackChunkbio=self.webpackChunkbio||[],t=e.push.bind(e);e.push=e=>{var[r,i,o]=e;for(var s in i)a.o(i,s)&&(a.m[s]=i[s]);for(o&&o(a);r.length;)n[r.pop()]=1;t(e)}})(),e=a.x,a.x=()=>a.e(590).then(e);var i=a.x();bio=i})();
2
- //# sourceMappingURL=246.js.map