molstar
Version:
A comprehensive macromolecular library.
168 lines • 6.53 kB
JavaScript
/**
* 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