New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

umap-js

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

umap-js - npm Package Compare versions

Comparing version 1.0.3 to 1.0.4

.prettierignore

10

dist/matrix.d.ts

@@ -13,2 +13,3 @@ export declare class SparseMatrix {

get(row: number, col: number, defaultValue?: number): number;
getDims(): number[];
getRows(): number[];

@@ -23,5 +24,12 @@ getCols(): number[];

export declare function identity(size: number[]): SparseMatrix;
export declare function dotMultiply(a: SparseMatrix, b: SparseMatrix): SparseMatrix;
export declare function pairwiseMultiply(a: SparseMatrix, b: SparseMatrix): SparseMatrix;
export declare function add(a: SparseMatrix, b: SparseMatrix): SparseMatrix;
export declare function subtract(a: SparseMatrix, b: SparseMatrix): SparseMatrix;
export declare function multiplyScalar(a: SparseMatrix, scalar: number): SparseMatrix;
export declare function eliminateZeros(m: SparseMatrix): SparseMatrix;
export declare function normalize(m: SparseMatrix, normType?: NormType): SparseMatrix;
export declare const enum NormType {
max = "max",
l1 = "l1",
l2 = "l2"
}
"use strict";
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
};
Object.defineProperty(exports, "__esModule", { value: true });
var _a;
var utils = require("./utils");
var SparseMatrix = (function () {

@@ -8,5 +40,5 @@ function SparseMatrix(rows, cols, values, dims) {

this.nCols = 0;
this.rows = rows.slice();
this.cols = cols.slice();
this.values = values.slice();
this.rows = __spread(rows);
this.cols = __spread(cols);
this.values = __spread(values);
for (var i = 0; i < values.length; i++) {

@@ -54,10 +86,13 @@ var key = this.makeKey(this.rows[i], this.cols[i]);

};
SparseMatrix.prototype.getDims = function () {
return [this.nRows, this.nCols];
};
SparseMatrix.prototype.getRows = function () {
return this.rows.slice();
return __spread(this.rows);
};
SparseMatrix.prototype.getCols = function () {
return this.cols.slice();
return __spread(this.cols);
};
SparseMatrix.prototype.getValues = function () {
return this.values.slice();
return __spread(this.values);
};

@@ -79,6 +114,5 @@ SparseMatrix.prototype.forEach = function (fn) {

var _this = this;
var rows = new Array(this.nRows).slice();
var rows = utils.empty(this.nRows);
var output = rows.map(function () {
var cols = new Array(_this.nCols).slice();
return cols.map(function () { return 0; });
return utils.zeros(_this.nCols);
});

@@ -107,3 +141,3 @@ for (var i = 0; i < this.values.length; i++) {

function identity(size) {
var rows = size[0];
var _a = __read(size, 1), rows = _a[0];
var matrix = new SparseMatrix([], [], [], size);

@@ -116,6 +150,6 @@ for (var i = 0; i < rows; i++) {

exports.identity = identity;
function dotMultiply(a, b) {
function pairwiseMultiply(a, b) {
return elementWise(a, b, function (x, y) { return x * y; });
}
exports.dotMultiply = dotMultiply;
exports.pairwiseMultiply = pairwiseMultiply;
function add(a, b) {

@@ -135,2 +169,77 @@ return elementWise(a, b, function (x, y) { return x + y; });

exports.multiplyScalar = multiplyScalar;
function eliminateZeros(m) {
var zeroIndices = new Set();
var values = m.getValues();
var rows = m.getRows();
var cols = m.getCols();
for (var i = 0; i < values.length; i++) {
if (values[i] === 0) {
zeroIndices.add(i);
}
}
var removeByZeroIndex = function (_, index) { return !zeroIndices.has(index); };
var nextValues = values.filter(removeByZeroIndex);
var nextRows = rows.filter(removeByZeroIndex);
var nextCols = cols.filter(removeByZeroIndex);
return new SparseMatrix(nextRows, nextCols, nextValues, m.getDims());
}
exports.eliminateZeros = eliminateZeros;
function normalize(m, normType) {
if (normType === void 0) { normType = "l2"; }
var e_1, _a;
var normFn = normFns[normType];
var colsByRow = new Map();
m.forEach(function (_, row, col) {
var cols = colsByRow.get(row) || [];
cols.push(col);
colsByRow.set(row, cols);
});
var nextMatrix = new SparseMatrix([], [], [], m.getDims());
var _loop_1 = function (row) {
var cols = colsByRow.get(row).sort();
var vals = cols.map(function (col) { return m.get(row, col); });
var norm = normFn(vals);
for (var i = 0; i < norm.length; i++) {
nextMatrix.set(row, cols[i], norm[i]);
}
};
try {
for (var _b = __values(colsByRow.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
var row = _c.value;
_loop_1(row);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
return nextMatrix;
}
exports.normalize = normalize;
var normFns = (_a = {},
_a["max"] = function (xs) {
var max = -Infinity;
for (var i = 0; i < xs.length; i++) {
max = xs[i] > max ? xs[i] : max;
}
return xs.map(function (x) { return x / max; });
},
_a["l1"] = function (xs) {
var sum = 0;
for (var i = 0; i < xs.length; i++) {
sum += xs[i];
}
return xs.map(function (x) { return x / sum; });
},
_a["l2"] = function (xs) {
var sum = 0;
for (var i = 0; i < xs.length; i++) {
sum += Math.pow(xs[i], 2);
}
return xs.map(function (x) { return Math.sqrt(Math.pow(x, 2) / sum); });
},
_a);
function elementWise(a, b, op) {

@@ -137,0 +246,0 @@ var visited = new Set();

"use strict";
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -124,3 +154,3 @@ var utils = require("./utils");

children[nodeNum][0] = -leafNum;
(_a = indices[leafNum]).splice.apply(_a, [0, tree.indices.length].concat(tree.indices));
(_a = indices[leafNum]).splice.apply(_a, __spread([0, tree.indices.length], tree.indices));
leafNum += 1;

@@ -159,8 +189,18 @@ return { nodeNum: nodeNum, leafNum: leafNum };

function makeLeafArray(rpForest) {
var e_1, _a;
if (rpForest.length > 0) {
var output = [];
for (var _i = 0, rpForest_1 = rpForest; _i < rpForest_1.length; _i++) {
var tree = rpForest_1[_i];
output.push.apply(output, tree.indices);
try {
for (var rpForest_1 = __values(rpForest), rpForest_1_1 = rpForest_1.next(); !rpForest_1_1.done; rpForest_1_1 = rpForest_1.next()) {
var tree = rpForest_1_1.value;
output.push.apply(output, __spread(tree.indices));
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (rpForest_1_1 && !rpForest_1_1.done && (_a = rpForest_1.return)) _a.call(rpForest_1);
}
finally { if (e_1) throw e_1.error; }
}
return output;

@@ -167,0 +207,0 @@ }

@@ -0,1 +1,2 @@

import * as matrix from './matrix';
export declare type DistanceFn = (x: Vector, y: Vector) => number;

@@ -5,3 +6,9 @@ export declare type EpochCallback = (epoch: number) => boolean | void;

export declare type Vectors = Vector[];
export declare const enum TargetMetric {
categorical = "categorical",
l1 = "l1",
l2 = "l2"
}
export interface UMAPParameters {
minDist?: number;
nComponents?: number;

@@ -11,8 +18,19 @@ nEpochs?: number;

random?: () => number;
spread?: number;
}
export interface UMAPSupervisedParams {
targetMetric?: TargetMetric;
targetWeight?: number;
targetNNeighbors?: number;
}
export declare class UMAP {
private nNeighbors;
private minDist;
private nComponents;
private nEpochs;
private nNeighbors;
private random;
private spread;
private targetMetric;
private targetWeight;
private targetNNeighbors;
private distanceFn;

@@ -22,4 +40,5 @@ private knnIndices?;

private graph;
private data;
private X;
private isInitialized;
private Y?;
private embedding;

@@ -30,3 +49,6 @@ private optimizationState;

fitAsync(X: Vectors, callback?: (epochNumber: number) => void | boolean): Promise<number[][]>;
initializeFit(X: Vectors, knnIndices?: number[][], knnDistances?: number[][]): number;
setSupervisedProjection(Y: number[], params?: UMAPSupervisedParams): void;
setPrecomputedKNN(knnIndices: number[][], knnDistances: number[][]): void;
initializeFit(X: Vectors): number;
private processGraphForSupervisedProjection;
step(): number;

@@ -36,2 +58,3 @@ getEmbedding(): number[][];

private fuzzySimplicialSet;
private categoricalSimplicialSetIntersection;
private smoothKNNDistance;

@@ -48,1 +71,7 @@ private computeMembershipStrengths;

export declare function cosine(x: Vector, y: Vector): number;
export declare function findABParams(spread: number, minDist: number): {
a: number;
b: number;
};
export declare function fastIntersection(graph: matrix.SparseMatrix, target: number[], unknownDist?: number, farDist?: number): matrix.SparseMatrix;
export declare function resetLocalConnectivity(simplicialSet: matrix.SparseMatrix): matrix.SparseMatrix;

@@ -37,2 +37,22 @@ "use strict";

};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -43,2 +63,3 @@ var matrix = require("./matrix");

var utils = require("./utils");
var LM = require("ml-levenberg-marquardt");
var SMOOTH_K_TOLERANCE = 1e-5;

@@ -49,6 +70,11 @@ var MIN_K_DIST_SCALE = 1e-3;

if (params === void 0) { params = {}; }
this.nNeighbors = 15;
this.minDist = 0.1;
this.nComponents = 2;
this.nEpochs = 0;
this.nNeighbors = 15;
this.random = Math.random;
this.spread = 1.0;
this.targetMetric = "categorical";
this.targetWeight = 0.5;
this.targetNNeighbors = this.nNeighbors;
this.distanceFn = euclidean;

@@ -58,2 +84,3 @@ this.isInitialized = false;

this.optimizationState = new OptimizationState();
this.minDist = params.minDist || this.minDist;
this.nComponents = params.nComponents || this.nComponents;

@@ -63,2 +90,3 @@ this.nEpochs = params.nEpochs || this.nEpochs;

this.random = params.random || this.random;
this.spread = params.spread || this.spread;
}

@@ -85,12 +113,19 @@ UMAP.prototype.fit = function (X) {

};
UMAP.prototype.initializeFit = function (X, knnIndices, knnDistances) {
if (this.data === X && this.isInitialized) {
UMAP.prototype.setSupervisedProjection = function (Y, params) {
if (params === void 0) { params = {}; }
this.Y = Y;
this.targetMetric = params.targetMetric || this.targetMetric;
this.targetWeight = params.targetWeight || this.targetWeight;
this.targetNNeighbors = params.targetNNeighbors || this.targetNNeighbors;
};
UMAP.prototype.setPrecomputedKNN = function (knnIndices, knnDistances) {
this.knnIndices = knnIndices;
this.knnDistances = knnDistances;
};
UMAP.prototype.initializeFit = function (X) {
if (this.X === X && this.isInitialized) {
return this.getNEpochs();
}
this.data = X;
if (knnIndices && knnDistances) {
this.knnIndices = knnIndices;
this.knnDistances = knnDistances;
}
else {
this.X = X;
if (!this.knnIndices && !this.knnDistances) {
var knnResults = this.nearestNeighbors(X);

@@ -100,3 +135,4 @@ this.knnIndices = knnResults.knnIndices;

}
this.graph = this.fuzzySimplicialSet(X);
this.graph = this.fuzzySimplicialSet(X, this.nNeighbors);
this.processGraphForSupervisedProjection();
var _a = this.initializeSimplicialSetEmbedding(), head = _a.head, tail = _a.tail, epochsPerSample = _a.epochsPerSample;

@@ -109,2 +145,15 @@ this.optimizationState.head = head;

};
UMAP.prototype.processGraphForSupervisedProjection = function () {
var _a = this, Y = _a.Y, X = _a.X;
if (Y) {
if (Y.length !== X.length) {
throw new Error('Length of X and y must be equal');
}
if (this.targetMetric === "categorical") {
var lt = this.targetWeight < 1.0;
var farDist = lt ? 2.5 * (1.0 / (1.0 - this.targetWeight)) : 1.0e12;
this.graph = this.categoricalSimplicialSetIntersection(this.graph, Y, farDist);
}
}
};
UMAP.prototype.step = function () {

@@ -137,6 +186,6 @@ var _a = this.optimizationState, currentEpoch = _a.currentEpoch, isInitialized = _a.isInitialized;

};
UMAP.prototype.fuzzySimplicialSet = function (X, localConnectivity, setOpMixRatio) {
UMAP.prototype.fuzzySimplicialSet = function (X, nNeighbors, localConnectivity, setOpMixRatio) {
if (localConnectivity === void 0) { localConnectivity = 1.0; }
if (setOpMixRatio === void 0) { setOpMixRatio = 1.0; }
var _a = this, nNeighbors = _a.nNeighbors, _b = _a.knnIndices, knnIndices = _b === void 0 ? [] : _b, _c = _a.knnDistances, knnDistances = _c === void 0 ? [] : _c;
var _a = this, _b = _a.knnIndices, knnIndices = _b === void 0 ? [] : _b, _c = _a.knnDistances, knnDistances = _c === void 0 ? [] : _c;
var _d = this.smoothKNNDistance(knnDistances, nNeighbors, localConnectivity), sigmas = _d.sigmas, rhos = _d.rhos;

@@ -147,3 +196,3 @@ var _e = this.computeMembershipStrengths(knnIndices, knnDistances, sigmas, rhos), rows = _e.rows, cols = _e.cols, vals = _e.vals;

var transpose = matrix.transpose(sparseMatrix);
var prodMatrix = matrix.dotMultiply(sparseMatrix, transpose);
var prodMatrix = matrix.pairwiseMultiply(sparseMatrix, transpose);
var a = matrix.subtract(matrix.add(sparseMatrix, transpose), prodMatrix);

@@ -155,2 +204,8 @@ var b = matrix.multiplyScalar(a, setOpMixRatio);

};
UMAP.prototype.categoricalSimplicialSetIntersection = function (simplicialSet, target, farDist, unknownDist) {
if (unknownDist === void 0) { unknownDist = 1.0; }
var intersection = fastIntersection(simplicialSet, target, unknownDist, farDist);
intersection = matrix.eliminateZeros(intersection);
return resetLocalConnectivity(intersection);
};
UMAP.prototype.smoothKNNDistance = function (distances, k, localConnectivity, nIter, bandwidth) {

@@ -318,4 +373,3 @@ if (localConnectivity === void 0) { localConnectivity = 1.0; }

var nVertices = this.graph.nCols;
var a = 1.5769434603113077;
var b = 0.8950608779109733;
var _b = findABParams(this.spread, this.minDist), a = _b.a, b = _b.b;
var dim = headEmbedding[0].length;

@@ -325,4 +379,4 @@ var moveOther = headEmbedding.length === tailEmbedding.length;

var epochsPerNegativeSample = epochsPerSample.map(function (e) { return e / negativeSampleRate; });
var epochOfNextNegativeSample = epochsPerNegativeSample.slice();
var epochOfNextSample = epochsPerSample.slice();
var epochOfNextNegativeSample = __spread(epochsPerNegativeSample);
var epochOfNextSample = __spread(epochsPerSample);
Object.assign(this.optimizationState, {

@@ -524,1 +578,53 @@ isInitialized: true,

}
function findABParams(spread, minDist) {
var curve = function (_a) {
var _b = __read(_a, 2), a = _b[0], b = _b[1];
return function (x) {
return 1.0 / (1.0 + a * Math.pow(x, (2 * b)));
};
};
var xv = utils
.linear(0, spread * 3, 300)
.map(function (val) { return (val < minDist ? 1.0 : val); });
var yv = utils.zeros(xv.length).map(function (val, index) {
var gte = xv[index] >= minDist;
return gte ? Math.exp(-(xv[index] - minDist) / spread) : val;
});
var initialValues = [0.5, 0.5];
var data = { x: xv, y: yv };
var options = {
damping: 1.5,
initialValues: initialValues,
gradientDifference: 10e-2,
maxIterations: 100,
errorTolerance: 10e-3,
};
var parameterValues = LM(data, curve, options).parameterValues;
var _a = __read(parameterValues, 2), a = _a[0], b = _a[1];
return { a: a, b: b };
}
exports.findABParams = findABParams;
function fastIntersection(graph, target, unknownDist, farDist) {
if (unknownDist === void 0) { unknownDist = 1.0; }
if (farDist === void 0) { farDist = 5.0; }
return graph.map(function (value, row, col) {
if (target[row] === -1 || target[col] === -1) {
return value * Math.exp(-unknownDist);
}
else if (target[row] !== target[col]) {
return value * Math.exp(-farDist);
}
else {
return value;
}
});
}
exports.fastIntersection = fastIntersection;
function resetLocalConnectivity(simplicialSet) {
simplicialSet = matrix.normalize(simplicialSet, "max");
var transpose = matrix.transpose(simplicialSet);
var prodMatrix = matrix.pairwiseMultiply(transpose, simplicialSet);
simplicialSet = matrix.add(simplicialSet, matrix.subtract(transpose, prodMatrix));
return matrix.eliminateZeros(simplicialSet);
}
exports.resetLocalConnectivity = resetLocalConnectivity;

@@ -10,2 +10,3 @@ export declare function randomNormal2d(mean?: number, stdev?: number, size?: number[], rng?: () => number): number[][];

export declare function ones(n: number): number[];
export declare function linear(a: number, b: number, len: number): number[];
export declare function sum(input: number[]): number;

@@ -12,0 +13,0 @@ export declare function mean(input: number[]): number;

"use strict";
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -35,7 +45,17 @@ function generateGaussian(mean, std, rng) {

function norm(vec) {
var e_1, _a;
var result = 0;
for (var _i = 0, vec_1 = vec; _i < vec_1.length; _i++) {
var item = vec_1[_i];
result += Math.pow(item, 2);
try {
for (var vec_1 = __values(vec), vec_1_1 = vec_1.next(); !vec_1_1.done; vec_1_1 = vec_1.next()) {
var item = vec_1_1.value;
result += Math.pow(item, 2);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (vec_1_1 && !vec_1_1.done && (_a = vec_1.return)) _a.call(vec_1);
}
finally { if (e_1) throw e_1.error; }
}
return Math.sqrt(result);

@@ -68,2 +88,8 @@ }

exports.ones = ones;
function linear(a, b, len) {
return empty(len).map(function (_, i) {
return a + i * ((b - a) / (len - 1));
});
}
exports.linear = linear;
function sum(input) {

@@ -70,0 +96,0 @@ return input.reduce(function (sum, val) { return sum + val; });

3

jest.config.js

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.

@@ -20,2 +20,1 @@ Licensed under the Apache License, Version 2.0 (the "License");

};
{
"name": "umap-js",
"version": "1.0.3",
"version": "1.0.4",
"description": "JavaScript implementation of UMAP",

@@ -21,3 +21,2 @@ "author": {

"@types/node": "^10.12.21",
"dts-bundle-webpack": "^1.0.2",
"jest": "23",

@@ -33,3 +32,5 @@ "prando": "^5.1.0",

},
"dependencies": {},
"dependencies": {
"ml-levenberg-marquardt": "^1.0.3"
},
"publishConfig": {

@@ -36,0 +37,0 @@ "registry": "https://wombat-dressing-room.appspot.com"

@@ -0,1 +1,3 @@

[![Build Status](https://travis-ci.org/PAIR-code/umap-js.svg?branch=master)](https://travis-ci.org/PAIR-code/umap-js)
# UMAP-JS

@@ -53,2 +55,12 @@

#### Supervised projection using labels
```typescript
import { UMAP } from 'umap-js';
const umap = new UMAP();
umap.setSupervisedProjection(labels);
const embedding = umap.fit(data);
```
#### Parameters

@@ -58,8 +70,10 @@

| Parameter | Description | default |
| ------------- | --------------------------------------------------------------------- | ------------------------ |
| `nComponents` | The number of components (dimensions) to project the data to | 2 |
| `nEpochs` | The number of epochs to optimize embeddings via SGD | (computed automatically) |
| `nNeigbors` | The number of nearest neigbors to construct the fuzzy manifold | 15 |
| `random` | A pseudo-random-number generator for controlling stochastic processes | `Math.random` |
| Parameter | Description | default |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
| `nComponents` | The number of components (dimensions) to project the data to | 2 |
| `nEpochs` | The number of epochs to optimize embeddings via SGD | (computed automatically) |
| `nNeigbors` | The number of nearest neigbors to construct the fuzzy manifold | 15 |
| `minDist` | The effective minimum distance between embedded points, used with `spread` to control the clumped/dispersed nature of the embedding | 0.1 |
| `spread` | The effective scale of embedded points, used with `minDist` to control the clumped/dispersed nature of the embedding | 1.0 |
| `random` | A pseudo-random-number generator for controlling stochastic processes | `Math.random` |

@@ -66,0 +80,0 @@ ```typescript

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.

@@ -3,0 +3,0 @@ Licensed under the Apache License, Version 2.0 (the "License");

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");

@@ -3,0 +3,0 @@ you may not use this file except in compliance with the License.

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");

@@ -3,0 +3,0 @@ you may not use this file except in compliance with the License.

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.

@@ -16,2 +16,4 @@ Licensed under the Apache License, Version 2.0 (the "License");

import * as utils from './utils';
/**

@@ -87,2 +89,6 @@ * Internal 2-dimensional sparse matrix class

getDims(): number[] {
return [this.nRows, this.nCols];
}
getRows(): number[] {

@@ -116,6 +122,5 @@ return [...this.rows];

toArray() {
const rows: number[][] = [...new Array(this.nRows)];
const rows: undefined[] = utils.empty(this.nRows);
const output = rows.map(() => {
const cols = [...new Array(this.nCols)];
return cols.map(() => 0);
return utils.zeros(this.nCols);
});

@@ -162,3 +167,6 @@ for (let i = 0; i < this.values.length; i++) {

*/
export function dotMultiply(a: SparseMatrix, b: SparseMatrix): SparseMatrix {
export function pairwiseMultiply(
a: SparseMatrix,
b: SparseMatrix
): SparseMatrix {
return elementWise(a, b, (x, y) => x * y);

@@ -191,2 +199,85 @@ }

/**
* Returns a new matrix with zero entries removed.
*/
export function eliminateZeros(m: SparseMatrix) {
const zeroIndices = new Set();
const values = m.getValues();
const rows = m.getRows();
const cols = m.getCols();
for (let i = 0; i < values.length; i++) {
if (values[i] === 0) {
zeroIndices.add(i);
}
}
const removeByZeroIndex = (_, index: number) => !zeroIndices.has(index);
const nextValues = values.filter(removeByZeroIndex);
const nextRows = rows.filter(removeByZeroIndex);
const nextCols = cols.filter(removeByZeroIndex);
return new SparseMatrix(nextRows, nextCols, nextValues, m.getDims());
}
/**
* Normalization of a sparse matrix.
*/
export function normalize(m: SparseMatrix, normType = NormType.l2) {
const normFn = normFns[normType];
const colsByRow = new Map<number, number[]>();
m.forEach((_, row, col) => {
const cols = colsByRow.get(row) || [];
cols.push(col);
colsByRow.set(row, cols);
});
const nextMatrix = new SparseMatrix([], [], [], m.getDims());
for (let row of colsByRow.keys()) {
const cols = colsByRow.get(row)!.sort();
const vals = cols.map(col => m.get(row, col));
const norm = normFn(vals);
for (let i = 0; i < norm.length; i++) {
nextMatrix.set(row, cols[i], norm[i]);
}
}
return nextMatrix;
}
/**
* Vector normalization functions
*/
type NormFns = { [key in NormType]: (v: number[]) => number[] };
const normFns: NormFns = {
[NormType.max]: (xs: number[]) => {
let max = -Infinity;
for (let i = 0; i < xs.length; i++) {
max = xs[i] > max ? xs[i] : max;
}
return xs.map(x => x / max);
},
[NormType.l1]: (xs: number[]) => {
let sum = 0;
for (let i = 0; i < xs.length; i++) {
sum += xs[i];
}
return xs.map(x => x / sum);
},
[NormType.l2]: (xs: number[]) => {
let sum = 0;
for (let i = 0; i < xs.length; i++) {
sum += xs[i] ** 2;
}
return xs.map(x => Math.sqrt(x ** 2 / sum));
},
};
export const enum NormType {
max = 'max',
l1 = 'l1',
l2 = 'l2',
}
/**
* Helper function for element-wise operations.

@@ -193,0 +284,0 @@ */

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.

@@ -3,0 +3,0 @@ Licensed under the Apache License, Version 2.0 (the "License");

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.

@@ -3,0 +3,0 @@ Licensed under the Apache License, Version 2.0 (the "License");

@@ -1,9 +0,6 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software

@@ -60,2 +57,3 @@ distributed under the License is distributed on an "AS IS" BASIS,

import * as utils from './utils';
import * as LM from 'ml-levenberg-marquardt';

@@ -66,2 +64,7 @@ export type DistanceFn = (x: Vector, y: Vector) => number;

export type Vectors = Vector[];
export const enum TargetMetric {
categorical = 'categorical',
l1 = 'l1',
l2 = 'l2',
}

@@ -72,8 +75,71 @@ const SMOOTH_K_TOLERANCE = 1e-5;

export interface UMAPParameters {
/**
* The effective minimum distance between embedded points. Smaller values
* will result in a more clustered/clumped embedding where nearby points
* on the manifold are drawn closer together, while larger values will
* result on a more even dispersal of points. The value should be set
* relative to the ``spread`` value, which determines the scale at which
* embedded points will be spread out.
*/
minDist?: number;
/**
* The dimension of the space to embed into. This defaults to 2 to
* provide easy visualization, but can reasonably be set to any
* integer value in the range 2 to 100.
*/
nComponents?: number;
/**
* The number of training epochs to be used in optimizing the
* low dimensional embedding. Larger values result in more accurate
* embeddings. If None is specified a value will be selected based on
* the size of the input dataset (200 for large datasets, 500 for small).
*/
nEpochs?: number;
/**
* The size of local neighborhood (in terms of number of neighboring
* sample points) used for manifold approximation. Larger values
* result in more global views of the manifold, while smaller
* values result in more local data being preserved. In general
* values should be in the range 2 to 100.
*/
nNeighbors?: number;
/**
* The pseudo-random number generator used by the stochastic parts of the
* algorithm.
*/
random?: () => number;
/**
* The effective scale of embedded points. In combination with ``min_dist``
* this determines how clustered/clumped the embedded points are.
*/
spread?: number;
}
export interface UMAPSupervisedParams {
/**
* The metric used to measure distance for a target array is using supervised
* dimension reduction. By default this is 'categorical' which will measure
* distance in terms of whether categories match or are different. Furthermore,
* if semi-supervised is required target values of -1 will be treated as
* unlabelled under the 'categorical' metric. If the target array takes
* continuous values (e.g. for a regression problem) then metric of 'l1'
* or 'l2' is probably more appropriate.
*/
targetMetric?: TargetMetric;
/**
* Weighting factor between data topology and target topology. A value of
* 0.0 weights entirely on data, a value of 1.0 weights entirely on target.
* The default of 0.5 balances the weighting equally between data and target.
*/
targetWeight?: number;
/**
* The number of nearest neighbors to use to construct the target simplcial
* set. Defaults to the `nearestNeighbors` parameter.
*/
targetNNeighbors?: number;
}
/**

@@ -102,7 +168,14 @@ * UMAP projection system, based on the python implementation from McInnes, L,

export class UMAP {
private nNeighbors = 15;
private minDist = 0.1;
private nComponents = 2;
private nEpochs = 0;
private nNeighbors = 15;
private random = Math.random;
private spread = 1.0;
// Supervised projection params
private targetMetric = TargetMetric.categorical;
private targetWeight = 0.5;
private targetNNeighbors = this.nNeighbors;
private distanceFn: DistanceFn = euclidean;

@@ -116,5 +189,8 @@

private graph!: matrix.SparseMatrix;
private data!: Vectors;
private X!: Vectors;
private isInitialized = false;
// Supervised projection labels / targets
private Y?: number[];
// Projected embedding

@@ -125,2 +201,3 @@ private embedding: number[][] = [];

constructor(params: UMAPParameters = {}) {
this.minDist = params.minDist || this.minDist;
this.nComponents = params.nComponents || this.nComponents;

@@ -130,2 +207,3 @@ this.nEpochs = params.nEpochs || this.nEpochs;

this.random = params.random || this.random;
this.spread = params.spread || this.spread;
}

@@ -158,2 +236,20 @@

/**
* Initializes parameters needed for supervised projection.
*/
setSupervisedProjection(Y: number[], params: UMAPSupervisedParams = {}) {
this.Y = Y;
this.targetMetric = params.targetMetric || this.targetMetric;
this.targetWeight = params.targetWeight || this.targetWeight;
this.targetNNeighbors = params.targetNNeighbors || this.targetNNeighbors;
}
/**
* Initializes umap with precomputed KNN indices and distances.
*/
setPrecomputedKNN(knnIndices: number[][], knnDistances: number[][]) {
this.knnIndices = knnIndices;
this.knnDistances = knnDistances;
}
/**
* Initializes fit by computing KNN and a fuzzy simplicial set, as well as

@@ -164,18 +260,11 @@ * initializing the projected embeddings. Sets the optimization state ahead

*/
initializeFit(
X: Vectors,
knnIndices?: number[][],
knnDistances?: number[][]
): number {
initializeFit(X: Vectors): number {
// We don't need to reinitialize if we've already initialized for this data.
if (this.data === X && this.isInitialized) {
if (this.X === X && this.isInitialized) {
return this.getNEpochs();
}
this.data = X;
this.X = X;
if (knnIndices && knnDistances) {
this.knnIndices = knnIndices;
this.knnDistances = knnDistances;
} else {
if (!this.knnIndices && !this.knnDistances) {
const knnResults = this.nearestNeighbors(X);

@@ -186,4 +275,7 @@ this.knnIndices = knnResults.knnIndices;

this.graph = this.fuzzySimplicialSet(X);
this.graph = this.fuzzySimplicialSet(X, this.nNeighbors);
// Check if supervised projection, then adjust the graph.
this.processGraphForSupervisedProjection();
const {

@@ -205,2 +297,26 @@ head,

/**
* Checks if we're using supervised projection, then process the graph
* accordingly.
*/
private processGraphForSupervisedProjection() {
const { Y, X } = this;
if (Y) {
if (Y.length !== X.length) {
throw new Error('Length of X and y must be equal');
}
if (this.targetMetric === TargetMetric.categorical) {
const lt = this.targetWeight < 1.0;
const farDist = lt ? 2.5 * (1.0 / (1.0 - this.targetWeight)) : 1.0e12;
this.graph = this.categoricalSimplicialSetIntersection(
this.graph,
Y,
farDist
);
}
// TODO (andycoenen@): add non-categorical supervised embeddings.
}
}
/**
* Manually step through the optimization process one epoch at a time.

@@ -267,6 +383,7 @@ */

X: Vectors,
nNeighbors: number,
localConnectivity = 1.0,
setOpMixRatio = 1.0
) {
const { nNeighbors, knnIndices = [], knnDistances = [] } = this;
const { knnIndices = [], knnDistances = [] } = this;

@@ -290,3 +407,3 @@ const { sigmas, rhos } = this.smoothKNNDistance(

const transpose = matrix.transpose(sparseMatrix);
const prodMatrix = matrix.dotMultiply(sparseMatrix, transpose);
const prodMatrix = matrix.pairwiseMultiply(sparseMatrix, transpose);

@@ -302,2 +419,24 @@ const a = matrix.subtract(matrix.add(sparseMatrix, transpose), prodMatrix);

/**
* Combine a fuzzy simplicial set with another fuzzy simplicial set
* generated from categorical data using categorical distances. The target
* data is assumed to be categorical label data (a vector of labels),
* and this will update the fuzzy simplicial set to respect that label data.
*/
private categoricalSimplicialSetIntersection(
simplicialSet: matrix.SparseMatrix,
target: number[],
farDist: number,
unknownDist = 1.0
) {
let intersection = fastIntersection(
simplicialSet,
target,
unknownDist,
farDist
);
intersection = matrix.eliminateZeros(intersection);
return resetLocalConnectivity(intersection);
}
/**
* Compute a continuous version of the distance to the kth nearest

@@ -522,6 +661,3 @@ * neighbor. That is, this is similar to knn-distance but allows continuous

// TODO -> Compute these values which are computed via a curve-fitting
// routine in the python implementation.
const a = 1.5769434603113077;
const b = 0.8950608779109733;
const { a, b } = findABParams(this.spread, this.minDist);

@@ -789,1 +925,76 @@ const dim = headEmbedding[0].length;

}
/**
* Fit a, b params for the differentiable curve used in lower
* dimensional fuzzy simplicial complex construction. We want the
* smooth curve (from a pre-defined family with simple gradient) that
* best matches an offset exponential decay.
*/
export function findABParams(spread: number, minDist: number) {
const curve = ([a, b]) => (x: number) => {
return 1.0 / (1.0 + a * x ** (2 * b));
};
const xv = utils
.linear(0, spread * 3, 300)
.map(val => (val < minDist ? 1.0 : val));
const yv = utils.zeros(xv.length).map((val, index) => {
const gte = xv[index] >= minDist;
return gte ? Math.exp(-(xv[index] - minDist) / spread) : val;
});
const initialValues = [0.5, 0.5];
const data = { x: xv, y: yv };
// Default options for the algorithm (from github example)
const options = {
damping: 1.5,
initialValues,
gradientDifference: 10e-2,
maxIterations: 100,
errorTolerance: 10e-3,
};
const { parameterValues } = LM(data, curve, options);
const [a, b] = parameterValues as number[];
return { a, b };
}
/**
* Under the assumption of categorical distance for the intersecting
* simplicial set perform a fast intersection.
*/
export function fastIntersection(
graph: matrix.SparseMatrix,
target: number[],
unknownDist = 1.0,
farDist = 5.0
) {
return graph.map((value, row, col) => {
if (target[row] === -1 || target[col] === -1) {
return value * Math.exp(-unknownDist);
} else if (target[row] !== target[col]) {
return value * Math.exp(-farDist);
} else {
return value;
}
});
}
/**
* Reset the local connectivity requirement -- each data sample should
* have complete confidence in at least one 1-simplex in the simplicial set.
* We can enforce this by locally rescaling confidences, and then remerging the
* different local simplicial sets together.
*/
export function resetLocalConnectivity(simplicialSet: matrix.SparseMatrix) {
simplicialSet = matrix.normalize(simplicialSet, matrix.NormType.max);
const transpose = matrix.transpose(simplicialSet);
const prodMatrix = matrix.pairwiseMultiply(transpose, simplicialSet);
simplicialSet = matrix.add(
simplicialSet,
matrix.subtract(transpose, prodMatrix)
);
return matrix.eliminateZeros(simplicialSet);
}

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.

@@ -108,2 +108,11 @@ Licensed under the Apache License, Version 2.0 (the "License");

/**
* Creates an array from a to b, of length len, inclusive
*/
export function linear(a: number, b: number, len: number): number[] {
return empty(len).map((_, i) => {
return a + i * ((b - a) / (len - 1));
});
}
/**
* Returns the sum of an array

@@ -110,0 +119,0 @@ */

@@ -1,9 +0,6 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software

@@ -20,6 +17,9 @@ distributed under the License is distributed on an "AS IS" BASIS,

identity,
dotMultiply,
pairwiseMultiply,
add,
subtract,
multiplyScalar,
eliminateZeros,
normalize,
NormType,
} from '../src/matrix';

@@ -44,3 +44,3 @@

const cols = [0, 1, 0, 1];
const vals = [1, 2];
const vals = [1, 2, 3, 4];
const dims = [2, 2];

@@ -84,3 +84,3 @@ const matrix = new SparseMatrix(rows, cols, vals, dims);

const entries = [];
const entries: number[][] = [];
matrix.forEach((value, row, col) => {

@@ -117,4 +117,4 @@ entries.push([value, row, col]);

test('dot multiply method', () => {
const X = dotMultiply(A, B);
test('pairwise multiply method', () => {
const X = pairwiseMultiply(A, B);
expect(X.toArray()).toEqual([[1, 4], [9, 16]]);

@@ -137,3 +137,62 @@ });

});
test('eliminateZeros method', () => {
const defaultValue = 11;
const rows = [0, 1, 1];
const cols = [0, 0, 1];
const vals = [0, 1, 3];
const dims = [2, 2];
const matrix = new SparseMatrix(rows, cols, vals, dims);
expect(matrix.get(0, 0, defaultValue)).toEqual(0);
const eliminated = eliminateZeros(matrix);
expect(eliminated.getValues()).toEqual([1, 3]);
expect(eliminated.getRows()).toEqual([1, 1]);
expect(eliminated.getCols()).toEqual([0, 1]);
expect(eliminated.get(0, 0, defaultValue)).toEqual(defaultValue);
});
});
describe('normalize method', () => {
let A: SparseMatrix;
beforeEach(() => {
const rows = [0, 0, 0, 1, 1, 1, 2, 2, 2];
const cols = [0, 1, 2, 0, 1, 2, 0, 1, 2];
const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const dims = [3, 3];
A = new SparseMatrix(rows, cols, vals, dims);
});
test('max normalization method', () => {
const expected = [
[0.3333333333333333, 0.6666666666666666, 1.0],
[0.6666666666666666, 0.8333333333333334, 1.0],
[0.7777777777777778, 0.8888888888888888, 1.0],
];
const n = normalize(A, NormType.max);
expect(n.toArray()).toEqual(expected);
});
test('l1 normalization method', () => {
const expected = [
[0.16666666666666666, 0.3333333333333333, 0.5],
[0.26666666666666666, 0.3333333333333333, 0.4],
[0.2916666666666667, 0.3333333333333333, 0.375],
];
const n = normalize(A, NormType.l1);
expect(n.toArray()).toEqual(expected);
});
test('l2 normalization method (default)', () => {
const expected = [
[0.2672612419124244, 0.5345224838248488, 0.8017837257372732],
[0.4558423058385518, 0.5698028822981898, 0.6837634587578277],
[0.5025707110324167, 0.5743665268941904, 0.6461623427559643],
];
const n = normalize(A);
expect(n.toArray()).toEqual(expected);
});
});

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.

@@ -3,0 +3,0 @@ Licensed under the Apache License, Version 2.0 (the "License");

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.

@@ -17,6813 +17,348 @@ Licensed under the Apache License, Version 2.0 (the "License");

export const testData: number[][] = [
[
0,
0,
5,
13,
9,
1,
0,
0,
0,
0,
13,
15,
10,
15,
5,
0,
0,
3,
15,
2,
0,
11,
8,
0,
0,
4,
12,
0,
0,
8,
8,
0,
0,
5,
8,
0,
0,
9,
8,
0,
0,
4,
11,
0,
1,
12,
7,
0,
0,
2,
14,
5,
10,
12,
0,
0,
0,
0,
6,
13,
10,
0,
0,
0,
],
[
0,
0,
0,
12,
13,
5,
0,
0,
0,
0,
0,
11,
16,
9,
0,
0,
0,
0,
3,
15,
16,
6,
0,
0,
0,
7,
15,
16,
16,
2,
0,
0,
0,
0,
1,
16,
16,
3,
0,
0,
0,
0,
1,
16,
16,
6,
0,
0,
0,
0,
1,
16,
16,
6,
0,
0,
0,
0,
0,
11,
16,
10,
0,
0,
],
[
0,
0,
0,
4,
15,
12,
0,
0,
0,
0,
3,
16,
15,
14,
0,
0,
0,
0,
8,
13,
8,
16,
0,
0,
0,
0,
1,
6,
15,
11,
0,
0,
0,
1,
8,
13,
15,
1,
0,
0,
0,
9,
16,
16,
5,
0,
0,
0,
0,
3,
13,
16,
16,
11,
5,
0,
0,
0,
0,
3,
11,
16,
9,
0,
],
[
0,
0,
7,
15,
13,
1,
0,
0,
0,
8,
13,
6,
15,
4,
0,
0,
0,
2,
1,
13,
13,
0,
0,
0,
0,
0,
2,
15,
11,
1,
0,
0,
0,
0,
0,
1,
12,
12,
1,
0,
0,
0,
0,
0,
1,
10,
8,
0,
0,
0,
8,
4,
5,
14,
9,
0,
0,
0,
7,
13,
13,
9,
0,
0,
],
[
0,
0,
0,
1,
11,
0,
0,
0,
0,
0,
0,
7,
8,
0,
0,
0,
0,
0,
1,
13,
6,
2,
2,
0,
0,
0,
7,
15,
0,
9,
8,
0,
0,
5,
16,
10,
0,
16,
6,
0,
0,
4,
15,
16,
13,
16,
1,
0,
0,
0,
0,
3,
15,
10,
0,
0,
0,
0,
0,
2,
16,
4,
0,
0,
],
[
0,
0,
12,
10,
0,
0,
0,
0,
0,
0,
14,
16,
16,
14,
0,
0,
0,
0,
13,
16,
15,
10,
1,
0,
0,
0,
11,
16,
16,
7,
0,
0,
0,
0,
0,
4,
7,
16,
7,
0,
0,
0,
0,
0,
4,
16,
9,
0,
0,
0,
5,
4,
12,
16,
4,
0,
0,
0,
9,
16,
16,
10,
0,
0,
],
[
0,
0,
0,
12,
13,
0,
0,
0,
0,
0,
5,
16,
8,
0,
0,
0,
0,
0,
13,
16,
3,
0,
0,
0,
0,
0,
14,
13,
0,
0,
0,
0,
0,
0,
15,
12,
7,
2,
0,
0,
0,
0,
13,
16,
13,
16,
3,
0,
0,
0,
7,
16,
11,
15,
8,
0,
0,
0,
1,
9,
15,
11,
3,
0,
],
[
0,
0,
7,
8,
13,
16,
15,
1,
0,
0,
7,
7,
4,
11,
12,
0,
0,
0,
0,
0,
8,
13,
1,
0,
0,
4,
8,
8,
15,
15,
6,
0,
0,
2,
11,
15,
15,
4,
0,
0,
0,
0,
0,
16,
5,
0,
0,
0,
0,
0,
9,
15,
1,
0,
0,
0,
0,
0,
13,
5,
0,
0,
0,
0,
],
[
0,
0,
9,
14,
8,
1,
0,
0,
0,
0,
12,
14,
14,
12,
0,
0,
0,
0,
9,
10,
0,
15,
4,
0,
0,
0,
3,
16,
12,
14,
2,
0,
0,
0,
4,
16,
16,
2,
0,
0,
0,
3,
16,
8,
10,
13,
2,
0,
0,
1,
15,
1,
3,
16,
8,
0,
0,
0,
11,
16,
15,
11,
1,
0,
],
[
0,
0,
11,
12,
0,
0,
0,
0,
0,
2,
16,
16,
16,
13,
0,
0,
0,
3,
16,
12,
10,
14,
0,
0,
0,
1,
16,
1,
12,
15,
0,
0,
0,
0,
13,
16,
9,
15,
2,
0,
0,
0,
0,
3,
0,
9,
11,
0,
0,
0,
0,
0,
9,
15,
4,
0,
0,
0,
9,
12,
13,
3,
0,
0,
],
[
0,
0,
1,
9,
15,
11,
0,
0,
0,
0,
11,
16,
8,
14,
6,
0,
0,
2,
16,
10,
0,
9,
9,
0,
0,
1,
16,
4,
0,
8,
8,
0,
0,
4,
16,
4,
0,
8,
8,
0,
0,
1,
16,
5,
1,
11,
3,
0,
0,
0,
12,
12,
10,
10,
0,
0,
0,
0,
1,
10,
13,
3,
0,
0,
],
[
0,
0,
0,
0,
14,
13,
1,
0,
0,
0,
0,
5,
16,
16,
2,
0,
0,
0,
0,
14,
16,
12,
0,
0,
0,
1,
10,
16,
16,
12,
0,
0,
0,
3,
12,
14,
16,
9,
0,
0,
0,
0,
0,
5,
16,
15,
0,
0,
0,
0,
0,
4,
16,
14,
0,
0,
0,
0,
0,
1,
13,
16,
1,
0,
],
[
0,
0,
5,
12,
1,
0,
0,
0,
0,
0,
15,
14,
7,
0,
0,
0,
0,
0,
13,
1,
12,
0,
0,
0,
0,
2,
10,
0,
14,
0,
0,
0,
0,
0,
2,
0,
16,
1,
0,
0,
0,
0,
0,
6,
15,
0,
0,
0,
0,
0,
9,
16,
15,
9,
8,
2,
0,
0,
3,
11,
8,
13,
12,
4,
],
[
0,
2,
9,
15,
14,
9,
3,
0,
0,
4,
13,
8,
9,
16,
8,
0,
0,
0,
0,
6,
14,
15,
3,
0,
0,
0,
0,
11,
14,
2,
0,
0,
0,
0,
0,
2,
15,
11,
0,
0,
0,
0,
0,
0,
2,
15,
4,
0,
0,
1,
5,
6,
13,
16,
6,
0,
0,
2,
12,
12,
13,
11,
0,
0,
],
[
0,
0,
0,
8,
15,
1,
0,
0,
0,
0,
1,
14,
13,
1,
1,
0,
0,
0,
10,
15,
3,
15,
11,
0,
0,
7,
16,
7,
1,
16,
8,
0,
0,
9,
16,
13,
14,
16,
5,
0,
0,
1,
10,
15,
16,
14,
0,
0,
0,
0,
0,
1,
16,
10,
0,
0,
0,
0,
0,
10,
15,
4,
0,
0,
],
[
0,
5,
12,
13,
16,
16,
2,
0,
0,
11,
16,
15,
8,
4,
0,
0,
0,
8,
14,
11,
1,
0,
0,
0,
0,
8,
16,
16,
14,
0,
0,
0,
0,
1,
6,
6,
16,
0,
0,
0,
0,
0,
0,
5,
16,
3,
0,
0,
0,
1,
5,
15,
13,
0,
0,
0,
0,
4,
15,
16,
2,
0,
0,
0,
],
[
0,
0,
0,
8,
15,
1,
0,
0,
0,
0,
0,
12,
14,
0,
0,
0,
0,
0,
3,
16,
7,
0,
0,
0,
0,
0,
6,
16,
2,
0,
0,
0,
0,
0,
7,
16,
16,
13,
5,
0,
0,
0,
15,
16,
9,
9,
14,
0,
0,
0,
3,
14,
9,
2,
16,
2,
0,
0,
0,
7,
15,
16,
11,
0,
],
[
0,
0,
1,
8,
15,
10,
0,
0,
0,
3,
13,
15,
14,
14,
0,
0,
0,
5,
10,
0,
10,
12,
0,
0,
0,
0,
3,
5,
15,
10,
2,
0,
0,
0,
16,
16,
16,
16,
12,
0,
0,
1,
8,
12,
14,
8,
3,
0,
0,
0,
0,
10,
13,
0,
0,
0,
0,
0,
0,
11,
9,
0,
0,
0,
],
[
0,
0,
10,
7,
13,
9,
0,
0,
0,
0,
9,
10,
12,
15,
2,
0,
0,
0,
4,
11,
10,
11,
0,
0,
0,
0,
1,
16,
10,
1,
0,
0,
0,
0,
12,
13,
4,
0,
0,
0,
0,
0,
12,
1,
12,
0,
0,
0,
0,
1,
10,
2,
14,
0,
0,
0,
0,
0,
11,
14,
5,
0,
0,
0,
],
[
0,
0,
6,
14,
4,
0,
0,
0,
0,
0,
11,
16,
10,
0,
0,
0,
0,
0,
8,
14,
16,
2,
0,
0,
0,
0,
1,
12,
12,
11,
0,
0,
0,
0,
0,
0,
0,
11,
3,
0,
0,
0,
0,
0,
0,
5,
11,
0,
0,
0,
1,
4,
4,
7,
16,
2,
0,
0,
7,
16,
16,
13,
11,
1,
],
[
0,
0,
3,
13,
11,
7,
0,
0,
0,
0,
11,
16,
16,
16,
2,
0,
0,
4,
16,
9,
1,
14,
2,
0,
0,
4,
16,
0,
0,
16,
2,
0,
0,
0,
16,
1,
0,
12,
8,
0,
0,
0,
15,
9,
0,
13,
6,
0,
0,
0,
9,
14,
9,
14,
1,
0,
0,
0,
2,
12,
13,
4,
0,
0,
],
[
0,
0,
0,
2,
16,
16,
2,
0,
0,
0,
0,
4,
16,
16,
2,
0,
0,
1,
4,
12,
16,
12,
0,
0,
0,
7,
16,
16,
16,
12,
0,
0,
0,
0,
3,
10,
16,
14,
0,
0,
0,
0,
0,
8,
16,
12,
0,
0,
0,
0,
0,
6,
16,
16,
2,
0,
0,
0,
0,
2,
12,
15,
4,
0,
],
[
0,
0,
8,
16,
5,
0,
0,
0,
0,
1,
13,
11,
16,
0,
0,
0,
0,
0,
10,
0,
13,
3,
0,
0,
0,
0,
3,
1,
16,
1,
0,
0,
0,
0,
0,
9,
12,
0,
0,
0,
0,
0,
3,
15,
5,
0,
0,
0,
0,
0,
14,
15,
8,
8,
3,
0,
0,
0,
7,
12,
12,
12,
13,
1,
],
[
0,
1,
8,
12,
15,
14,
4,
0,
0,
3,
11,
8,
8,
12,
12,
0,
0,
0,
0,
0,
2,
13,
7,
0,
0,
0,
0,
2,
15,
12,
1,
0,
0,
0,
0,
0,
13,
5,
0,
0,
0,
0,
0,
0,
9,
13,
0,
0,
0,
0,
7,
8,
14,
15,
0,
0,
0,
0,
14,
15,
11,
2,
0,
0,
],
[
0,
0,
0,
0,
12,
2,
0,
0,
0,
0,
0,
6,
14,
1,
0,
0,
0,
0,
4,
16,
7,
8,
0,
0,
0,
0,
13,
9,
0,
16,
6,
0,
0,
6,
16,
10,
11,
16,
0,
0,
0,
0,
5,
10,
13,
16,
0,
0,
0,
0,
0,
0,
6,
16,
0,
0,
0,
0,
0,
0,
12,
8,
0,
0,
],
[
0,
0,
12,
8,
8,
7,
0,
0,
0,
3,
16,
16,
11,
7,
0,
0,
0,
2,
14,
1,
0,
0,
0,
0,
0,
5,
14,
5,
0,
0,
0,
0,
0,
2,
15,
16,
9,
0,
0,
0,
0,
0,
0,
2,
16,
2,
0,
0,
0,
0,
4,
8,
16,
4,
0,
0,
0,
0,
11,
14,
9,
0,
0,
0,
],
[
0,
0,
1,
13,
14,
3,
0,
0,
0,
0,
8,
16,
13,
2,
0,
0,
0,
2,
16,
16,
3,
0,
0,
0,
0,
3,
16,
12,
1,
0,
0,
0,
0,
5,
16,
14,
5,
0,
0,
0,
0,
3,
16,
16,
16,
16,
6,
0,
0,
1,
14,
16,
16,
16,
12,
0,
0,
0,
3,
12,
15,
14,
7,
0,
],
[
0,
0,
0,
8,
14,
14,
2,
0,
0,
0,
0,
6,
10,
15,
11,
0,
0,
0,
0,
0,
0,
14,
10,
0,
0,
2,
8,
11,
12,
16,
8,
0,
0,
8,
16,
16,
16,
16,
7,
0,
0,
0,
0,
0,
11,
15,
1,
0,
0,
0,
0,
9,
16,
7,
0,
0,
0,
0,
0,
12,
13,
1,
0,
0,
],
[
0,
0,
10,
11,
4,
0,
0,
0,
0,
0,
10,
15,
13,
13,
1,
0,
0,
0,
8,
11,
0,
14,
4,
0,
0,
0,
0,
13,
15,
13,
0,
0,
0,
1,
11,
16,
16,
0,
0,
0,
0,
1,
15,
3,
9,
10,
0,
0,
0,
0,
14,
6,
15,
10,
0,
0,
0,
0,
8,
14,
7,
1,
0,
0,
],
[
0,
0,
9,
13,
7,
0,
0,
0,
0,
0,
12,
16,
16,
2,
0,
0,
0,
0,
12,
13,
16,
6,
0,
0,
0,
0,
6,
16,
16,
14,
0,
0,
0,
0,
0,
0,
2,
16,
3,
0,
0,
0,
0,
0,
0,
9,
10,
0,
0,
0,
3,
7,
12,
14,
16,
2,
0,
0,
7,
12,
12,
12,
11,
0,
],
[
0,
0,
10,
14,
11,
3,
0,
0,
0,
4,
16,
13,
6,
14,
1,
0,
0,
4,
16,
2,
0,
11,
7,
0,
0,
8,
16,
0,
0,
10,
5,
0,
0,
8,
16,
0,
0,
14,
4,
0,
0,
8,
16,
0,
1,
16,
1,
0,
0,
4,
16,
1,
11,
15,
0,
0,
0,
0,
11,
16,
12,
3,
0,
0,
],
[
0,
0,
2,
13,
8,
0,
0,
0,
0,
0,
6,
16,
16,
6,
0,
0,
0,
0,
5,
15,
13,
11,
0,
0,
0,
0,
0,
7,
16,
15,
0,
0,
0,
0,
0,
0,
0,
14,
3,
0,
0,
0,
0,
0,
0,
7,
11,
0,
0,
0,
0,
3,
4,
4,
16,
2,
0,
0,
2,
15,
13,
14,
13,
2,
],
[
0,
2,
13,
16,
16,
16,
11,
0,
0,
5,
16,
10,
5,
4,
1,
0,
0,
6,
16,
7,
3,
0,
0,
0,
0,
9,
16,
16,
16,
6,
0,
0,
0,
3,
8,
4,
11,
15,
0,
0,
0,
0,
0,
1,
12,
15,
0,
0,
0,
0,
4,
13,
16,
6,
0,
0,
0,
2,
16,
15,
8,
0,
0,
0,
],
[
0,
6,
13,
5,
8,
8,
1,
0,
0,
8,
16,
16,
16,
16,
6,
0,
0,
6,
16,
9,
6,
4,
0,
0,
0,
6,
16,
16,
15,
5,
0,
0,
0,
0,
4,
5,
15,
12,
0,
0,
0,
0,
0,
3,
16,
9,
0,
0,
0,
1,
8,
13,
15,
3,
0,
0,
0,
4,
16,
15,
3,
0,
0,
0,
],
[
0,
0,
0,
5,
14,
2,
0,
0,
0,
0,
1,
13,
11,
0,
0,
0,
0,
0,
5,
16,
2,
0,
0,
0,
0,
0,
6,
15,
5,
0,
0,
0,
0,
1,
15,
16,
15,
11,
1,
0,
0,
2,
13,
14,
1,
12,
9,
0,
0,
0,
4,
16,
7,
13,
9,
0,
0,
0,
0,
5,
16,
15,
3,
0,
],
[
0,
3,
15,
8,
8,
6,
0,
0,
0,
4,
16,
16,
16,
13,
2,
0,
0,
3,
16,
9,
2,
0,
0,
0,
0,
2,
16,
16,
15,
3,
0,
0,
0,
0,
7,
6,
12,
9,
0,
0,
0,
0,
0,
1,
14,
10,
0,
0,
0,
0,
5,
14,
15,
2,
0,
0,
0,
1,
15,
14,
1,
0,
0,
0,
],
[
0,
0,
6,
14,
10,
2,
0,
0,
0,
0,
15,
15,
13,
15,
3,
0,
0,
2,
16,
10,
0,
13,
9,
0,
0,
1,
16,
5,
0,
12,
5,
0,
0,
0,
16,
3,
0,
13,
6,
0,
0,
1,
15,
5,
6,
13,
1,
0,
0,
0,
16,
11,
14,
10,
0,
0,
0,
0,
7,
16,
11,
1,
0,
0,
],
[
0,
0,
13,
10,
1,
0,
0,
0,
0,
5,
16,
14,
7,
0,
0,
0,
0,
4,
16,
8,
14,
0,
0,
0,
0,
2,
14,
16,
16,
6,
0,
0,
0,
0,
1,
4,
9,
13,
1,
0,
0,
0,
0,
0,
0,
13,
6,
0,
0,
0,
5,
8,
5,
9,
14,
0,
0,
0,
13,
13,
15,
16,
13,
0,
],
[
0,
0,
7,
7,
13,
16,
4,
0,
0,
0,
13,
13,
6,
12,
7,
0,
0,
0,
10,
4,
10,
11,
1,
0,
0,
0,
8,
16,
10,
0,
0,
0,
0,
3,
14,
16,
0,
0,
0,
0,
0,
8,
8,
11,
5,
0,
0,
0,
0,
4,
10,
9,
8,
0,
0,
0,
0,
1,
11,
16,
6,
0,
0,
0,
],
[
0,
1,
9,
16,
13,
7,
0,
0,
0,
7,
14,
4,
10,
12,
0,
0,
0,
6,
15,
9,
16,
11,
0,
0,
0,
0,
9,
11,
7,
14,
0,
0,
0,
0,
0,
0,
0,
15,
2,
0,
0,
0,
0,
0,
0,
11,
6,
0,
0,
3,
13,
8,
5,
14,
5,
0,
0,
0,
9,
14,
13,
10,
1,
0,
],
[
0,
0,
11,
10,
12,
4,
0,
0,
0,
0,
12,
13,
9,
16,
1,
0,
0,
0,
7,
13,
11,
16,
0,
0,
0,
0,
1,
16,
14,
4,
0,
0,
0,
0,
10,
16,
13,
0,
0,
0,
0,
0,
14,
7,
12,
7,
0,
0,
0,
4,
14,
4,
12,
13,
0,
0,
0,
1,
11,
14,
12,
4,
0,
0,
],
[
0,
0,
0,
9,
15,
1,
0,
0,
0,
0,
4,
16,
12,
0,
0,
0,
0,
0,
15,
14,
2,
11,
3,
0,
0,
4,
16,
9,
4,
16,
10,
0,
0,
9,
16,
11,
13,
16,
2,
0,
0,
0,
9,
16,
16,
14,
0,
0,
0,
0,
0,
8,
16,
6,
0,
0,
0,
0,
0,
9,
16,
2,
0,
0,
],
[
0,
0,
0,
0,
12,
5,
0,
0,
0,
0,
0,
2,
16,
12,
0,
0,
0,
0,
1,
12,
16,
11,
0,
0,
0,
2,
12,
16,
16,
10,
0,
0,
0,
6,
11,
5,
15,
6,
0,
0,
0,
0,
0,
1,
16,
9,
0,
0,
0,
0,
0,
2,
16,
11,
0,
0,
0,
0,
0,
3,
16,
8,
0,
0,
],
[
0,
0,
0,
9,
15,
12,
0,
0,
0,
0,
4,
7,
7,
14,
0,
0,
0,
0,
0,
0,
0,
13,
3,
0,
0,
4,
9,
8,
10,
13,
1,
0,
0,
4,
16,
15,
16,
16,
6,
0,
0,
0,
0,
0,
14,
3,
0,
0,
0,
0,
0,
9,
12,
0,
0,
0,
0,
0,
0,
11,
7,
0,
0,
0,
],
[
0,
0,
9,
16,
16,
16,
5,
0,
0,
1,
14,
10,
8,
16,
8,
0,
0,
0,
0,
0,
7,
16,
3,
0,
0,
3,
8,
11,
15,
16,
11,
0,
0,
8,
16,
16,
15,
11,
3,
0,
0,
0,
2,
16,
7,
0,
0,
0,
0,
0,
8,
16,
1,
0,
0,
0,
0,
0,
13,
10,
0,
0,
0,
0,
],
[
0,
0,
9,
16,
13,
6,
0,
0,
0,
0,
6,
5,
16,
16,
0,
0,
0,
0,
0,
8,
15,
5,
0,
0,
0,
0,
0,
5,
14,
3,
0,
0,
0,
0,
0,
0,
9,
15,
2,
0,
0,
0,
0,
0,
0,
11,
12,
0,
0,
0,
4,
8,
11,
15,
12,
0,
0,
0,
11,
14,
12,
8,
0,
0,
],
[
0,
1,
15,
4,
0,
0,
0,
0,
0,
2,
16,
16,
16,
14,
2,
0,
0,
6,
16,
11,
8,
8,
3,
0,
0,
5,
16,
11,
5,
0,
0,
0,
0,
0,
11,
14,
14,
1,
0,
0,
0,
0,
0,
5,
16,
7,
0,
0,
0,
0,
6,
16,
16,
4,
0,
0,
0,
0,
14,
14,
4,
0,
0,
0,
],
[
0,
0,
0,
1,
11,
9,
0,
0,
0,
0,
0,
7,
16,
13,
0,
0,
0,
0,
4,
14,
16,
9,
0,
0,
0,
10,
16,
11,
16,
8,
0,
0,
0,
0,
0,
3,
16,
6,
0,
0,
0,
0,
0,
3,
16,
8,
0,
0,
0,
0,
0,
5,
16,
10,
0,
0,
0,
0,
0,
2,
14,
6,
0,
0,
],
[
0,
0,
2,
15,
13,
3,
0,
0,
0,
0,
10,
15,
11,
15,
0,
0,
0,
3,
16,
6,
0,
10,
0,
0,
0,
4,
16,
8,
0,
3,
8,
0,
0,
8,
14,
3,
0,
4,
8,
0,
0,
3,
15,
1,
0,
3,
7,
0,
0,
0,
14,
11,
6,
14,
5,
0,
0,
0,
4,
12,
15,
6,
0,
0,
],
[
0,
0,
1,
15,
13,
1,
0,
0,
0,
0,
7,
16,
14,
8,
0,
0,
0,
8,
12,
9,
2,
13,
2,
0,
0,
7,
9,
1,
0,
6,
6,
0,
0,
5,
9,
0,
0,
3,
9,
0,
0,
0,
15,
2,
0,
8,
12,
0,
0,
0,
9,
15,
13,
16,
6,
0,
0,
0,
0,
13,
14,
8,
0,
0,
],
[
0,
0,
0,
5,
14,
12,
2,
0,
0,
0,
7,
15,
8,
14,
4,
0,
0,
0,
6,
2,
3,
13,
1,
0,
0,
0,
0,
1,
13,
4,
0,
0,
0,
0,
1,
11,
9,
0,
0,
0,
0,
8,
16,
13,
0,
0,
0,
0,
0,
5,
14,
16,
11,
2,
0,
0,
0,
0,
0,
6,
12,
13,
3,
0,
],
[
0,
0,
0,
3,
15,
10,
1,
0,
0,
0,
0,
11,
10,
16,
4,
0,
0,
0,
0,
12,
1,
15,
6,
0,
0,
0,
0,
3,
4,
15,
4,
0,
0,
0,
0,
6,
15,
6,
0,
0,
0,
4,
15,
16,
9,
0,
0,
0,
0,
0,
13,
16,
15,
9,
3,
0,
0,
0,
0,
4,
9,
14,
7,
0,
],
[
0,
0,
3,
12,
16,
16,
6,
0,
0,
0,
10,
11,
7,
16,
11,
0,
0,
0,
0,
0,
2,
14,
10,
0,
0,
5,
11,
8,
9,
16,
3,
0,
0,
9,
16,
16,
16,
16,
9,
0,
0,
1,
4,
9,
16,
6,
0,
0,
0,
0,
0,
11,
14,
0,
0,
0,
0,
0,
4,
16,
5,
0,
0,
0,
],
[
0,
0,
4,
8,
16,
5,
0,
0,
0,
0,
9,
16,
8,
11,
0,
0,
0,
0,
5,
10,
0,
13,
2,
0,
0,
0,
0,
13,
4,
15,
2,
0,
0,
0,
0,
9,
16,
8,
0,
0,
0,
0,
8,
15,
14,
5,
0,
0,
0,
0,
16,
5,
14,
4,
0,
0,
0,
0,
6,
16,
12,
1,
0,
0,
],
[
0,
0,
0,
1,
14,
14,
3,
0,
0,
0,
0,
10,
11,
13,
8,
0,
0,
0,
0,
7,
0,
13,
8,
0,
0,
0,
0,
0,
7,
15,
1,
0,
0,
4,
8,
12,
15,
4,
0,
0,
0,
6,
16,
16,
6,
0,
0,
0,
0,
0,
2,
12,
12,
4,
2,
0,
0,
0,
0,
1,
13,
16,
5,
0,
],
[
0,
0,
2,
14,
15,
5,
0,
0,
0,
0,
10,
16,
16,
15,
1,
0,
0,
3,
16,
10,
10,
16,
4,
0,
0,
5,
16,
0,
0,
14,
6,
0,
0,
5,
16,
6,
0,
12,
7,
0,
0,
1,
15,
13,
4,
13,
6,
0,
0,
0,
11,
16,
16,
15,
0,
0,
0,
0,
2,
11,
13,
4,
0,
0,
],
[
0,
0,
0,
0,
12,
13,
1,
0,
0,
0,
0,
8,
16,
15,
2,
0,
0,
0,
10,
16,
16,
12,
0,
0,
0,
4,
16,
16,
16,
13,
0,
0,
0,
4,
7,
4,
16,
6,
0,
0,
0,
0,
0,
1,
16,
8,
0,
0,
0,
0,
0,
1,
16,
8,
0,
0,
0,
0,
0,
0,
12,
12,
0,
0,
],
[
0,
0,
0,
1,
9,
11,
0,
0,
0,
0,
0,
13,
16,
16,
0,
0,
0,
0,
0,
12,
7,
14,
0,
0,
0,
0,
0,
0,
14,
7,
0,
0,
0,
0,
5,
12,
12,
0,
0,
0,
0,
7,
16,
16,
6,
0,
0,
0,
0,
4,
9,
13,
16,
11,
4,
0,
0,
0,
0,
0,
9,
13,
3,
0,
],
[
0,
0,
0,
10,
13,
1,
0,
0,
0,
1,
11,
12,
7,
0,
0,
0,
0,
2,
16,
12,
0,
0,
0,
0,
0,
4,
16,
11,
0,
0,
0,
0,
0,
4,
16,
15,
8,
4,
0,
0,
0,
4,
16,
16,
13,
16,
6,
0,
0,
0,
7,
16,
7,
13,
14,
0,
0,
0,
0,
7,
15,
15,
5,
0,
],
[
0,
1,
10,
15,
11,
1,
0,
0,
0,
3,
8,
8,
11,
12,
0,
0,
0,
0,
0,
5,
14,
15,
1,
0,
0,
0,
0,
11,
15,
2,
0,
0,
0,
0,
0,
4,
15,
2,
0,
0,
0,
0,
0,
0,
12,
10,
0,
0,
0,
0,
3,
4,
10,
16,
1,
0,
0,
0,
13,
16,
15,
10,
0,
0,
],
[
0,
0,
10,
15,
14,
4,
0,
0,
0,
0,
4,
6,
13,
16,
2,
0,
0,
0,
0,
3,
16,
9,
0,
0,
0,
0,
0,
1,
16,
6,
0,
0,
0,
0,
0,
0,
10,
12,
0,
0,
0,
0,
0,
0,
1,
16,
4,
0,
0,
1,
9,
5,
6,
16,
7,
0,
0,
0,
14,
12,
15,
11,
2,
0,
],
[
0,
0,
6,
13,
16,
6,
0,
0,
0,
3,
16,
14,
15,
16,
1,
0,
0,
0,
5,
0,
8,
16,
2,
0,
0,
0,
0,
0,
8,
16,
3,
0,
0,
3,
15,
16,
16,
16,
9,
0,
0,
5,
13,
14,
16,
11,
3,
0,
0,
0,
0,
12,
15,
1,
0,
0,
0,
0,
4,
16,
7,
0,
0,
0,
],
[
0,
0,
14,
16,
14,
6,
0,
0,
0,
0,
7,
10,
16,
16,
3,
0,
0,
0,
0,
5,
16,
16,
1,
0,
0,
0,
0,
2,
16,
8,
0,
0,
0,
0,
0,
0,
12,
13,
1,
0,
0,
0,
0,
0,
4,
16,
7,
0,
0,
0,
5,
9,
14,
16,
7,
0,
0,
0,
13,
16,
16,
10,
1,
0,
],
[
0,
3,
16,
16,
14,
7,
1,
0,
0,
1,
9,
9,
15,
16,
4,
0,
0,
0,
0,
7,
16,
12,
1,
0,
0,
0,
0,
9,
16,
2,
0,
0,
0,
0,
0,
3,
15,
7,
0,
0,
0,
0,
0,
0,
9,
15,
0,
0,
0,
1,
10,
10,
16,
16,
3,
0,
0,
2,
13,
16,
12,
5,
0,
0,
],
[
0,
0,
0,
6,
16,
4,
0,
0,
0,
0,
1,
13,
15,
1,
0,
0,
0,
1,
11,
16,
5,
0,
0,
0,
0,
8,
16,
10,
0,
10,
6,
0,
0,
12,
16,
8,
9,
16,
12,
0,
0,
2,
15,
16,
16,
16,
7,
0,
0,
0,
0,
4,
16,
11,
0,
0,
0,
0,
0,
7,
16,
3,
0,
0,
],
[
0,
0,
0,
9,
10,
0,
0,
0,
0,
0,
7,
16,
7,
0,
0,
0,
0,
0,
13,
13,
1,
0,
0,
0,
0,
0,
15,
7,
0,
0,
0,
0,
0,
4,
16,
15,
12,
7,
0,
0,
0,
2,
16,
12,
4,
11,
10,
0,
0,
0,
8,
14,
5,
9,
14,
0,
0,
0,
0,
6,
12,
14,
9,
0,
],
[
0,
0,
0,
10,
11,
0,
0,
0,
0,
0,
9,
16,
6,
0,
0,
0,
0,
0,
15,
13,
0,
0,
0,
0,
0,
0,
14,
10,
0,
0,
0,
0,
0,
1,
15,
12,
8,
2,
0,
0,
0,
0,
12,
16,
16,
16,
10,
1,
0,
0,
7,
16,
12,
12,
16,
4,
0,
0,
0,
9,
15,
12,
5,
0,
],
[
0,
0,
5,
14,
0,
0,
0,
0,
0,
0,
12,
9,
0,
0,
0,
0,
0,
0,
15,
3,
0,
0,
0,
0,
0,
1,
16,
0,
0,
0,
0,
0,
0,
1,
16,
2,
7,
4,
0,
0,
0,
3,
16,
16,
16,
16,
9,
0,
0,
0,
15,
15,
4,
10,
16,
0,
0,
0,
4,
14,
16,
12,
7,
0,
],
[
0,
0,
0,
9,
9,
0,
0,
0,
0,
0,
3,
16,
9,
0,
0,
0,
0,
3,
14,
10,
0,
2,
0,
0,
0,
10,
16,
5,
7,
15,
1,
0,
0,
2,
11,
15,
16,
13,
1,
0,
0,
0,
0,
7,
16,
3,
0,
0,
0,
0,
0,
6,
15,
0,
0,
0,
0,
0,
0,
4,
16,
5,
0,
0,
],
[
0,
0,
6,
12,
13,
6,
0,
0,
0,
6,
16,
9,
12,
16,
2,
0,
0,
7,
16,
9,
15,
13,
0,
0,
0,
0,
11,
15,
16,
4,
0,
0,
0,
0,
0,
12,
10,
0,
0,
0,
0,
0,
3,
16,
4,
0,
0,
0,
0,
0,
1,
16,
2,
0,
0,
0,
0,
0,
6,
11,
0,
0,
0,
0,
],
[
0,
0,
0,
0,
14,
7,
0,
0,
0,
0,
0,
13,
16,
9,
0,
0,
0,
0,
10,
16,
16,
7,
0,
0,
0,
7,
16,
8,
16,
2,
0,
0,
0,
1,
5,
6,
16,
6,
0,
0,
0,
0,
0,
4,
16,
6,
0,
0,
0,
0,
0,
2,
16,
6,
0,
0,
0,
0,
0,
0,
12,
11,
0,
0,
],
[
0,
1,
13,
15,
12,
12,
5,
0,
0,
4,
16,
8,
8,
6,
0,
0,
0,
7,
13,
0,
0,
0,
0,
0,
0,
8,
15,
13,
15,
7,
0,
0,
0,
1,
6,
5,
8,
12,
0,
0,
0,
0,
0,
0,
12,
11,
0,
0,
0,
0,
2,
13,
14,
1,
0,
0,
0,
3,
14,
10,
1,
0,
0,
0,
],
[
0,
0,
1,
13,
10,
0,
0,
0,
0,
7,
16,
16,
16,
7,
0,
0,
0,
8,
16,
13,
10,
15,
0,
0,
0,
8,
16,
2,
2,
15,
3,
0,
0,
5,
15,
2,
0,
12,
7,
0,
0,
1,
15,
6,
2,
16,
3,
0,
0,
0,
11,
15,
13,
16,
0,
0,
0,
0,
1,
15,
14,
8,
0,
0,
],
[
0,
1,
12,
13,
4,
0,
0,
0,
0,
4,
16,
16,
16,
3,
0,
0,
0,
4,
16,
16,
16,
10,
0,
0,
0,
0,
6,
16,
14,
16,
0,
0,
0,
0,
0,
0,
0,
16,
4,
0,
0,
0,
0,
0,
0,
13,
7,
0,
0,
1,
2,
3,
7,
14,
10,
0,
0,
2,
12,
16,
14,
12,
3,
0,
],
[
0,
0,
13,
13,
8,
2,
0,
0,
0,
5,
16,
16,
16,
12,
0,
0,
0,
1,
15,
12,
0,
0,
0,
0,
0,
0,
12,
13,
7,
1,
0,
0,
0,
0,
8,
16,
16,
12,
0,
0,
0,
0,
0,
4,
9,
16,
3,
0,
0,
0,
1,
5,
14,
15,
1,
0,
0,
0,
10,
16,
16,
6,
0,
0,
],
[
0,
0,
0,
0,
9,
13,
0,
0,
0,
0,
0,
2,
16,
16,
1,
0,
0,
0,
0,
5,
9,
15,
0,
0,
0,
0,
0,
0,
5,
14,
0,
0,
0,
0,
0,
3,
15,
7,
0,
0,
0,
7,
16,
16,
11,
0,
0,
0,
0,
0,
11,
14,
16,
7,
3,
0,
0,
0,
0,
0,
9,
15,
9,
0,
],
[
0,
3,
5,
14,
13,
6,
0,
0,
0,
9,
16,
12,
10,
12,
0,
0,
0,
6,
16,
3,
12,
11,
0,
0,
0,
1,
13,
10,
16,
6,
0,
0,
0,
0,
10,
16,
10,
0,
0,
0,
0,
1,
15,
16,
10,
0,
0,
0,
0,
0,
16,
12,
16,
0,
0,
0,
0,
0,
3,
15,
16,
5,
0,
0,
],
[
0,
0,
0,
0,
11,
15,
4,
0,
0,
0,
0,
3,
16,
16,
12,
0,
0,
0,
0,
8,
14,
16,
12,
0,
0,
0,
0,
5,
10,
16,
6,
0,
0,
1,
7,
11,
16,
13,
0,
0,
0,
9,
16,
16,
14,
1,
0,
0,
0,
3,
8,
14,
16,
9,
0,
0,
0,
0,
0,
1,
11,
16,
12,
0,
],
[
0,
0,
10,
12,
10,
0,
0,
0,
0,
3,
16,
16,
16,
4,
0,
0,
0,
7,
15,
3,
8,
13,
0,
0,
0,
8,
12,
0,
0,
14,
1,
0,
0,
8,
12,
0,
0,
7,
8,
0,
0,
5,
13,
0,
0,
4,
8,
0,
0,
0,
14,
8,
0,
10,
8,
0,
0,
0,
7,
12,
13,
12,
4,
0,
],
[
0,
0,
4,
14,
11,
0,
0,
0,
0,
3,
15,
15,
16,
9,
0,
0,
0,
8,
13,
0,
3,
15,
1,
0,
0,
8,
12,
0,
0,
8,
6,
0,
0,
8,
12,
0,
0,
8,
8,
0,
0,
5,
13,
1,
0,
8,
8,
0,
0,
2,
15,
14,
12,
15,
6,
0,
0,
0,
5,
16,
15,
8,
0,
0,
],
[
0,
0,
0,
1,
14,
13,
1,
0,
0,
0,
0,
1,
16,
16,
3,
0,
0,
5,
11,
15,
16,
16,
0,
0,
0,
4,
15,
16,
16,
15,
0,
0,
0,
0,
0,
8,
16,
7,
0,
0,
0,
0,
0,
10,
16,
3,
0,
0,
0,
0,
0,
8,
16,
6,
0,
0,
0,
0,
0,
2,
13,
15,
2,
0,
],
[
0,
0,
3,
14,
16,
14,
0,
0,
0,
0,
13,
13,
13,
16,
2,
0,
0,
0,
1,
0,
9,
15,
0,
0,
0,
0,
9,
12,
15,
16,
10,
0,
0,
4,
16,
16,
16,
11,
3,
0,
0,
0,
4,
9,
14,
2,
0,
0,
0,
0,
2,
15,
9,
0,
0,
0,
0,
0,
4,
13,
1,
0,
0,
0,
],
[
0,
0,
0,
10,
15,
3,
0,
0,
0,
0,
7,
16,
11,
0,
0,
0,
0,
0,
13,
15,
1,
0,
0,
0,
0,
0,
15,
11,
0,
0,
0,
0,
0,
0,
16,
13,
8,
1,
0,
0,
0,
0,
15,
16,
16,
15,
6,
0,
0,
0,
10,
16,
14,
16,
14,
2,
0,
0,
1,
9,
15,
16,
11,
0,
],
[
0,
2,
13,
15,
10,
4,
0,
0,
0,
0,
5,
4,
13,
15,
2,
0,
0,
0,
0,
0,
11,
16,
4,
0,
0,
0,
0,
0,
16,
12,
0,
0,
0,
0,
0,
0,
13,
11,
0,
0,
0,
0,
0,
0,
8,
13,
0,
0,
0,
1,
6,
8,
14,
12,
0,
0,
0,
2,
12,
14,
11,
1,
0,
0,
],
[
0,
1,
13,
15,
2,
0,
0,
0,
0,
6,
15,
15,
9,
0,
0,
0,
0,
9,
8,
10,
13,
0,
0,
0,
0,
5,
3,
12,
12,
0,
0,
0,
0,
0,
3,
16,
6,
0,
0,
0,
0,
5,
15,
15,
1,
0,
0,
0,
0,
6,
16,
15,
12,
12,
11,
0,
0,
1,
11,
13,
16,
16,
12,
0,
],
[
0,
0,
0,
1,
16,
5,
0,
0,
0,
0,
0,
5,
16,
11,
0,
0,
0,
0,
0,
12,
16,
11,
0,
0,
0,
7,
12,
16,
16,
7,
0,
0,
0,
4,
8,
12,
16,
4,
0,
0,
0,
0,
0,
9,
16,
2,
0,
0,
0,
0,
0,
10,
16,
2,
0,
0,
0,
0,
0,
3,
13,
5,
0,
0,
],
[
0,
0,
2,
7,
15,
13,
1,
0,
0,
0,
14,
12,
9,
14,
8,
0,
0,
0,
2,
0,
0,
12,
8,
0,
0,
0,
0,
0,
0,
13,
6,
0,
0,
5,
16,
16,
16,
16,
5,
0,
0,
2,
5,
7,
13,
14,
2,
0,
0,
0,
0,
1,
15,
5,
0,
0,
0,
0,
0,
11,
9,
0,
0,
0,
],
[
0,
0,
0,
9,
16,
4,
0,
0,
0,
1,
9,
16,
13,
2,
0,
0,
0,
14,
16,
14,
8,
0,
0,
0,
1,
15,
15,
5,
16,
9,
0,
0,
0,
5,
16,
16,
16,
8,
0,
0,
0,
0,
2,
13,
16,
1,
0,
0,
0,
0,
0,
11,
13,
0,
0,
0,
0,
0,
0,
11,
13,
0,
0,
0,
],
[
0,
0,
0,
10,
11,
0,
0,
0,
0,
0,
3,
16,
10,
0,
0,
0,
0,
0,
8,
16,
0,
0,
0,
0,
0,
0,
12,
14,
0,
0,
0,
0,
0,
0,
14,
16,
15,
6,
0,
0,
0,
0,
12,
16,
12,
15,
6,
0,
0,
0,
7,
16,
10,
13,
14,
0,
0,
0,
0,
9,
13,
11,
6,
0,
],
[
0,
0,
13,
16,
15,
4,
0,
0,
0,
0,
9,
8,
13,
16,
3,
0,
0,
0,
0,
0,
13,
16,
7,
0,
0,
0,
0,
1,
16,
12,
0,
0,
0,
0,
0,
0,
15,
10,
0,
0,
0,
0,
0,
0,
8,
15,
0,
0,
0,
0,
3,
6,
15,
16,
7,
0,
0,
0,
15,
16,
16,
11,
1,
0,
],
[
0,
0,
0,
1,
12,
8,
1,
0,
0,
0,
0,
4,
16,
16,
1,
0,
0,
0,
1,
13,
16,
11,
0,
0,
0,
1,
11,
16,
16,
12,
0,
0,
0,
2,
12,
8,
16,
10,
0,
0,
0,
0,
0,
0,
15,
8,
0,
0,
0,
0,
0,
4,
16,
4,
0,
0,
0,
0,
0,
3,
13,
4,
0,
0,
],
[
0,
4,
14,
16,
16,
12,
1,
0,
0,
2,
12,
7,
14,
16,
6,
0,
0,
0,
0,
5,
16,
10,
0,
0,
0,
0,
0,
4,
16,
7,
0,
0,
0,
0,
0,
4,
16,
6,
0,
0,
0,
0,
0,
1,
15,
11,
0,
0,
0,
1,
8,
10,
16,
10,
0,
0,
0,
5,
16,
16,
15,
1,
0,
0,
],
[
0,
0,
9,
13,
14,
5,
0,
0,
0,
4,
16,
10,
13,
16,
0,
0,
0,
0,
13,
15,
14,
16,
1,
0,
0,
0,
0,
3,
7,
16,
3,
0,
0,
0,
0,
0,
4,
16,
0,
0,
0,
0,
0,
0,
1,
16,
3,
0,
0,
1,
15,
5,
8,
16,
2,
0,
0,
0,
7,
15,
16,
9,
0,
0,
],
[
0,
0,
0,
11,
16,
5,
0,
0,
0,
0,
0,
10,
16,
5,
0,
0,
0,
0,
4,
16,
16,
5,
0,
0,
0,
11,
16,
16,
16,
3,
0,
0,
0,
5,
8,
14,
16,
2,
0,
0,
0,
0,
0,
14,
16,
2,
0,
0,
0,
0,
0,
11,
16,
2,
0,
0,
0,
0,
0,
8,
16,
8,
0,
0,
],
[
0,
0,
3,
12,
16,
10,
0,
0,
0,
2,
14,
12,
12,
12,
0,
0,
0,
5,
10,
0,
10,
11,
0,
0,
0,
0,
0,
1,
14,
9,
2,
0,
0,
0,
8,
16,
16,
16,
10,
0,
0,
0,
6,
16,
13,
7,
0,
0,
0,
0,
0,
16,
5,
0,
0,
0,
0,
0,
5,
13,
0,
0,
0,
0,
],
[
0,
0,
0,
11,
16,
8,
0,
0,
0,
0,
6,
16,
13,
3,
0,
0,
0,
0,
8,
16,
8,
0,
0,
0,
0,
0,
13,
16,
2,
0,
0,
0,
0,
0,
15,
16,
5,
0,
0,
0,
0,
2,
16,
16,
16,
5,
0,
0,
0,
1,
10,
16,
16,
14,
0,
0,
0,
0,
0,
12,
16,
15,
0,
0,
],
[
0,
1,
9,
16,
15,
10,
0,
0,
0,
6,
16,
8,
7,
16,
3,
0,
0,
0,
11,
14,
16,
11,
1,
0,
0,
1,
13,
16,
6,
0,
0,
0,
0,
8,
15,
16,
3,
0,
0,
0,
0,
5,
14,
10,
11,
0,
0,
0,
0,
0,
15,
7,
16,
3,
0,
0,
0,
0,
11,
16,
8,
0,
0,
0,
],
[
0,
0,
0,
3,
14,
1,
0,
0,
0,
0,
0,
13,
12,
1,
0,
0,
0,
0,
7,
16,
5,
3,
0,
0,
0,
3,
15,
11,
5,
16,
2,
0,
0,
5,
16,
11,
11,
16,
6,
0,
0,
0,
6,
12,
16,
13,
3,
0,
0,
0,
0,
1,
15,
7,
0,
0,
0,
0,
0,
2,
16,
7,
0,
0,
],
[
0,
2,
15,
16,
16,
13,
2,
0,
0,
1,
10,
8,
14,
16,
8,
0,
0,
0,
0,
0,
16,
15,
1,
0,
0,
0,
0,
0,
16,
8,
0,
0,
0,
0,
0,
0,
14,
14,
0,
0,
0,
0,
0,
0,
11,
16,
1,
0,
0,
2,
14,
13,
16,
16,
3,
0,
0,
2,
15,
16,
14,
5,
0,
0,
],
[
0,
0,
1,
15,
13,
0,
0,
0,
0,
0,
1,
16,
16,
5,
0,
0,
0,
0,
7,
16,
16,
0,
0,
0,
0,
0,
13,
16,
13,
0,
0,
0,
0,
7,
16,
16,
13,
0,
0,
0,
0,
1,
11,
16,
13,
0,
0,
0,
0,
0,
2,
16,
16,
0,
0,
0,
0,
0,
1,
14,
16,
3,
0,
0,
],
];
[0,0,5,13,9,1,0,0,0,0,13,15,10,15,5,0,0,3,15,2,0,11,8,0,0,4,12,0,0,8,8,0,0,5,8,0,0,9,8,0,0,4,11,0,1,12,7,0,0,2,14,5,10,12,0,0,0,0,6,13,10,0,0,0],
[0,0,0,12,13,5,0,0,0,0,0,11,16,9,0,0,0,0,3,15,16,6,0,0,0,7,15,16,16,2,0,0,0,0,1,16,16,3,0,0,0,0,1,16,16,6,0,0,0,0,1,16,16,6,0,0,0,0,0,11,16,10,0,0],
[0,0,0,4,15,12,0,0,0,0,3,16,15,14,0,0,0,0,8,13,8,16,0,0,0,0,1,6,15,11,0,0,0,1,8,13,15,1,0,0,0,9,16,16,5,0,0,0,0,3,13,16,16,11,5,0,0,0,0,3,11,16,9,0],
[0,0,7,15,13,1,0,0,0,8,13,6,15,4,0,0,0,2,1,13,13,0,0,0,0,0,2,15,11,1,0,0,0,0,0,1,12,12,1,0,0,0,0,0,1,10,8,0,0,0,8,4,5,14,9,0,0,0,7,13,13,9,0,0],
[0,0,0,1,11,0,0,0,0,0,0,7,8,0,0,0,0,0,1,13,6,2,2,0,0,0,7,15,0,9,8,0,0,5,16,10,0,16,6,0,0,4,15,16,13,16,1,0,0,0,0,3,15,10,0,0,0,0,0,2,16,4,0,0],
[0,0,12,10,0,0,0,0,0,0,14,16,16,14,0,0,0,0,13,16,15,10,1,0,0,0,11,16,16,7,0,0,0,0,0,4,7,16,7,0,0,0,0,0,4,16,9,0,0,0,5,4,12,16,4,0,0,0,9,16,16,10,0,0],
[0,0,0,12,13,0,0,0,0,0,5,16,8,0,0,0,0,0,13,16,3,0,0,0,0,0,14,13,0,0,0,0,0,0,15,12,7,2,0,0,0,0,13,16,13,16,3,0,0,0,7,16,11,15,8,0,0,0,1,9,15,11,3,0],
[0,0,7,8,13,16,15,1,0,0,7,7,4,11,12,0,0,0,0,0,8,13,1,0,0,4,8,8,15,15,6,0,0,2,11,15,15,4,0,0,0,0,0,16,5,0,0,0,0,0,9,15,1,0,0,0,0,0,13,5,0,0,0,0],
[0,0,9,14,8,1,0,0,0,0,12,14,14,12,0,0,0,0,9,10,0,15,4,0,0,0,3,16,12,14,2,0,0,0,4,16,16,2,0,0,0,3,16,8,10,13,2,0,0,1,15,1,3,16,8,0,0,0,11,16,15,11,1,0],
[0,0,11,12,0,0,0,0,0,2,16,16,16,13,0,0,0,3,16,12,10,14,0,0,0,1,16,1,12,15,0,0,0,0,13,16,9,15,2,0,0,0,0,3,0,9,11,0,0,0,0,0,9,15,4,0,0,0,9,12,13,3,0,0],
[0,0,1,9,15,11,0,0,0,0,11,16,8,14,6,0,0,2,16,10,0,9,9,0,0,1,16,4,0,8,8,0,0,4,16,4,0,8,8,0,0,1,16,5,1,11,3,0,0,0,12,12,10,10,0,0,0,0,1,10,13,3,0,0],
[0,0,0,0,14,13,1,0,0,0,0,5,16,16,2,0,0,0,0,14,16,12,0,0,0,1,10,16,16,12,0,0,0,3,12,14,16,9,0,0,0,0,0,5,16,15,0,0,0,0,0,4,16,14,0,0,0,0,0,1,13,16,1,0],
[0,0,5,12,1,0,0,0,0,0,15,14,7,0,0,0,0,0,13,1,12,0,0,0,0,2,10,0,14,0,0,0,0,0,2,0,16,1,0,0,0,0,0,6,15,0,0,0,0,0,9,16,15,9,8,2,0,0,3,11,8,13,12,4],
[0,2,9,15,14,9,3,0,0,4,13,8,9,16,8,0,0,0,0,6,14,15,3,0,0,0,0,11,14,2,0,0,0,0,0,2,15,11,0,0,0,0,0,0,2,15,4,0,0,1,5,6,13,16,6,0,0,2,12,12,13,11,0,0],
[0,0,0,8,15,1,0,0,0,0,1,14,13,1,1,0,0,0,10,15,3,15,11,0,0,7,16,7,1,16,8,0,0,9,16,13,14,16,5,0,0,1,10,15,16,14,0,0,0,0,0,1,16,10,0,0,0,0,0,10,15,4,0,0],
[0,5,12,13,16,16,2,0,0,11,16,15,8,4,0,0,0,8,14,11,1,0,0,0,0,8,16,16,14,0,0,0,0,1,6,6,16,0,0,0,0,0,0,5,16,3,0,0,0,1,5,15,13,0,0,0,0,4,15,16,2,0,0,0],
[0,0,0,8,15,1,0,0,0,0,0,12,14,0,0,0,0,0,3,16,7,0,0,0,0,0,6,16,2,0,0,0,0,0,7,16,16,13,5,0,0,0,15,16,9,9,14,0,0,0,3,14,9,2,16,2,0,0,0,7,15,16,11,0],
[0,0,1,8,15,10,0,0,0,3,13,15,14,14,0,0,0,5,10,0,10,12,0,0,0,0,3,5,15,10,2,0,0,0,16,16,16,16,12,0,0,1,8,12,14,8,3,0,0,0,0,10,13,0,0,0,0,0,0,11,9,0,0,0],
[0,0,10,7,13,9,0,0,0,0,9,10,12,15,2,0,0,0,4,11,10,11,0,0,0,0,1,16,10,1,0,0,0,0,12,13,4,0,0,0,0,0,12,1,12,0,0,0,0,1,10,2,14,0,0,0,0,0,11,14,5,0,0,0],
[0,0,6,14,4,0,0,0,0,0,11,16,10,0,0,0,0,0,8,14,16,2,0,0,0,0,1,12,12,11,0,0,0,0,0,0,0,11,3,0,0,0,0,0,0,5,11,0,0,0,1,4,4,7,16,2,0,0,7,16,16,13,11,1],
[0,0,3,13,11,7,0,0,0,0,11,16,16,16,2,0,0,4,16,9,1,14,2,0,0,4,16,0,0,16,2,0,0,0,16,1,0,12,8,0,0,0,15,9,0,13,6,0,0,0,9,14,9,14,1,0,0,0,2,12,13,4,0,0],
[0,0,0,2,16,16,2,0,0,0,0,4,16,16,2,0,0,1,4,12,16,12,0,0,0,7,16,16,16,12,0,0,0,0,3,10,16,14,0,0,0,0,0,8,16,12,0,0,0,0,0,6,16,16,2,0,0,0,0,2,12,15,4,0],
[0,0,8,16,5,0,0,0,0,1,13,11,16,0,0,0,0,0,10,0,13,3,0,0,0,0,3,1,16,1,0,0,0,0,0,9,12,0,0,0,0,0,3,15,5,0,0,0,0,0,14,15,8,8,3,0,0,0,7,12,12,12,13,1],
[0,1,8,12,15,14,4,0,0,3,11,8,8,12,12,0,0,0,0,0,2,13,7,0,0,0,0,2,15,12,1,0,0,0,0,0,13,5,0,0,0,0,0,0,9,13,0,0,0,0,7,8,14,15,0,0,0,0,14,15,11,2,0,0],
[0,0,0,0,12,2,0,0,0,0,0,6,14,1,0,0,0,0,4,16,7,8,0,0,0,0,13,9,0,16,6,0,0,6,16,10,11,16,0,0,0,0,5,10,13,16,0,0,0,0,0,0,6,16,0,0,0,0,0,0,12,8,0,0],
[0,0,12,8,8,7,0,0,0,3,16,16,11,7,0,0,0,2,14,1,0,0,0,0,0,5,14,5,0,0,0,0,0,2,15,16,9,0,0,0,0,0,0,2,16,2,0,0,0,0,4,8,16,4,0,0,0,0,11,14,9,0,0,0],
[0,0,1,13,14,3,0,0,0,0,8,16,13,2,0,0,0,2,16,16,3,0,0,0,0,3,16,12,1,0,0,0,0,5,16,14,5,0,0,0,0,3,16,16,16,16,6,0,0,1,14,16,16,16,12,0,0,0,3,12,15,14,7,0],
[0,0,0,8,14,14,2,0,0,0,0,6,10,15,11,0,0,0,0,0,0,14,10,0,0,2,8,11,12,16,8,0,0,8,16,16,16,16,7,0,0,0,0,0,11,15,1,0,0,0,0,9,16,7,0,0,0,0,0,12,13,1,0,0],
[0,0,10,11,4,0,0,0,0,0,10,15,13,13,1,0,0,0,8,11,0,14,4,0,0,0,0,13,15,13,0,0,0,1,11,16,16,0,0,0,0,1,15,3,9,10,0,0,0,0,14,6,15,10,0,0,0,0,8,14,7,1,0,0],
[0,0,9,13,7,0,0,0,0,0,12,16,16,2,0,0,0,0,12,13,16,6,0,0,0,0,6,16,16,14,0,0,0,0,0,0,2,16,3,0,0,0,0,0,0,9,10,0,0,0,3,7,12,14,16,2,0,0,7,12,12,12,11,0],
[0,0,10,14,11,3,0,0,0,4,16,13,6,14,1,0,0,4,16,2,0,11,7,0,0,8,16,0,0,10,5,0,0,8,16,0,0,14,4,0,0,8,16,0,1,16,1,0,0,4,16,1,11,15,0,0,0,0,11,16,12,3,0,0],
[0,0,2,13,8,0,0,0,0,0,6,16,16,6,0,0,0,0,5,15,13,11,0,0,0,0,0,7,16,15,0,0,0,0,0,0,0,14,3,0,0,0,0,0,0,7,11,0,0,0,0,3,4,4,16,2,0,0,2,15,13,14,13,2],
[0,2,13,16,16,16,11,0,0,5,16,10,5,4,1,0,0,6,16,7,3,0,0,0,0,9,16,16,16,6,0,0,0,3,8,4,11,15,0,0,0,0,0,1,12,15,0,0,0,0,4,13,16,6,0,0,0,2,16,15,8,0,0,0],
[0,6,13,5,8,8,1,0,0,8,16,16,16,16,6,0,0,6,16,9,6,4,0,0,0,6,16,16,15,5,0,0,0,0,4,5,15,12,0,0,0,0,0,3,16,9,0,0,0,1,8,13,15,3,0,0,0,4,16,15,3,0,0,0],
[0,0,0,5,14,2,0,0,0,0,1,13,11,0,0,0,0,0,5,16,2,0,0,0,0,0,6,15,5,0,0,0,0,1,15,16,15,11,1,0,0,2,13,14,1,12,9,0,0,0,4,16,7,13,9,0,0,0,0,5,16,15,3,0],
[0,3,15,8,8,6,0,0,0,4,16,16,16,13,2,0,0,3,16,9,2,0,0,0,0,2,16,16,15,3,0,0,0,0,7,6,12,9,0,0,0,0,0,1,14,10,0,0,0,0,5,14,15,2,0,0,0,1,15,14,1,0,0,0],
[0,0,6,14,10,2,0,0,0,0,15,15,13,15,3,0,0,2,16,10,0,13,9,0,0,1,16,5,0,12,5,0,0,0,16,3,0,13,6,0,0,1,15,5,6,13,1,0,0,0,16,11,14,10,0,0,0,0,7,16,11,1,0,0],
[0,0,13,10,1,0,0,0,0,5,16,14,7,0,0,0,0,4,16,8,14,0,0,0,0,2,14,16,16,6,0,0,0,0,1,4,9,13,1,0,0,0,0,0,0,13,6,0,0,0,5,8,5,9,14,0,0,0,13,13,15,16,13,0],
[0,0,7,7,13,16,4,0,0,0,13,13,6,12,7,0,0,0,10,4,10,11,1,0,0,0,8,16,10,0,0,0,0,3,14,16,0,0,0,0,0,8,8,11,5,0,0,0,0,4,10,9,8,0,0,0,0,1,11,16,6,0,0,0],
[0,1,9,16,13,7,0,0,0,7,14,4,10,12,0,0,0,6,15,9,16,11,0,0,0,0,9,11,7,14,0,0,0,0,0,0,0,15,2,0,0,0,0,0,0,11,6,0,0,3,13,8,5,14,5,0,0,0,9,14,13,10,1,0],
[0,0,11,10,12,4,0,0,0,0,12,13,9,16,1,0,0,0,7,13,11,16,0,0,0,0,1,16,14,4,0,0,0,0,10,16,13,0,0,0,0,0,14,7,12,7,0,0,0,4,14,4,12,13,0,0,0,1,11,14,12,4,0,0],
[0,0,0,9,15,1,0,0,0,0,4,16,12,0,0,0,0,0,15,14,2,11,3,0,0,4,16,9,4,16,10,0,0,9,16,11,13,16,2,0,0,0,9,16,16,14,0,0,0,0,0,8,16,6,0,0,0,0,0,9,16,2,0,0],
[0,0,0,0,12,5,0,0,0,0,0,2,16,12,0,0,0,0,1,12,16,11,0,0,0,2,12,16,16,10,0,0,0,6,11,5,15,6,0,0,0,0,0,1,16,9,0,0,0,0,0,2,16,11,0,0,0,0,0,3,16,8,0,0],
[0,0,0,9,15,12,0,0,0,0,4,7,7,14,0,0,0,0,0,0,0,13,3,0,0,4,9,8,10,13,1,0,0,4,16,15,16,16,6,0,0,0,0,0,14,3,0,0,0,0,0,9,12,0,0,0,0,0,0,11,7,0,0,0],
[0,0,9,16,16,16,5,0,0,1,14,10,8,16,8,0,0,0,0,0,7,16,3,0,0,3,8,11,15,16,11,0,0,8,16,16,15,11,3,0,0,0,2,16,7,0,0,0,0,0,8,16,1,0,0,0,0,0,13,10,0,0,0,0],
[0,0,9,16,13,6,0,0,0,0,6,5,16,16,0,0,0,0,0,8,15,5,0,0,0,0,0,5,14,3,0,0,0,0,0,0,9,15,2,0,0,0,0,0,0,11,12,0,0,0,4,8,11,15,12,0,0,0,11,14,12,8,0,0],
[0,1,15,4,0,0,0,0,0,2,16,16,16,14,2,0,0,6,16,11,8,8,3,0,0,5,16,11,5,0,0,0,0,0,11,14,14,1,0,0,0,0,0,5,16,7,0,0,0,0,6,16,16,4,0,0,0,0,14,14,4,0,0,0],
[0,0,0,1,11,9,0,0,0,0,0,7,16,13,0,0,0,0,4,14,16,9,0,0,0,10,16,11,16,8,0,0,0,0,0,3,16,6,0,0,0,0,0,3,16,8,0,0,0,0,0,5,16,10,0,0,0,0,0,2,14,6,0,0],
[0,0,2,15,13,3,0,0,0,0,10,15,11,15,0,0,0,3,16,6,0,10,0,0,0,4,16,8,0,3,8,0,0,8,14,3,0,4,8,0,0,3,15,1,0,3,7,0,0,0,14,11,6,14,5,0,0,0,4,12,15,6,0,0],
[0,0,1,15,13,1,0,0,0,0,7,16,14,8,0,0,0,8,12,9,2,13,2,0,0,7,9,1,0,6,6,0,0,5,9,0,0,3,9,0,0,0,15,2,0,8,12,0,0,0,9,15,13,16,6,0,0,0,0,13,14,8,0,0],
[0,0,0,5,14,12,2,0,0,0,7,15,8,14,4,0,0,0,6,2,3,13,1,0,0,0,0,1,13,4,0,0,0,0,1,11,9,0,0,0,0,8,16,13,0,0,0,0,0,5,14,16,11,2,0,0,0,0,0,6,12,13,3,0],
[0,0,0,3,15,10,1,0,0,0,0,11,10,16,4,0,0,0,0,12,1,15,6,0,0,0,0,3,4,15,4,0,0,0,0,6,15,6,0,0,0,4,15,16,9,0,0,0,0,0,13,16,15,9,3,0,0,0,0,4,9,14,7,0],
[0,0,3,12,16,16,6,0,0,0,10,11,7,16,11,0,0,0,0,0,2,14,10,0,0,5,11,8,9,16,3,0,0,9,16,16,16,16,9,0,0,1,4,9,16,6,0,0,0,0,0,11,14,0,0,0,0,0,4,16,5,0,0,0],
[0,0,4,8,16,5,0,0,0,0,9,16,8,11,0,0,0,0,5,10,0,13,2,0,0,0,0,13,4,15,2,0,0,0,0,9,16,8,0,0,0,0,8,15,14,5,0,0,0,0,16,5,14,4,0,0,0,0,6,16,12,1,0,0],
[0,0,0,1,14,14,3,0,0,0,0,10,11,13,8,0,0,0,0,7,0,13,8,0,0,0,0,0,7,15,1,0,0,4,8,12,15,4,0,0,0,6,16,16,6,0,0,0,0,0,2,12,12,4,2,0,0,0,0,1,13,16,5,0],
[0,0,2,14,15,5,0,0,0,0,10,16,16,15,1,0,0,3,16,10,10,16,4,0,0,5,16,0,0,14,6,0,0,5,16,6,0,12,7,0,0,1,15,13,4,13,6,0,0,0,11,16,16,15,0,0,0,0,2,11,13,4,0,0],
[0,0,0,0,12,13,1,0,0,0,0,8,16,15,2,0,0,0,10,16,16,12,0,0,0,4,16,16,16,13,0,0,0,4,7,4,16,6,0,0,0,0,0,1,16,8,0,0,0,0,0,1,16,8,0,0,0,0,0,0,12,12,0,0],
[0,0,0,1,9,11,0,0,0,0,0,13,16,16,0,0,0,0,0,12,7,14,0,0,0,0,0,0,14,7,0,0,0,0,5,12,12,0,0,0,0,7,16,16,6,0,0,0,0,4,9,13,16,11,4,0,0,0,0,0,9,13,3,0],
[0,0,0,10,13,1,0,0,0,1,11,12,7,0,0,0,0,2,16,12,0,0,0,0,0,4,16,11,0,0,0,0,0,4,16,15,8,4,0,0,0,4,16,16,13,16,6,0,0,0,7,16,7,13,14,0,0,0,0,7,15,15,5,0],
[0,1,10,15,11,1,0,0,0,3,8,8,11,12,0,0,0,0,0,5,14,15,1,0,0,0,0,11,15,2,0,0,0,0,0,4,15,2,0,0,0,0,0,0,12,10,0,0,0,0,3,4,10,16,1,0,0,0,13,16,15,10,0,0],
[0,0,10,15,14,4,0,0,0,0,4,6,13,16,2,0,0,0,0,3,16,9,0,0,0,0,0,1,16,6,0,0,0,0,0,0,10,12,0,0,0,0,0,0,1,16,4,0,0,1,9,5,6,16,7,0,0,0,14,12,15,11,2,0],
[0,0,6,13,16,6,0,0,0,3,16,14,15,16,1,0,0,0,5,0,8,16,2,0,0,0,0,0,8,16,3,0,0,3,15,16,16,16,9,0,0,5,13,14,16,11,3,0,0,0,0,12,15,1,0,0,0,0,4,16,7,0,0,0],
[0,0,14,16,14,6,0,0,0,0,7,10,16,16,3,0,0,0,0,5,16,16,1,0,0,0,0,2,16,8,0,0,0,0,0,0,12,13,1,0,0,0,0,0,4,16,7,0,0,0,5,9,14,16,7,0,0,0,13,16,16,10,1,0],
[0,3,16,16,14,7,1,0,0,1,9,9,15,16,4,0,0,0,0,7,16,12,1,0,0,0,0,9,16,2,0,0,0,0,0,3,15,7,0,0,0,0,0,0,9,15,0,0,0,1,10,10,16,16,3,0,0,2,13,16,12,5,0,0],
[0,0,0,6,16,4,0,0,0,0,1,13,15,1,0,0,0,1,11,16,5,0,0,0,0,8,16,10,0,10,6,0,0,12,16,8,9,16,12,0,0,2,15,16,16,16,7,0,0,0,0,4,16,11,0,0,0,0,0,7,16,3,0,0],
[0,0,0,9,10,0,0,0,0,0,7,16,7,0,0,0,0,0,13,13,1,0,0,0,0,0,15,7,0,0,0,0,0,4,16,15,12,7,0,0,0,2,16,12,4,11,10,0,0,0,8,14,5,9,14,0,0,0,0,6,12,14,9,0],
[0,0,0,10,11,0,0,0,0,0,9,16,6,0,0,0,0,0,15,13,0,0,0,0,0,0,14,10,0,0,0,0,0,1,15,12,8,2,0,0,0,0,12,16,16,16,10,1,0,0,7,16,12,12,16,4,0,0,0,9,15,12,5,0],
[0,0,5,14,0,0,0,0,0,0,12,9,0,0,0,0,0,0,15,3,0,0,0,0,0,1,16,0,0,0,0,0,0,1,16,2,7,4,0,0,0,3,16,16,16,16,9,0,0,0,15,15,4,10,16,0,0,0,4,14,16,12,7,0],
[0,0,0,9,9,0,0,0,0,0,3,16,9,0,0,0,0,3,14,10,0,2,0,0,0,10,16,5,7,15,1,0,0,2,11,15,16,13,1,0,0,0,0,7,16,3,0,0,0,0,0,6,15,0,0,0,0,0,0,4,16,5,0,0],
[0,0,6,12,13,6,0,0,0,6,16,9,12,16,2,0,0,7,16,9,15,13,0,0,0,0,11,15,16,4,0,0,0,0,0,12,10,0,0,0,0,0,3,16,4,0,0,0,0,0,1,16,2,0,0,0,0,0,6,11,0,0,0,0],
[0,0,0,0,14,7,0,0,0,0,0,13,16,9,0,0,0,0,10,16,16,7,0,0,0,7,16,8,16,2,0,0,0,1,5,6,16,6,0,0,0,0,0,4,16,6,0,0,0,0,0,2,16,6,0,0,0,0,0,0,12,11,0,0],
[0,1,13,15,12,12,5,0,0,4,16,8,8,6,0,0,0,7,13,0,0,0,0,0,0,8,15,13,15,7,0,0,0,1,6,5,8,12,0,0,0,0,0,0,12,11,0,0,0,0,2,13,14,1,0,0,0,3,14,10,1,0,0,0],
[0,0,1,13,10,0,0,0,0,7,16,16,16,7,0,0,0,8,16,13,10,15,0,0,0,8,16,2,2,15,3,0,0,5,15,2,0,12,7,0,0,1,15,6,2,16,3,0,0,0,11,15,13,16,0,0,0,0,1,15,14,8,0,0],
[0,1,12,13,4,0,0,0,0,4,16,16,16,3,0,0,0,4,16,16,16,10,0,0,0,0,6,16,14,16,0,0,0,0,0,0,0,16,4,0,0,0,0,0,0,13,7,0,0,1,2,3,7,14,10,0,0,2,12,16,14,12,3,0],
[0,0,13,13,8,2,0,0,0,5,16,16,16,12,0,0,0,1,15,12,0,0,0,0,0,0,12,13,7,1,0,0,0,0,8,16,16,12,0,0,0,0,0,4,9,16,3,0,0,0,1,5,14,15,1,0,0,0,10,16,16,6,0,0],
[0,0,0,0,9,13,0,0,0,0,0,2,16,16,1,0,0,0,0,5,9,15,0,0,0,0,0,0,5,14,0,0,0,0,0,3,15,7,0,0,0,7,16,16,11,0,0,0,0,0,11,14,16,7,3,0,0,0,0,0,9,15,9,0],
[0,3,5,14,13,6,0,0,0,9,16,12,10,12,0,0,0,6,16,3,12,11,0,0,0,1,13,10,16,6,0,0,0,0,10,16,10,0,0,0,0,1,15,16,10,0,0,0,0,0,16,12,16,0,0,0,0,0,3,15,16,5,0,0],
[0,0,0,0,11,15,4,0,0,0,0,3,16,16,12,0,0,0,0,8,14,16,12,0,0,0,0,5,10,16,6,0,0,1,7,11,16,13,0,0,0,9,16,16,14,1,0,0,0,3,8,14,16,9,0,0,0,0,0,1,11,16,12,0],
[0,0,10,12,10,0,0,0,0,3,16,16,16,4,0,0,0,7,15,3,8,13,0,0,0,8,12,0,0,14,1,0,0,8,12,0,0,7,8,0,0,5,13,0,0,4,8,0,0,0,14,8,0,10,8,0,0,0,7,12,13,12,4,0],
[0,0,4,14,11,0,0,0,0,3,15,15,16,9,0,0,0,8,13,0,3,15,1,0,0,8,12,0,0,8,6,0,0,8,12,0,0,8,8,0,0,5,13,1,0,8,8,0,0,2,15,14,12,15,6,0,0,0,5,16,15,8,0,0],
[0,0,0,1,14,13,1,0,0,0,0,1,16,16,3,0,0,5,11,15,16,16,0,0,0,4,15,16,16,15,0,0,0,0,0,8,16,7,0,0,0,0,0,10,16,3,0,0,0,0,0,8,16,6,0,0,0,0,0,2,13,15,2,0],
[0,0,3,14,16,14,0,0,0,0,13,13,13,16,2,0,0,0,1,0,9,15,0,0,0,0,9,12,15,16,10,0,0,4,16,16,16,11,3,0,0,0,4,9,14,2,0,0,0,0,2,15,9,0,0,0,0,0,4,13,1,0,0,0],
[0,0,0,10,15,3,0,0,0,0,7,16,11,0,0,0,0,0,13,15,1,0,0,0,0,0,15,11,0,0,0,0,0,0,16,13,8,1,0,0,0,0,15,16,16,15,6,0,0,0,10,16,14,16,14,2,0,0,1,9,15,16,11,0],
[0,2,13,15,10,4,0,0,0,0,5,4,13,15,2,0,0,0,0,0,11,16,4,0,0,0,0,0,16,12,0,0,0,0,0,0,13,11,0,0,0,0,0,0,8,13,0,0,0,1,6,8,14,12,0,0,0,2,12,14,11,1,0,0],
[0,1,13,15,2,0,0,0,0,6,15,15,9,0,0,0,0,9,8,10,13,0,0,0,0,5,3,12,12,0,0,0,0,0,3,16,6,0,0,0,0,5,15,15,1,0,0,0,0,6,16,15,12,12,11,0,0,1,11,13,16,16,12,0],
[0,0,0,1,16,5,0,0,0,0,0,5,16,11,0,0,0,0,0,12,16,11,0,0,0,7,12,16,16,7,0,0,0,4,8,12,16,4,0,0,0,0,0,9,16,2,0,0,0,0,0,10,16,2,0,0,0,0,0,3,13,5,0,0],
[0,0,2,7,15,13,1,0,0,0,14,12,9,14,8,0,0,0,2,0,0,12,8,0,0,0,0,0,0,13,6,0,0,5,16,16,16,16,5,0,0,2,5,7,13,14,2,0,0,0,0,1,15,5,0,0,0,0,0,11,9,0,0,0],
[0,0,0,9,16,4,0,0,0,1,9,16,13,2,0,0,0,14,16,14,8,0,0,0,1,15,15,5,16,9,0,0,0,5,16,16,16,8,0,0,0,0,2,13,16,1,0,0,0,0,0,11,13,0,0,0,0,0,0,11,13,0,0,0],
[0,0,0,10,11,0,0,0,0,0,3,16,10,0,0,0,0,0,8,16,0,0,0,0,0,0,12,14,0,0,0,0,0,0,14,16,15,6,0,0,0,0,12,16,12,15,6,0,0,0,7,16,10,13,14,0,0,0,0,9,13,11,6,0],
[0,0,13,16,15,4,0,0,0,0,9,8,13,16,3,0,0,0,0,0,13,16,7,0,0,0,0,1,16,12,0,0,0,0,0,0,15,10,0,0,0,0,0,0,8,15,0,0,0,0,3,6,15,16,7,0,0,0,15,16,16,11,1,0],
[0,0,0,1,12,8,1,0,0,0,0,4,16,16,1,0,0,0,1,13,16,11,0,0,0,1,11,16,16,12,0,0,0,2,12,8,16,10,0,0,0,0,0,0,15,8,0,0,0,0,0,4,16,4,0,0,0,0,0,3,13,4,0,0],
[0,4,14,16,16,12,1,0,0,2,12,7,14,16,6,0,0,0,0,5,16,10,0,0,0,0,0,4,16,7,0,0,0,0,0,4,16,6,0,0,0,0,0,1,15,11,0,0,0,1,8,10,16,10,0,0,0,5,16,16,15,1,0,0],
[0,0,9,13,14,5,0,0,0,4,16,10,13,16,0,0,0,0,13,15,14,16,1,0,0,0,0,3,7,16,3,0,0,0,0,0,4,16,0,0,0,0,0,0,1,16,3,0,0,1,15,5,8,16,2,0,0,0,7,15,16,9,0,0],
[0,0,0,11,16,5,0,0,0,0,0,10,16,5,0,0,0,0,4,16,16,5,0,0,0,11,16,16,16,3,0,0,0,5,8,14,16,2,0,0,0,0,0,14,16,2,0,0,0,0,0,11,16,2,0,0,0,0,0,8,16,8,0,0],
[0,0,3,12,16,10,0,0,0,2,14,12,12,12,0,0,0,5,10,0,10,11,0,0,0,0,0,1,14,9,2,0,0,0,8,16,16,16,10,0,0,0,6,16,13,7,0,0,0,0,0,16,5,0,0,0,0,0,5,13,0,0,0,0],
[0,0,0,11,16,8,0,0,0,0,6,16,13,3,0,0,0,0,8,16,8,0,0,0,0,0,13,16,2,0,0,0,0,0,15,16,5,0,0,0,0,2,16,16,16,5,0,0,0,1,10,16,16,14,0,0,0,0,0,12,16,15,0,0],
[0,1,9,16,15,10,0,0,0,6,16,8,7,16,3,0,0,0,11,14,16,11,1,0,0,1,13,16,6,0,0,0,0,8,15,16,3,0,0,0,0,5,14,10,11,0,0,0,0,0,15,7,16,3,0,0,0,0,11,16,8,0,0,0],
[0,0,0,3,14,1,0,0,0,0,0,13,12,1,0,0,0,0,7,16,5,3,0,0,0,3,15,11,5,16,2,0,0,5,16,11,11,16,6,0,0,0,6,12,16,13,3,0,0,0,0,1,15,7,0,0,0,0,0,2,16,7,0,0],
[0,2,15,16,16,13,2,0,0,1,10,8,14,16,8,0,0,0,0,0,16,15,1,0,0,0,0,0,16,8,0,0,0,0,0,0,14,14,0,0,0,0,0,0,11,16,1,0,0,2,14,13,16,16,3,0,0,2,15,16,14,5,0,0],
[0,0,1,15,13,0,0,0,0,0,1,16,16,5,0,0,0,0,7,16,16,0,0,0,0,0,13,16,13,0,0,0,0,7,16,16,13,0,0,0,0,1,11,16,13,0,0,0,0,0,2,16,16,0,0,0,0,0,1,14,16,3,0,0]
]
export const testLabels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 9, 5, 5, 6, 5, 0, 9, 8, 9, 8, 4, 1, 7, 7, 3, 5, 1, 0, 0, 2, 2, 7, 8, 2, 0, 1, 2, 6, 3, 3, 7, 3, 3, 4, 6, 6, 6, 4, 9, 1, 5, 0, 9, 5, 2, 8, 2, 0, 0, 1, 7, 6, 3, 2, 1, 7, 4, 6, 3, 1, 3, 9, 1, 7, 6, 8, 4, 3, 1];
export const testResults2D = [
[-5.143780305349707, -2.5671849569488616],
[4.995176133810635, 2.5965849735960616],
[4.6222573528541195, 0.7484388202104252],
[-0.23893280866794067, -2.3894217277547574],
[3.8216947866212427, 3.604325608202465],
[-0.8709911223696308, -2.1282149782202637],
[2.81844275442799, 4.261801561329653],
[3.985242946889707, -0.69987158462082],
[2.5284916251895444, -1.1717656494894668],
[-1.1298218377874478, -2.0309819209879776],
[-4.948353903108204, -2.2610065007394597],
[5.699199110791917, 2.877521090385841],
[1.3286051310764506, -1.5204832935580381],
[-0.19671964605119277, -1.596286230364697],
[3.9570111329958686, 3.2758570149544686],
[1.480375921466857, -0.21889058755079255],
[2.13395255568376, 4.067673257375693],
[4.350679484478442, -1.0921026099289],
[2.557272070095345, -0.6584862616536931],
[-0.6280886867504241, -2.6005372521893624],
[-4.951734534828008, -2.4317574249282763],
[5.852195575975039, 2.683552415493007],
[1.2673544881756855, -1.7652377046307073],
[0.27834352770569465, -1.2263441812138562],
[4.203201251314217, 3.558689446601454],
[1.839093964057868, -0.32070267402461533],
[2.7402909986130384, 3.748514695536701],
[4.775870513157077, -1.2882767672080533],
[2.6680274630025087, -1.060172254152725],
[-0.8890871150861309, -2.5406054355985],
[-5.199219365246346, -2.5439548747978544],
[-0.7742912077362485, -2.4924772238682538],
[1.2101317364796087, -0.35983641761170776],
[1.3903614428637778, -0.5810630253592894],
[2.3312708440231273, 3.895422135976703],
[1.314610523244508, -0.4483167485489965],
[-4.809219291666345, -2.67224397563046],
[-0.9330458817876642, -2.6887418499828972],
[2.7222830858039107, -0.24300134035081575],
[-0.537006977044404, -2.131989085370945],
[2.5840966544219466, -0.8742501821039962],
[3.9067723616717593, 3.2304268903335442],
[5.807179557496094, 2.81976387725541],
[4.713582746786369, -1.0630236450960113],
[3.9641348734902975, -0.8967473157539272],
[-0.01530404877843643, -2.038490150958936],
[1.722873318704653, -0.6231473558362151],
[5.525874058784288, 2.579474068671955],
[-5.122152010646219, -1.9559304813772806],
[-4.909827414454853, -2.0381460953648247],
[4.435235743327855, 0.8087691590587817],
[4.776283370939164, 0.5623242625671616],
[4.509813103087742, -1.2722181689692529],
[3.0463351139730444, -0.8555512042899034],
[4.725418433330528, 0.5816264030007843],
[-4.649522276017468, -2.4558056605042777],
[5.735211401229367, 2.572494889130049],
[4.737476680160634, 0.8090144113193056],
[2.6457554352277217, 3.8441381986893037],
[0.044581381624577684, -1.6680091087552553],
[0.19114681572811032, -1.9416261786294828],
[4.240988491390998, -1.2283750038224575],
[0.033047744155285615, -1.6942531784944643],
[0.210357401540182, -1.5529939111833393],
[3.7843164767414215, 3.3752214765548647],
[2.3144307157068273, 3.720756280006736],
[2.548752989928164, 4.217062982760938],
[2.5197488164345256, 3.8180966717310905],
[4.312121231767462, 3.073116273541051],
[3.185703087156189, -0.43873712206302057],
[5.385753546184886, 3.0132761685647913],
[1.3110498934462607, -0.17522840170490206],
[-4.764009567265803, -2.316651916353176],
[-0.9188046781255212, -2.371412876499229],
[1.5926491058153243, -0.4728096731292803],
[4.947034446292605, 0.6912887747637944],
[2.982800179052141, -0.19053947432288632],
[4.906581467579906, 0.6288331829907543],
[-5.26150429961407, -2.081657583184234],
[-5.219440756729904, -2.2310942986208833],
[5.600877498649305, 2.4307033874744346],
[4.258399881791161, -1.1351423590515684],
[2.5188641178920497, 4.107750982721579],
[0.3264943601798401, -1.4395225384895831],
[1.6075393800777409, -1.7664958459209985],
[5.287144028790786, 2.740148154739708],
[4.482899087116274, -1.3737458694813844],
[4.455288440369896, 2.880675270281383],
[2.3066608854113504, 4.087990208296346],
[0.002310248832477981, -1.4675603226569485],
[5.595577005423542, 2.7708126642925532],
[0.4656167622568051, -1.2306090656722155],
[-0.4643213501515245, -1.9444537727637536],
[5.0352286799455, 2.7955713231541415],
[4.178213509614446, -1.2438448661365353],
[2.842812133288208, 3.9554256472054883],
[2.717878167304611, -0.3231556631453297],
[4.078991558237693, 3.3734852571453176],
[0.3851783401659291, -1.3515285398938426],
[4.669846645209024, 2.73779208827989],
[-2.904975618700953, 3.683494083841041],
[-0.879124321765863, -0.4426951405143409],
[-5.681244379231256, -0.7285120769550153],
[-10.97656385005008, -1.7526666493055492],
[-0.31624613607402396, 1.1790435717043253],
[-10.335486943961724, -1.7263038658200893],
[1.0183234049896575, 1.5616783163531822],
[-6.670890452694134, -2.599411074380109],
[-7.427928924098714, -1.05418551144876],
[-10.056474336257683, -1.7483236829216935],
[-2.84058073813134, 3.4605708652841742],
[-1.5561486242848588, -0.7689145308285977],
[-9.618253615211268, -0.9363390901794612],
[-10.96225008756357, -2.7757046759437696],
[-0.5471130812484319, 1.0412069799695824],
[-8.468671293896426, -1.9946633211861478],
[1.7476633852483103, 1.7135835405359496],
[-6.060552685379354, -2.5918267819546004],
[-7.612742599715047, -1.5731281884494046],
[-10.686213384810973, -1.2269058958867671],
[-2.8003412175539504, 3.516631590760736],
[-1.7105731474897927, -0.4229854943104262],
[-9.687787910507133, -0.8332650324863461],
[-11.562098613314996, -2.8768460480875233],
[-0.6169436126132575, 0.9271669091731843],
[-8.263457345038251, -1.7749721223830195],
[1.2702831264161745, 1.1345515631395546],
[-5.625939784888585, -2.81705722551124],
[-7.321567272072983, -1.1714267827612699],
[-10.498673585109545, -1.4172021055405306],
[-2.8361027291899963, 3.7566550423427216],
[-10.742499099483476, -1.3312462253382054],
[-8.742331565355999, -1.962339327316867],
[-8.683249673946568, -1.7431070207306547],
[1.519913836537469, 1.5812210418530623],
[-8.639230381438411, -1.83626003754962],
[-3.0714622950362083, 3.360214813815334],
[-10.321920349887177, -1.2166199317699589],
[-7.479960982731633, -2.0085158275034654],
[-10.64339464722167, -1.98466938098528],
[-7.444943872419686, -1.3202152645583067],
[-0.6659047931509448, 1.0689298563354555],
[-1.337476996462183, -0.7062062107669966],
[-5.722954727686442, -2.614991713970329],
[-6.535367593759711, -2.8240481849859242],
[-11.07458350701865, -2.1857932277021],
[-8.465490267069768, -1.5262082312357834],
[-1.4028562692810291, -0.3234834011238395],
[-2.303657152463291, 3.4811020923228124],
[-2.7185070579122725, 3.1727811960040686],
[-5.769483048641313, -0.9860570623329065],
[-5.615815263813969, -0.6062651823744999],
[-5.912314417301917, -2.8274353398822054],
[-6.979235936333255, -1.3486153549845195],
[-5.580947395294925, -0.8487153054662616],
[-2.519127036098348, 3.235839368692096],
[-1.5666266264773967, -0.4084044324487192],
[-5.482920294320904, -0.7132829553293972],
[1.291443869275501, 1.2088921598961009],
[-10.996594305162729, -2.7052817764388934],
[-11.230034148536227, -2.3267787723370223],
[-6.172936702531247, -2.8092873015313207],
[-11.31268843509639, -2.4664461470306835],
[-11.383742431873435, -2.526000902907926],
[-0.5135436868771529, 1.219682963441809],
[1.6600210033832736, 1.2986546898831781],
[1.3440665949247865, 1.6471365427370084],
[1.4289155033476695, 1.3398242847863313],
[-0.749955073590225, 0.5597391612835082],
[-7.196844128522498, -2.2154060964753044],
[-1.287126546227924, -0.1161850904218144],
[-8.736469581347375, -2.133470874953044],
[-2.6244524948342693, 3.2661482243617606],
[-10.488890956441548, -1.518682221199595],
[-9.080187424004665, -1.7921945653042823],
[-5.409549676705336, -0.7562583268806944],
[-7.131907767719736, -1.7819102538183373],
[-5.3945164159653105, -0.6311831012797511],
[-2.4235633967787837, 3.5752787074610253],
[-2.5646735303118913, 3.6545463352449956],
[-1.6293939125209715, -0.3261124147226215],
[-6.174169159339828, -2.816398862346779],
[1.5011647046090915, 1.4604002557978188],
[-11.415289227608609, -2.784266265081746],
[-9.372108978232719, -0.6382375099773951],
[-1.1395765495328711, -0.4341112548365201],
[-5.90712646029175, -2.693143905929763],
[-0.8163580669991641, 0.27205961797264744],
[1.6757381906829827, 1.6959697431903369],
[-11.377447482142799, -2.463933981648078],
[-1.4565032357599115, -0.5951550644235234],
[-11.521681218113521, -2.939480142411405],
[-10.698652055676758, -2.14080724624675],
[-0.8906495642468407, -0.3084980108495706],
[-6.20543225894981, -2.712538184223933],
[1.074802277722911, 1.3366879290550757],
[-7.369542577049855, -1.7665150872563606],
[-0.6479104154512673, 0.8639090216770717],
[-11.63001115748303, -2.7650660117667964],
[-0.6177124196423712, -0.1336295015576095],
];
export const testResults3D = [
[-4.999350449966068, 1.646552093740238, 6.3209980182331975],
[2.8403788682574507, -2.5690234752364147, -0.4063832276708564],
[1.1833348034999547, -0.165914769440034, 1.4483763129412357],
[-3.1000569670380917, -3.388348490548774, 2.2939590758551605],
[1.590391725722708, -3.159107792780017, -0.9666315282361507],
[-2.3951803756711763, -2.875537534248424, 2.4888844450685776],
[1.3134087868452626, -4.839205855767238, -1.4684113194648682],
[-0.05862699213124383, -0.3230787022271161, 0.3909466032385804],
[-0.9818650602760947, -1.89052036738796, 0.7831797526779974],
[-2.2526555755620996, -2.6802831924164634, 2.546448994000601],
[-4.82304267864745, 1.6782749542805708, 6.351005545201137],
[3.525376540737558, -2.1831045439643115, -0.1957704511804789],
[-1.3146982433476153, -3.0779917025822088, 1.4477889446578915],
[-3.490624389399593, -3.2725536497663685, 2.4076973946962608],
[1.6046015330295582, -2.9611434864309123, -0.8593780060905368],
[-1.699544447645836, -1.642749673631885, 2.015345569855638],
[1.7342846706650423, -5.127050467625386, -1.2229636945836426],
[0.30235720908299474, -0.6590498012692595, -0.21010853583241784],
[-0.7547891213532484, -1.381181459704983, 1.2857859039621202],
[-2.405143781147724, -3.294790972121255, 2.2339921983105673],
[-4.6888145239183325, 1.5957495338043912, 6.066524279171597],
[3.3907864120350832, -1.9697227304551028, -0.35126345189817587],
[-1.1889833308558972, -2.986842318867589, 1.3290839509807597],
[-4.1965163088295805, -3.009606414989964, 2.280004284648866],
[1.8699507344843387, -2.8901613072466716, -0.830600419412514],
[-1.2517787389701411, -2.099937874882709, 1.7839399829560294],
[1.0708917156374802, -5.040659939484485, -1.451089571553497],
[0.6813397108314285, -0.2074722715948495, -0.11836522421473296],
[-0.9766999659990082, -1.599977553076435, 0.824970498549993],
[-2.4945221961883095, -3.1658696739622645, 2.3823771637216384],
[-4.899229005965406, 1.7685435183795715, 6.293268077232492],
[-2.7051503141017026, -3.4719168522662587, 2.365737648189881],
[-1.9250994663697636, -1.7104462379875267, 1.9011547899945314],
[-1.4894481361535463, -1.732734586496755, 1.8509188748432408],
[1.6165372485356557, -5.25131988631751, -1.3897749464436084],
[-1.5603087626214696, -1.815181035578557, 2.017380726207842],
[-4.71864837981744, 1.7869497011017945, 6.061729388856058],
[-2.2739760859343447, -3.0147636299303313, 2.262607608591685],
[-0.37109251169327256, -1.1043002671291442, 1.0253167282728668],
[-2.820969623808371, -3.0998329038438954, 2.396036632479787],
[-0.7005607382673469, -1.7002270390752574, 1.0510004240728807],
[1.4857504726622819, -2.833454022851123, -0.7149842931614216],
[3.1282727732040945, -2.240629557759072, -0.0194703003215026],
[0.49722410525448624, -0.1790547436210475, -0.1421387277822053],
[0.09781766189320759, -0.28309361000508254, 0.11780357683695647],
[-3.4873494863453067, -3.19663433127773, 2.607053817631071],
[-1.394546863463544, -1.8089301809170706, 1.7570392550055467],
[2.9492357183007285, -1.9585154862269956, -0.20808421980550004],
[-5.22357074906259, 1.6412010189222608, 6.044869008419269],
[-4.936611792437089, 1.829959701430522, 5.923757132103001],
[0.9856428272100313, -0.31122638985417883, 1.541888220378777],
[1.209163223244167, -0.4747701233033356, 1.6411155325893954],
[0.5298261787649933, -0.18663156089989155, 0.008270161212818027],
[-0.6662589815711999, -1.5607703637790205, 0.6435066358899714],
[1.418352281412417, -0.10764807283588383, 1.575872378114067],
[-4.555240623023682, 1.8072087498418707, 5.997825982675267],
[3.240143630100305, -1.9405200267144476, -0.31965641342931356],
[1.1499922939227833, -0.13459454836021864, 1.4272000080679261],
[1.6125476149045925, -5.1173136191753255, -1.7881270717654334],
[-3.6921959180484194, -3.3362767681393577, 2.179679240287428],
[-3.639459381261774, -3.117905607643891, 2.6472262960333692],
[0.2672042131204365, -0.5473997771077008, -0.05256561727345535],
[-3.7867686621215686, -2.8810304365179067, 2.582320769649838],
[-3.681651559523735, -3.088412486403305, 2.1989283128863546],
[1.477354480495836, -3.260757038729244, -1.0437334227819175],
[1.6462343893664715, -5.435555225918037, -1.6470710736463636],
[1.2719000848697173, -5.126682698632477, -1.7308887248203841],
[1.4942032644533132, -5.3640282721966805, -1.7989180398291422],
[1.913146785959154, -2.670915961959593, -0.6102127487772651],
[-0.2666484245094862, -1.0509976847223497, 0.8887493609418966],
[2.761473665451152, -2.2322803100331896, -0.08863916205797434],
[-1.7477489634205088, -1.5034624344789653, 1.8925715460796828],
[-4.731658917279828, 1.619745871364001, 5.874739099513872],
[-2.6555095221862364, -3.152804976526936, 2.4672114874195223],
[-1.709548442921802, -2.079181153742936, 2.0356373609865734],
[1.3596836250512536, -0.40332367575202277, 1.75177442940566],
[-0.20994833636849541, -1.5145952417600825, 1.0002114686085513],
[1.3207286114722674, -0.37340290400290377, 1.6787482056261671],
[-5.016050260138233, 1.4175111257931283, 5.899202327823393],
[-5.086724718741249, 1.5716093961869941, 6.03921201073803],
[3.263628017045966, -2.1117059598812458, -0.2055704803785597],
[0.24954732478375738, -0.2744252184542143, -0.014025851345480516],
[1.3359119235590569, -5.059645167131039, -1.561291300506062],
[-4.142837978742523, -2.847555281383964, 2.365603896961519],
[-0.9876231037669517, -3.062436809528216, 1.1199266838170152],
[2.906269122259462, -2.1934723519520247, -0.2935571114446365],
[0.4710945591432627, -0.4299725417899055, -0.223741599405139],
[2.164485907769525, -2.6518022877928185, -0.3949457076901189],
[1.5259368040909012, -5.11023176969685, -1.4155841804050042],
[-3.981046073547551, -3.100456373177016, 2.537924405568087],
[3.284582468988006, -2.0483724751519388, -0.05740936342908974],
[-3.9841636152475797, -2.901866851447435, 2.121223171846165],
[-3.0684236712372885, -3.0875360469144475, 2.4519377771603685],
[2.7093458942682282, -2.43935208804615, -0.3692812783851062],
[0.1480354518578467, -0.6060598102883284, 0.26434812544520253],
[1.172039183700656, -4.945614883308257, -1.1645387626634054],
[-0.3753833108922356, -1.4087919745438744, 1.125599123595257],
[1.7756200715237602, -2.9946438767029977, -0.8977646263946848],
[-3.9816581390155883, -2.9834721053610984, 2.28207294450481],
[2.556782981012287, -2.8317270564242976, -0.4581508277984368],
[7.689216888038721, 5.889500760682107, -0.9372910704861791],
[1.6289201733408833, 0.09644154452992573, -0.6515193779268037],
[1.8064203152613236, 1.0408971830461913, -3.759296358413371],
[3.719252646835446, 6.2652682378361995, -5.453359288044545],
[2.208579439712507, 1.459095083827724, 0.12000156409675383],
[3.2249615957947833, 5.960024670787041, -4.8481645679297305],
[1.72709168751186, 2.663674819440392, 2.0862843204012536],
[1.4390793446753154, 3.110175910025147, -2.64329402984594],
[2.322369780334226, 3.854174748115889, -4.1940933254107895],
[3.172586988457068, 5.988043163212074, -4.489868026985644],
[7.774232233860294, 5.728604682804332, -0.7492809764488474],
[1.216760464557976, 0.12651789052380594, -1.1160899217216294],
[2.9761272550252342, 5.127354763494007, -3.789929920251627],
[3.623435292999969, 6.467545035827176, -5.742880703018387],
[2.191615075396111, 1.3462025439777128, -0.06012668392608021],
[1.9792286512470967, 5.048455808227712, -4.503864167574659],
[2.289319043749516, 2.479364102096565, 2.06509502307054],
[1.7522008547912962, 3.028100683362274, -1.9757439514197939],
[1.9133011076476316, 3.976012857253692, -3.654786899504835],
[3.126237934842212, 6.121493120485744, -4.9163292854727025],
[7.59812385730979, 5.945122300518597, -0.5466031795420292],
[1.0642820336951215, -0.10032610638546975, -1.272495749311577],
[2.9120539005610295, 4.9615417834931055, -3.6557913237121338],
[3.6667322868678744, 6.432934502429571, -6.475883464450793],
[1.985579003136723, 1.1529793819422138, -0.14330347191913095],
[2.536689758242814, 4.94651699436971, -4.188789564228635],
[1.7588493803085914, 2.820477258013995, 2.356610282996252],
[1.3544004702547257, 2.5228876142069545, -2.0848215214143417],
[2.18648006037277, 3.6254018053870727, -4.0692699701558235],
[3.3080002706216582, 6.170491494769027, -4.909354375701165],
[7.838430931939201, 5.962279999222033, -0.8501265755322832],
[3.146812853890534, 6.420570628535107, -5.128511955440203],
[2.1655492350855243, 5.133684793191488, -4.794337818504037],
[2.156182788918373, 4.779020022109626, -4.458168130007138],
[2.1868295164680163, 2.651935395462085, 1.9402408691766964],
[2.1122898435485626, 5.101805045252335, -4.376461605992093],
[7.759497394541325, 5.99608504530489, -0.5721002846060569],
[3.2698139531816732, 5.945075221007509, -4.716167049727797],
[1.9537425223452107, 3.7990956170037817, -3.1702963336135563],
[3.5638849988193715, 6.286648383473683, -5.057728780776639],
[2.2260271578133892, 3.9062531861533376, -3.7926834207621583],
[2.3487636315682385, 1.2733078093794485, -0.20521957587061831],
[1.4763516191715822, -0.07339630024515807, -1.2568913530002406],
[1.4457541418594435, 2.6678280144185633, -1.968673498837688],
[1.3665146037972555, 3.1104612289267797, -2.3362646187488014],
[3.8775155788281355, 6.65251928161629, -5.665014425209378],
[2.243781465166822, 4.810096665722539, -4.325776535824173],
[1.3113157069794292, -0.3907556024946346, -0.9674678142514966],
[7.4707557181542885, 6.068425618027565, -0.9016754062087259],
[7.719682010298653, 6.293792082295646, -0.6943491194702454],
[1.889160988739313, 1.2825076320476096, -3.8797729494317945],
[1.528848553082611, 1.2588606673105436, -3.8859071748383442],
[1.328663194953698, 2.6696166169691624, -2.2155627880306157],
[2.1544579217204247, 3.4833076529627025, -3.93081895871594],
[1.678647726543417, 1.350749170768083, -3.6472298500923848],
[7.779378974045683, 5.941065599050965, -0.3768179153485322],
[1.090599105664963, -0.21897555239951227, -1.1245858483752145],
[1.9004151266296854, 1.0016306087525904, -3.8240643093652547],
[1.79519610139777, 3.072747351366555, 1.9924133395724823],
[3.385643758056163, 6.481555639718136, -5.946525871558117],
[3.739617985672955, 6.7734869473964165, -5.791002799859846],
[1.68329653285918, 2.9352559918931376, -2.1240958308135625],
[3.8689936660063227, 6.450100300090818, -5.863677747356829],
[3.5227324662391934, 6.304799948350529, -6.015458718806657],
[2.347687118964318, 1.422139375121024, 0.22278213875612188],
[2.2180670708690338, 2.9587217481110355, 1.9577285130476965],
[1.8383459478962132, 2.9516924800936106, 1.951773536386326],
[1.9915163516683876, 3.125657869624825, 1.9360001985910298],
[2.0586128716897076, 0.9319526850785679, -0.363347710318456],
[1.972391691031123, 3.8113757348470148, -3.013137897370146],
[1.379201705857466, -0.31634219940793756, -0.8396233794610332],
[1.9982809296461372, 4.979452278680934, -4.6935290145722695],
[7.572434557728682, 6.103563807021123, -0.45238952042062147],
[3.361781071733503, 6.347807072766981, -4.965261048582085],
[2.4457518923571953, 5.208909777707682, -4.488138746033763],
[1.515371062452698, 1.2451955950131388, -4.004308683680948],
[2.327020894876154, 3.945346529979229, -3.214052790232576],
[1.6340689753522157, 1.1646400128291376, -3.9523159112572697],
[7.3434417124707885, 6.210680610725227, -0.7232208833510627],
[7.487203581595136, 6.091453370170096, -0.814759660914381],
[1.2523055479826777, -0.03355046908458365, -1.1445314775885431],
[1.4031260098000506, 2.9095043917838788, -2.2536281371792706],
[1.920464298567037, 2.8073745017850773, 2.2462294375046903],
[3.8813522730544237, 6.681172127785995, -6.326452335509549],
[2.9558363810192625, 4.788647132234979, -3.4553572807116355],
[1.670714138250657, 0.026486419185176892, -0.991392665968696],
[1.581545066906788, 2.7844989846664046, -1.984244575230313],
[1.875907008651662, 0.6952868053471871, -0.5229128767158864],
[2.084307557879972, 2.646840109884875, 2.056998572415541],
[3.5806516860631024, 6.743248753046012, -6.105297199686208],
[1.462558096710222, -0.10092139207798385, -1.1898581884339972],
[3.654706027150071, 6.390585202444062, -6.357892180833042],
[3.6027095941866247, 6.383704215055882, -5.318204043566554],
[1.7245257657018247, 0.192478655399741, -0.7436440052075087],
[1.683165920875281, 3.243957316304348, -2.3259907808966545],
[1.745611159759802, 2.472672662103672, 1.9155422431593778],
[2.177305599456365, 3.9231388710705675, -3.3039650230819726],
[2.068771729441073, 1.222227121468545, -0.02797486874066797],
[3.773289766268219, 6.534098686594626, -6.250642359343324],
[1.7729320319143027, 0.3201914207876183, -0.40659921859631903],
];
export const treeData = {
"hyperplanes": [[0,0,0,-3,-1,11,2,0,0,0,7,3,-6,14,4,0,0,0,3,-14,-4,13,1,0,0,0,-6,-15,11,4,0,0,0,0,-6,-5,-7,-13,-5,0,0,8,1,-3,-9,-9,-14,0,0,5,11,2,2,0,-16,-2,0,0,0,-1,-3,-3,-8,0],[0,-1,-6,12,16,16,5,0,0,-1,-2,-6,-8,2,6,0,0,-6,-16,-11,-1,8,0,0,0,-2,-8,0,10,16,11,0,0,8,5,2,1,10,3,0,0,0,2,11,-9,-7,0,0,0,0,2,0,-15,-4,0,0,0,0,-1,-4,-4,0,0,0],[0,0,3,7,2,4,4,0,0,0,3,-4,-1,2,7,0,0,0,-6,-2,-1,1,9,0,0,5,11,7,-4,12,3,0,0,9,15,5,7,16,9,0,0,-7,-12,-4,16,6,0,0,0,-5,-14,-5,3,-2,0,0,0,0,4,10,-7,-13,-3,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,10,11,-1,-9,0,0,0,3,16,9,0,-9,0,0,0,7,11,-11,-8,4,0,0,0,-2,-4,-11,-16,6,1,0,0,8,12,-3,-16,1,8,0,0,5,13,-3,-16,-4,8,0,0,0,14,3,-16,0,8,0,0,0,7,10,-1,6,4,0],[0,0,10,-6,-7,2,0,0,0,3,6,0,-5,-8,-1,0,0,-1,-2,-9,-10,-16,-4,0,0,0,-2,5,0,-14,-6,0,0,-3,-1,10,9,-12,-7,0,0,-1,-15,-11,12,-11,-6,0,0,0,-7,-8,0,-11,0,0,0,0,9,3,-4,-4,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,-2,-13,-15,-5,-7,-11,0,0,-5,-16,-3,11,9,-1,0,0,-6,-12,7,13,9,0,0,0,1,0,-5,0,2,0,0,0,-3,-8,-1,5,-9,0,0,0,0,0,2,4,-7,0,0,0,0,-4,-8,0,4,0,0,0,-2,-16,-13,6,6,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,2,-1,-3,0,0,0,0,-7,0,3,3,0,0,0,-2,-9,0,13,0,0,0,0,-3,-3,4,12,0,0,0,0,2,0,2,8,0,0,0,0,-2,-5,0,-3,-16,-6,0,0,-1,-12,0,0,-16,-12,0,0,0,-2,2,1,-11,-7,0],[0,0,0,9,1,-6,0,0,0,0,4,3,-4,-9,0,0,0,0,5,-2,-14,4,3,0,0,-3,0,1,-12,14,10,0,0,8,11,5,-3,10,2,0,0,0,9,12,0,8,0,0,0,0,0,6,0,0,0,0,0,0,0,9,4,-9,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,-1,0,-1,0,0,0,0,-5,-2,2,9,14,0,0,0,-4,-3,8,1,10,1,0,0,-2,-3,0,0,1,0,0,0,0,-1,0,-2,3,6,0,0,0,0,0,4,3,3,0,0,0,0,-4,7,7,-10,0,0,0,-4,3,1,-6,-13,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],
"hyperplanes": [
[0,0,0,-3,-1,11,2,0,0,0,7,3,-6,14,4,0,0,0,3,-14,-4,13,1,0,0,0,-6,-15,11,4,0,0,0,0,-6,-5,-7,-13,-5,0,0,8,1,-3,-9,-9,-14,0,0,5,11,2,2,0,-16,-2,0,0,0,-1,-3,-3,-8,0],
[0,-1,-6,12,16,16,5,0,0,-1,-2,-6,-8,2,6,0,0,-6,-16,-11,-1,8,0,0,0,-2,-8,0,10,16,11,0,0,8,5,2,1,10,3,0,0,0,2,11,-9,-7,0,0,0,0,2,0,-15,-4,0,0,0,0,-1,-4,-4,0,0,0],
[0,0,3,7,2,4,4,0,0,0,3,-4,-1,2,7,0,0,0,-6,-2,-1,1,9,0,0,5,11,7,-4,12,3,0,0,9,15,5,7,16,9,0,0,-7,-12,-4,16,6,0,0,0,-5,-14,-5,3,-2,0,0,0,0,4,10,-7,-13,-3,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,10,11,-1,-9,0,0,0,3,16,9,0,-9,0,0,0,7,11,-11,-8,4,0,0,0,-2,-4,-11,-16,6,1,0,0,8,12,-3,-16,1,8,0,0,5,13,-3,-16,-4,8,0,0,0,14,3,-16,0,8,0,0,0,7,10,-1,6,4,0],
[0,0,10,-6,-7,2,0,0,0,3,6,0,-5,-8,-1,0,0,-1,-2,-9,-10,-16,-4,0,0,0,-2,5,0,-14,-6,0,0,-3,-1,10,9,-12,-7,0,0,-1,-15,-11,12,-11,-6,0,0,0,-7,-8,0,-11,0,0,0,0,9,3,-4,-4,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,-2,-13,-15,-5,-7,-11,0,0,-5,-16,-3,11,9,-1,0,0,-6,-12,7,13,9,0,0,0,1,0,-5,0,2,0,0,0,-3,-8,-1,5,-9,0,0,0,0,0,2,4,-7,0,0,0,0,-4,-8,0,4,0,0,0,-2,-16,-13,6,6,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,2,-1,-3,0,0,0,0,-7,0,3,3,0,0,0,-2,-9,0,13,0,0,0,0,-3,-3,4,12,0,0,0,0,2,0,2,8,0,0,0,0,-2,-5,0,-3,-16,-6,0,0,-1,-12,0,0,-16,-12,0,0,0,-2,2,1,-11,-7,0],
[0,0,0,9,1,-6,0,0,0,0,4,3,-4,-9,0,0,0,0,5,-2,-14,4,3,0,0,-3,0,1,-12,14,10,0,0,8,11,5,-3,10,2,0,0,0,9,12,0,8,0,0,0,0,0,6,0,0,0,0,0,0,0,9,4,-9,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,-1,0,-1,0,0,0,0,-5,-2,2,9,14,0,0,0,-4,-3,8,1,10,1,0,0,-2,-3,0,0,1,0,0,0,0,-1,0,-2,3,6,0,0,0,0,0,4,3,3,0,0,0,0,-4,7,7,-10,0,0,0,-4,3,1,-6,-13,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
],
"offsets": [529.5,-244,-709,0,0,-164.5,896.5,0,0,640.5,0,0,381.5,-556,0,0,-263,0,0],
"children": [[1,12],[2,5],[3,4],[-0,-1],[-1,-1],[6,9],[7,8],[-2,-1],[-3,-1],[10,11],[-4,-1],[-5,-1],[13,16],[14,15],[-6,-1],[-7,-1],[17,18],[-8,-1],[-9,-1]],
"indices": [[7,17,23,27,43,44,52,61,81,83,86,89,94,98,-1],[2,13,38,50,51,53,54,57,60,75,77,-1,-1,-1,-1],[22,25,76,84,96,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],[0,8,9,10,20,30,36,39,48,49,55,72,78,79,92],[12,18,28,40,47,56,59,62,63,69,80,-1,-1,-1,-1],[15,32,33,35,46,71,91,-1,-1,-1,-1,-1,-1,-1,-1],[41,68,87,97,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],[1,3,11,19,21,31,42,45,70,85,90,93,99,-1,-1],[4,5,14,24,64,73,74,95,-1,-1,-1,-1,-1,-1,-1],[6,16,26,29,34,37,58,65,66,67,82,88,-1,-1,-1]]};
"indices": [
[7,17,23,27,43,44,52,61,81,83,86,89,94,98,-1],
[2,13,38,50,51,53,54,57,60,75,77,-1,-1,-1,-1],
[22,25,76,84,96,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
[0,8,9,10,20,30,36,39,48,49,55,72,78,79,92],
[12,18,28,40,47,56,59,62,63,69,80,-1,-1,-1,-1],
[15,32,33,35,46,71,91,-1,-1,-1,-1,-1,-1,-1,-1],
[41,68,87,97,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
[1,3,11,19,21,31,42,45,70,85,90,93,99,-1,-1],
[4,5,14,24,64,73,74,95,-1,-1,-1,-1,-1,-1,-1],
[6,16,26,29,34,37,58,65,66,67,82,88,-1,-1,-1],
]
};

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.

@@ -3,0 +3,0 @@ Licensed under the Apache License, Version 2.0 (the "License");

@@ -1,9 +0,6 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software

@@ -16,4 +13,10 @@ distributed under the License is distributed on an "AS IS" BASIS,

import { UMAP } from '../src/umap';
import { testData, testResults2D, testResults3D } from './test_data';
import { UMAP, findABParams, euclidean, TargetMetric } from '../src/umap';
import * as utils from '../src/utils';
import {
testData,
testLabels,
testResults2D,
testResults3D,
} from './test_data';
import Prando from 'prando';

@@ -23,2 +26,8 @@

let random: () => number;
// Expected "clustering" ratios, representing inter-cluster distance vs mean
// distance to other points.
const UNSUPERVISED_CLUSTER_RATIO = 0.15;
const SUPERVISED_CLUSTER_RATIO = 0.04;
beforeEach(() => {

@@ -33,2 +42,3 @@ const prng = new Prando(42);

expect(embedding).toEqual(testResults2D);
checkClusters(embedding, testLabels, UNSUPERVISED_CLUSTER_RATIO);
});

@@ -40,2 +50,3 @@

expect(embedding).toEqual(testResults3D);
checkClusters(embedding, testLabels, UNSUPERVISED_CLUSTER_RATIO);
});

@@ -70,3 +81,3 @@

let nEpochsComputed = 0;
const embedding = await umap.fitAsync(testData, () => {
await umap.fitAsync(testData, () => {
nEpochsComputed += 1;

@@ -93,4 +104,4 @@ });

const umap = new UMAP({ random });
umap.setPrecomputedKNN(knnIndices, knnDistances);
spyOn<any>(umap, 'nearestNeighbors');
umap.initializeFit(testData, knnIndices, knnDistances);
umap.fit(testData);

@@ -100,2 +111,84 @@

});
test('supervised projection', () => {
const umap = new UMAP({ random, nComponents: 2 });
umap.setSupervisedProjection(testLabels);
const embedding = umap.fit(testData);
expect(embedding.length).toEqual(testResults2D.length);
checkClusters(embedding, testLabels, SUPERVISED_CLUSTER_RATIO);
});
test('non-categorical supervised projection is not implemented', () => {
const umap = new UMAP({ random, nComponents: 2 });
// Unimplemented target metric.
const targetMetric = TargetMetric.l1;
umap.setSupervisedProjection(testLabels, { targetMetric });
const embedding = umap.fit(testData);
// Supervision with unimplemented target metric is a noop.
expect(embedding).toEqual(testResults2D);
});
test('finds AB params using levenberg-marquardt', () => {
// The default parameters from the python implementation
const minDist = 0.1;
const spread = 1.0;
// The default results from the python sklearn curve-fitting algorithm
const a = 1.5769434603113077;
const b = 0.8950608779109733;
const epsilon = 0.01;
const params = findABParams(spread, minDist);
const diff = (x: number, y: number) => Math.abs(x - y);
expect(diff(params.a, a)).toBeLessThanOrEqual(epsilon);
expect(diff(params.b, b)).toBeLessThanOrEqual(epsilon);
});
const computeMeanDistances = (vectors: number[][]) => {
return vectors.map(vector => {
return utils.mean(
vectors.map(other => {
return euclidean(vector, other);
})
);
});
};
/**
* Check the ratio between distances within a cluster and for all points to
* indicate "clustering"
*/
const checkClusters = (
embeddings: number[][],
labels: number[],
expectedClusterRatio: number
) => {
const distances = computeMeanDistances(embeddings);
const overallMeanDistance = utils.mean(distances);
const embeddingsByLabel = new Map<number, number[][]>();
for (let i = 0; i < labels.length; i++) {
const label = labels[i];
const embedding = embeddings[i];
const group = embeddingsByLabel.get(label) || [];
group.push(embedding);
embeddingsByLabel.set(label, group);
}
let totalIntraclusterDistance = 0;
for (let label of embeddingsByLabel.keys()) {
const group = embeddingsByLabel.get(label)!;
const distances = computeMeanDistances(group);
const meanDistance = utils.mean(distances);
totalIntraclusterDistance += meanDistance * group.length;
}
const meanInterclusterDistance =
totalIntraclusterDistance / embeddings.length;
const clusterRatio = meanInterclusterDistance / overallMeanDistance;
expect(clusterRatio).toBeLessThan(expectedClusterRatio);
};
});

@@ -1,2 +0,2 @@

/* Copyright 2019 Google Inc. All Rights Reserved.
/* Copyright 2019 Google LLC. All Rights Reserved.

@@ -66,2 +66,7 @@ Licensed under the Apache License, Version 2.0 (the "License");

test('linear function', () => {
const results = utils.linear(0, 5, 5);
expect(results).toEqual([0, 1.25, 2.5, 3.75, 5]);
});
test('sum function', () => {

@@ -87,2 +92,1 @@ const results = utils.sum([1, 2, 3]);

});

@@ -17,2 +17,3 @@ {

"allowUnreachableCode": true,
"downlevelIteration": true,
"lib": ["dom", "es2015", "es2016", "es2017"]

@@ -19,0 +20,0 @@ },

import * as path from 'path';
import * as DtsBundleWebpack from 'dts-bundle-webpack';

@@ -9,5 +8,5 @@ export default {

{
test: /\.ts$/,
test: /(\.ts$|\.js$)/,
exclude: /node_modules/,
use: 'ts-loader',
loader: 'ts-loader',
},

@@ -17,6 +16,6 @@ ],

resolve: {
extensions: ['.ts'],
extensions: ['.ts', '.js'],
},
entry: {
lib: './src/lib.ts',
lib: path.resolve(__dirname, '../src/lib.ts'),
},

@@ -28,9 +27,2 @@ output: {

optimization: { minimize: false },
plugins: [
new DtsBundleWebpack({
name: 'umap-js',
main: 'dist/umap.d.ts',
out: '../lib/umap-js.d.ts',
}),
],
};

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc