UNPKG

molstar

Version:

A comprehensive macromolecular library.

168 lines 6.53 kB
/** * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> */ import { __assign } from "tslib"; import { ArrayEncoding as E } from './array-encoder'; import { getArrayDigitCount } from '../../../mol-util/number'; export function classifyIntArray(xs) { return IntClassifier.classify(xs); } export function classifyFloatArray(xs) { return FloatClassifier.classify(xs); } var IntClassifier; (function (IntClassifier) { function packSize(value, upperLimit) { return value >= 0 ? Math.ceil((value + 1) / upperLimit) : Math.ceil((value + 1) / (-upperLimit - 1)); } function getInfo(data) { var signed = false; for (var i = 0, n = data.length; i < n; i++) { if (data[i] < 0) { signed = true; break; } } return signed ? { signed: signed, limit8: 0x7F, limit16: 0x7FFF } : { signed: signed, limit8: 0xFF, limit16: 0xFFFF }; } function SizeInfo() { return { pack8: 0, pack16: 0, count: 0 }; } ; function incSize(_a, info, value) { var limit8 = _a.limit8, limit16 = _a.limit16; info.pack8 += packSize(value, limit8); info.pack16 += packSize(value, limit16); info.count += 1; } function incSizeSigned(info, value) { info.pack8 += packSize(value, 0x7F); info.pack16 += packSize(value, 0x7FFF); info.count += 1; } function byteSize(info) { if (info.count * 4 < info.pack16 * 2) return { length: info.count * 4, elem: 4 }; if (info.pack16 * 2 < info.pack8) return { length: info.pack16 * 2, elem: 2 }; return { length: info.pack8, elem: 1 }; } function packingSize(data, info) { var size = SizeInfo(); for (var i = 0, n = data.length; i < n; i++) { incSize(info, size, data[i]); } return __assign(__assign({}, byteSize(size)), { kind: 'pack' }); } function deltaSize(data, info) { var size = SizeInfo(); var prev = data[0]; for (var i = 1, n = data.length; i < n; i++) { incSizeSigned(size, data[i] - prev); prev = data[i]; } return __assign(__assign({}, byteSize(size)), { kind: 'delta' }); } function rleSize(data, info) { var size = SizeInfo(); var run = 1; for (var i = 1, n = data.length; i < n; i++) { if (data[i - 1] !== data[i]) { incSize(info, size, data[i - 1]); incSize(info, size, run); run = 1; } else { run++; } } incSize(info, size, data[data.length - 1]); incSize(info, size, run); return __assign(__assign({}, byteSize(size)), { kind: 'rle' }); } function deltaRleSize(data, info) { var size = SizeInfo(); var run = 1, prev = 0, prevValue = 0; for (var i = 1, n = data.length; i < n; i++) { var v = data[i] - prev; if (prevValue !== v) { incSizeSigned(size, prevValue); incSizeSigned(size, run); run = 1; } else { run++; } prevValue = v; prev = data[i]; } incSizeSigned(size, prevValue); incSizeSigned(size, run); return __assign(__assign({}, byteSize(size)), { kind: 'delta-rle' }); } function getSize(data) { var info = getInfo(data); var sizes = [packingSize(data, info), rleSize(data, info), deltaSize(data, info), deltaRleSize(data, info)]; sizes.sort(function (a, b) { return a.length - b.length; }); return sizes; } IntClassifier.getSize = getSize; function classify(data) { if (data.length < 2) return E.by(E.byteArray); var sizes = getSize(data); var size = sizes[0]; switch (size.kind) { case 'pack': return E.by(E.integerPacking); case 'rle': return E.by(E.runLength).and(E.integerPacking); case 'delta': return E.by(E.delta).and(E.integerPacking); case 'delta-rle': return E.by(E.delta).and(E.runLength).and(E.integerPacking); } throw new Error('should not happen :)'); } IntClassifier.classify = classify; })(IntClassifier || (IntClassifier = {})); var FloatClassifier; (function (FloatClassifier) { var delta = 1e-6; function classify(data) { var maxDigits = 4; var _a = getArrayDigitCount(data, maxDigits, delta), mantissaDigits = _a.mantissaDigits, integerDigits = _a.integerDigits; // TODO: better check for overflows here? if (mantissaDigits < 0 || mantissaDigits + integerDigits > 10) return E.by(E.byteArray); // TODO: this needs a conversion to Int?Array? if (mantissaDigits === 0) return IntClassifier.classify(data); var multiplier = getMultiplier(mantissaDigits); var intArray = new Int32Array(data.length); for (var i = 0, n = data.length; i < n; i++) { intArray[i] = Math.round(multiplier * data[i]); // TODO: enable this again? // const v = Math.round(multiplier * data[i]); // if (Math.abs(Math.round(v) / multiplier - intArray[i] / multiplier) > delta) { // return E.by(E.byteArray); // } } var sizes = IntClassifier.getSize(intArray); var size = sizes[0]; var fp = E.by(E.fixedPoint(multiplier)); switch (size.kind) { case 'pack': return fp.and(E.integerPacking); case 'rle': return fp.and(E.runLength).and(E.integerPacking); case 'delta': return fp.and(E.delta).and(E.integerPacking); case 'delta-rle': return fp.and(E.delta).and(E.runLength).and(E.integerPacking); } throw new Error('should not happen :)'); } FloatClassifier.classify = classify; function getMultiplier(mantissaDigits) { var m = 1; for (var i = 0; i < mantissaDigits; i++) m *= 10; return m; } })(FloatClassifier || (FloatClassifier = {})); //# sourceMappingURL=classifier.js.map