Skip to content

Instantly share code, notes, and snippets.

@sdwfrost
Created March 5, 2018 14:27
Show Gist options
  • Save sdwfrost/71b5a9dbf5bfa829155fd1e8d2105671 to your computer and use it in GitHub Desktop.
Save sdwfrost/71b5a9dbf5bfa829155fd1e8d2105671 to your computer and use it in GitHub Desktop.
/* BEGIN node2umd PREFIX */
;(function(define) { define(function(require, exports, module) {
/* END node2umd PREFIX */
var Nt = function() {
'use strict';
function makeArray(length, val) {
if (val === undefined) { val = 0|0; }
if (val < 0) { val = 0; }
length |= 0;
var max = 0;
for (var i = length; i !== 0; i >>>= 1) { max++; }
var n = Array(max);
n[0] = [val];
for (i = 1; i < max; i++) {
n[i] = n[i-1].concat(n[i-1]);
}
var a = [];
for (var i = 0, l = length; l !== 0; l >>>= 1, i++) {
if (l&1) {
a = a.concat(n[i]);
}
}
return a;
};
var __bitCount = (function() {
var a = new Uint8Array(256);
var bin;
for (var i = 0; i < 256; i++) {
bin = i;
bin = bin - ((bin >> 1) & 0x55555555);
bin = (bin & 0x33333333) + ((bin >> 2) & 0x33333333);
a[i] = (((bin + (bin >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
return a;
})();
var __nucleotideTo4Bit = Object.create(null);
__nucleotideTo4Bit['A'] = 8; // 0b1000
__nucleotideTo4Bit['T'] = 4; // 0b0100
__nucleotideTo4Bit['G'] = 2; // 0b0010
__nucleotideTo4Bit['C'] = 1; // 0b0001
function setNucleotide() {
var n = arguments[0];
__nucleotideTo4Bit[n] = 0;
for (var i = 1; i < arguments.length; i++) {
__nucleotideTo4Bit[n] |= __nucleotideTo4Bit[arguments[i]];
}
};
setNucleotide('-');
setNucleotide('W', 'A', 'T');
setNucleotide('S', 'G', 'C');
setNucleotide('M', 'A', 'C');
setNucleotide('K', 'G', 'T');
setNucleotide('R', 'A', 'G');
setNucleotide('Y', 'C', 'T');
setNucleotide('B', 'C', 'G', 'T');
setNucleotide('D', 'A', 'G', 'T');
setNucleotide('H', 'A', 'C', 'T');
setNucleotide('V', 'A', 'C', 'G');
setNucleotide('N', 'A', 'T', 'G', 'C');
var __4BitToNucleotide = (
function() {
var a = makeArray(16);
var keys = Object.keys(__nucleotideTo4Bit);
for (var i = 0, len = keys.length; i < len; i++) {
a[__nucleotideTo4Bit[keys[i]]] = keys[i];
}
return a;
}
)();
var __nucleotideList = Object.keys(__nucleotideTo4Bit);
var __complementNucleotide = (
function() {
var a = Object.create(null);
a['A'] = 'T';
a['G'] = 'C';
a['B'] = 'V';
a['H'] = 'D';
a['M'] = 'K';
a['R'] = 'Y';
// S, W, N, - not included
var keys = Object.keys(a);
for (var i = 0, len = keys.length; i < len; i++) {
a[a[keys[i]]] = keys[i];
}
a['S'] = 'S';
a['W'] = 'W';
a['N'] = 'N';
a['-'] = '-';
return a;
}
)();
var __complement4Bit = (
function() {
var a = new Uint8Array(16);
for (var i = 0, len = a.length; i < len; i++) {
a[i] = __nucleotideTo4Bit[__complementNucleotide[__4BitToNucleotide[i]]];
}
return a;
}
)();
function nucleotideToBin(s) {
return __nucleotideTo4Bit[s] | 0;
}
function binToNucleotide(b) {
return __4BitToNucleotide[b] || '-';
}
function complementNucleotide(s) {
return __complementNucleotide[s] || '-';
}
function complementBin(b) {
return __complement4Bit[b] | 0;
}
/* Double up to form bytes */
var __byteComplement;
var __nucleotidesToByte;
var __byteToNucleotides;
var __byteNucleotideContent;
void function() {
var a = Object.create(null);
var b = new Uint8Array(256);
var c = new makeArray(256);
var d = new makeArray(256);
var keys = Object.keys(__nucleotideTo4Bit);
var len = keys.length;
var ki;
var kj;
var byte;
for (var i = 0; i < len; i++) {
ki = keys[i];
for (var j = 0; j < len; j++) {
kj = keys[j];
byte = __nucleotideTo4Bit[ki] | (__nucleotideTo4Bit[kj] << 4);
a[ki + kj] = byte;
b[byte] = __nucleotideTo4Bit[complementNucleotide(kj)] | (__nucleotideTo4Bit[complementNucleotide(ki)] << 4);
c[byte] = ki + kj;
d[byte] = [ki, kj];
}
}
__nucleotidesToByte = a;
__byteComplement = b;
__byteToNucleotides = c;
__byteNucleotideContent = d;
}();
function nucleotidesToByte(ss) {
return __nucleotidesToByte[ss] | 0;
}
/* amino acids */
var __codonToAminoAcid = Object.create(null);
__codonToAminoAcid['AAA'] = 'K';
__codonToAminoAcid['AAT'] = 'N';
__codonToAminoAcid['AAG'] = 'K';
__codonToAminoAcid['AAC'] = 'N';
__codonToAminoAcid['ATA'] = 'I';
__codonToAminoAcid['ATT'] = 'I';
__codonToAminoAcid['ATG'] = 'M';
__codonToAminoAcid['ATC'] = 'I';
__codonToAminoAcid['AGA'] = 'R';
__codonToAminoAcid['AGT'] = 'S';
__codonToAminoAcid['AGG'] = 'R';
__codonToAminoAcid['AGC'] = 'S';
__codonToAminoAcid['ACA'] = 'T';
__codonToAminoAcid['ACT'] = 'T';
__codonToAminoAcid['ACG'] = 'T';
__codonToAminoAcid['ACC'] = 'T';
__codonToAminoAcid['TAA'] = '*';
__codonToAminoAcid['TAT'] = 'Y';
__codonToAminoAcid['TAG'] = '&';
__codonToAminoAcid['TAC'] = 'Y';
__codonToAminoAcid['TTA'] = 'L';
__codonToAminoAcid['TTT'] = 'F';
__codonToAminoAcid['TTG'] = 'L';
__codonToAminoAcid['TTC'] = 'F';
__codonToAminoAcid['TGA'] = '$';
__codonToAminoAcid['TGT'] = 'C';
__codonToAminoAcid['TGG'] = 'W';
__codonToAminoAcid['TGC'] = 'C';
__codonToAminoAcid['TCA'] = 'S';
__codonToAminoAcid['TCT'] = 'S';
__codonToAminoAcid['TCG'] = 'S';
__codonToAminoAcid['TCC'] = 'S';
__codonToAminoAcid['GAA'] = 'E';
__codonToAminoAcid['GAT'] = 'D';
__codonToAminoAcid['GAG'] = 'E';
__codonToAminoAcid['GAC'] = 'D';
__codonToAminoAcid['GTA'] = 'V';
__codonToAminoAcid['GTT'] = 'V';
__codonToAminoAcid['GTG'] = 'V';
__codonToAminoAcid['GTC'] = 'V';
__codonToAminoAcid['GGA'] = 'G';
__codonToAminoAcid['GGT'] = 'G';
__codonToAminoAcid['GGG'] = 'G';
__codonToAminoAcid['GGC'] = 'G';
__codonToAminoAcid['GCA'] = 'A';
__codonToAminoAcid['GCT'] = 'A';
__codonToAminoAcid['GCG'] = 'A';
__codonToAminoAcid['GCC'] = 'A';
__codonToAminoAcid['CAA'] = 'Q';
__codonToAminoAcid['CAT'] = 'H';
__codonToAminoAcid['CAG'] = 'Q';
__codonToAminoAcid['CAC'] = 'H';
__codonToAminoAcid['CTA'] = 'L';
__codonToAminoAcid['CTT'] = 'L';
__codonToAminoAcid['CTG'] = 'L';
__codonToAminoAcid['CTC'] = 'L';
__codonToAminoAcid['CGA'] = 'R';
__codonToAminoAcid['CGT'] = 'R';
__codonToAminoAcid['CGG'] = 'R';
__codonToAminoAcid['CGC'] = 'R';
__codonToAminoAcid['CCA'] = 'P';
__codonToAminoAcid['CCT'] = 'P';
__codonToAminoAcid['CCG'] = 'P';
__codonToAminoAcid['CCC'] = 'P';
var __12BitToAminoAcid = (function() {
var a = makeArray(4096, '?');
var codons = Object.keys(__codonToAminoAcid);
var codon;
for (var i = 0, len = codons.length; i < len; i++) {
codon = codons[i];
a[
(nucleotideToBin(codon[2]) << 8) |
(nucleotideToBin(codon[1]) << 4) |
nucleotideToBin(codon[0])
] = __codonToAminoAcid[codon];
}
return a;
})();
function Seq(type) {
if (type === undefined) {
type = 'DNA';
}
if (!{'RNA': true, 'DNA': true}[type]) {
throw new Error('Sequence type ' + type + ' not supported');
}
this.__type = type;
this.__isRNA = (type === 'RNA');
this.__endPadding = 0;
this.__buffer = new ArrayBuffer(4);
this.__complement = null;
this.__content = null;
this.__fractionalContent = null;
this.__contentATGC = null;
this.__fractionalContent = null;
};
Seq.prototype.read = function(strData) {
var ntToByte = nucleotidesToByte;
var nucleotideString = strData.toUpperCase()
.replace(/\s/g, '')
.replace('U', 'T')
.replace(/[^ATGCBVHDMKRYSWN\-]/g, '-');
var length = nucleotideString.length | 0;
var max = length >>> 1;
var odd = length & 1;
var endPadding = (4 - (max + odd) % 4) % 4;
this.__endPadding = endPadding;
var buffer = new ArrayBuffer(max + odd + endPadding + 4);
var dataArray = new Int8Array(buffer, 4);
var n;
var byte;
var content;
for (var i = 0; i < max; i++) {
n = i << 1;
dataArray[i] = ntToByte(nucleotideString[n] + nucleotideString[++n]);
}
if (odd) {
dataArray[i] = __nucleotideTo4Bit[nucleotideString[i << 1]];
}
this.__buffer = buffer;
this.__length = length;
(new Uint32Array(buffer, 0, 1))[0] = length;
this.__complement = null;
this.__content = null;
this.__fractionalContent = null;
this.__contentATGC = null;
this.__fractionalContent = null;
return this;
};
Seq.prototype.readFASTA = function(strFASTA) {
var data = strFASTA.split(/\n\r?/gi);
while (data.length && data[0][0] === '>') {
data.shift();
}
return this.read(data.join(''));
};
Seq.prototype.readBuffer = function(buffer) {
this.__buffer = buffer;
var length = (new Uint32Array(buffer, 0, 1))[0];
var max = length >>> 1;
var odd = length & 1;
var endPadding = (4 - (max + odd) % 4) % 4;
this.__endPadding = endPadding;
this.__length = length;
this.__complement = null;
this.__content = null;
this.__fractionalContent = null;
this.__contentATGC = null;
this.__fractionalContent = null;
return this;
};
Seq.prototype.__byteComplement = function() {
var bComp = __byteComplement;
var fwdBuffer = this.__buffer;
var len = fwdBuffer.byteLength;
var n, i;
var copyBuffer, fromArray, copyArray;
var isOdd = this.__length & 1;
if (isOdd) {
copyBuffer = new ArrayBuffer(len);
copyArray = new Uint32Array(copyBuffer, 4);
fromArray = new Uint32Array(fwdBuffer, 4);
n = (len - 4) >>> 2;
while(n--) {
copyArray[n] = (fromArray[n] << 4) | ((fromArray[n - 1]) >>> 28);
}
} else {
copyBuffer = fwdBuffer;
}
var fwdArray = new Uint8Array(copyBuffer, 4);
var buffer = new ArrayBuffer(len);
var dataArray = new Uint8Array(buffer, 4);
n = (len - 4) - this.__endPadding;
i = 0;
while(n--) {
dataArray[i++] = bComp[fwdArray[n]];
}
(new Uint32Array(buffer, 0, 1))[0] = this.__length;
return buffer;
};
Seq.prototype.size = function() {
return this.__length;
};
Seq.prototype.sequence = function() {
var byteToNt = __byteToNucleotides;
var buffer = this.__buffer;
if (buffer.byteLength < 4) {
return '';
}
var dataArray = new Uint8Array(buffer, 4);
var len = (buffer.byteLength - 4) - this.__endPadding;
var nts = makeArray(len);
for (var i = 0; i < len; i++) {
nts[i] = byteToNt[dataArray[i]];
}
var returnString;
i = nts.length - 1;
if (this.__length & 1) {
nts[i] = nts[i][0];
}
returnString = nts.join('');
if (this.__isRNA) {
returnString = returnString.replace(/T/gi, 'U');
}
return returnString;
};
Seq.prototype.complement = function() {
if (!this.__complement) {
this.__complement = this.__byteComplement();
}
var complement = new Seq(this.__type).readBuffer(this.__complement.slice(0));
complement.__complement = this.__buffer.slice(0);
return complement;
};
Seq.prototype.equivalent = function(seq) {
if (!(seq instanceof Seq)) {
throw new Error('Can only check for equivalence between sequences');
}
if (this.__type !== seq.__type) {
return false;
}
var checkInts = new Uint32Array(this.__buffer);
var compareInts = new Uint32Array(seq.__buffer);
for (var i = 0, len = checkInts.length; i < len; i++) {
if (checkInts[i] !== compareInts[i]) {
return false;
}
}
return true;
};
Seq.prototype.replicate = function(start, length) {
start |= 0;
if (start < 0) {
start = this.__length + start;
}
if (length === undefined) {
if (start === 0) {
return this.__clone();
}
length = this.__length - start;
} else {
length |= 0;
length = Math.min(length, this.__length - start);
}
length = Math.min(length, this.__length - start);
if (length <= 0) {
return this.__nullSeq();
}
return this.__slice(start, length);
};
Seq.prototype.polymerize = function(seq) {
var seqLen = seq.__length;
if (!(seq instanceof Seq)) {
throw new Error('.polymerize requires valid sequence');
}
if (!this.__length) {
return seq.__clone();
}
var offset = this.__length;
var length = this.__length + seqLen;
var max = length >>> 1;
var odd = length & 1;
var endPadding = (4 - (max + odd) % 4) % 4;
var newBuffer = new ArrayBuffer(max + odd + endPadding + 4);
var newArray = new Uint32Array(newBuffer, 4);
var copyBuffer = this.__buffer;
var copyArray = new Uint32Array(copyBuffer, 4);
var seqBuffer = seq.__buffer;
var seqArray = new Uint32Array(seqBuffer, 4);
var copyPos = 0;
var shift = (this.__length % 8) * 4;
var shiftSeq = 32 - shift;
for (var len = copyArray.length; copyPos < len; copyPos++) {
newArray[copyPos] = copyArray[copyPos];
}
if (shift) {
newArray[--copyPos] |= seqArray[0] << shift;
for (var i = 0, len = seqArray.length; i < len; i++) {
newArray[++copyPos] = (seqArray[i] >>> shiftSeq) | (seqArray[i + 1] << shift);
}
} else {
for (var i = 0, len = seqArray.length; i < len; i++) {
newArray[copyPos++] = seqArray[i];
}
}
(new Uint32Array(newBuffer, 0, 1))[0] = length;
return new Seq(this.__type).readBuffer(newBuffer);
};
Seq.prototype.insertion = function(seq, offset) {
if (!(seq instanceof Seq)) {
throw new Error('Insertion requires valid sequence');
}
offset |= 0;
if (offset < 0) {
offset = this.__length + offset;
}
offset = Math.min(offset, this.__length);
return this.replicate(0, offset).polymerize(seq).polymerize(this.replicate(offset));
};
Seq.prototype.deletion = function(offset, count) {
if (offset === undefined || count === undefined) {
throw new Error('Must give valid offset and count for deletion');
}
offset |= 0;
count |= 0;
if (count === 0) {
return this.__clone();
}
if (count < 0) {
throw new Error('Invalid count for deletion');
}
if (offset < 0) {
offset = this.__length + offset;
}
offset = Math.min(offset, this.__length);
return this.replicate(0, offset).polymerize(this.replicate(offset + count));
};
Seq.prototype.repeat = function(count) {
count |= 0;
var copy = this.replicate();
var base = new Seq(this.__type);
if (count <= 0) {
return base;
}
while(true) {
if (count & 1) {
base = base.polymerize(copy);
}
count >>>= 1;
if (!count) {
break;
}
copy = copy.polymerize(copy);
}
return base;
};
Seq.prototype.mask = function(seq) {
if (!(seq instanceof Seq)) {
throw new Error('Can only mask with valid sequence');
}
var newBuffer = this.__buffer.slice(0);
var newArray = new Uint32Array(newBuffer, 4);
var compareArray = new Uint32Array(seq.__buffer, 4);
for (var i = 0, len = newArray.length; i < len; i++) {
newArray[i] &= compareArray[i];
}
return new Seq(this.__type).readBuffer(newBuffer);
};
Seq.prototype.cover = function(seq) {
if (!(seq instanceof Seq)) {
throw new Error('Can only cover with valid sequence');
}
var newBuffer = this.__buffer.slice(0);
var newArray = new Uint32Array(newBuffer, 4);
var compareArray = new Uint32Array(seq.__buffer, 4);
for (var i = 0, len = newArray.length; i < len; i++) {
newArray[i] |= compareArray[i];
}
return new Seq(this.__type).readBuffer(newBuffer);
};
Seq.prototype.__nullSeq = function() {
return new Seq(this.__type).readBuffer(new ArrayBuffer(4));
};
Seq.prototype.__clone = function() {
return new Seq(this.__type).readBuffer(this.__buffer.slice(0));
};
Seq.prototype.__slice = function(start, length) {
var max = length >>> 1;
var odd = length & 1;
var endPadding = (4 - (max + odd) % 4) % 4;
var newBuffer = new ArrayBuffer(max + odd + endPadding + 4);
var newArray = new Uint32Array(newBuffer, 4);
var subBuffer = this.__buffer.slice(4 + (start >>> 1), 4 + (start >>> 1) + newBuffer.byteLength);
var subInt32Length = subBuffer.byteLength >>> 2;
var subArray = new Uint32Array(subBuffer, 0, subInt32Length);
if (start & 1) {
for (var i = 0, len = subArray.length; i < len; i++) {
newArray[i] = (subArray[i] >>> 4) | (subArray[i + 1] << 28);
}
var remainder = subBuffer.byteLength - subArray.byteLength;
if (remainder) {
var remainderArray = new Uint8Array(newBuffer, 4 + (i << 2));
var subRemainderArray = new Uint8Array(subBuffer, i << 2);
if (newArray.length > 0) {
newArray[i - 1] |= subRemainderArray[0] << 28;
}
for (var i = 0, len = subRemainderArray.length; i < len; i++) {
remainderArray[i] = (subRemainderArray[i] >>> 4) | (subRemainderArray[i + 1] << 4);
}
}
} else {
for (var i = 0, len = subArray.length; i < len; i++) {
newArray[i] = subArray[i];
}
var remainder = subArray.byteLength - subBuffer.byteLength;
if (remainder) {
var remainderArray = new Uint8Array(newBuffer, 4 + (i << 2));
var subRemainderArray = new Uint8Array(subBuffer, i << 2);
for (var i = 0, len = subRemainderArray.length; i < len; i++) {
remainderArray[i] = subRemainderArray[i];
}
}
}
var clearShift = ((endPadding * 2) + odd) * 4;
var clearOut = new Uint32Array(newBuffer, newBuffer.byteLength - 4);
clearOut[0] = (clearOut[0] << clearShift) >>> clearShift;
(new Uint32Array(newBuffer, 0, 1))[0] = length;
return new Seq(this.__type).readBuffer(newBuffer);
};
Seq.prototype.content = function() {
if (!this.__content) {
var ntContentByte = makeArray(256);
var buffer = this.__buffer;
var dataArray = new Uint8Array(buffer);
for(var i = 4; i < buffer.byteLength - this.__endPadding; i++) {
ntContentByte[dataArray[i]]++;
}
var binToNt = binToNucleotide;
var ntList = __nucleotideList;
var ntContent = Object.create(null);
for (var i = 0, len = ntList.length; i < len; i++) {
ntContent[ntList[i]] = 0;
}
for (var i = 0, len = ntContentByte.length; i < len; i++) {
if (ntContentByte[i]) {
ntContent[binToNt(i & 0xF)] += ntContentByte[i];
ntContent[binToNt(i >>> 4)] += ntContentByte[i];
}
}
if (this.__length & 1) {
ntContent['-']--;
}
if (this.__isRNA) {
ntContent['U'] = ntContent['T'];
delete ntContent['T'];
}
this.__content = ntContent;
}
var returnContent = Object.create(null);
var keys = Object.keys(this.__content);
for (var i = 0, len = keys.length; i < len; i++) {
returnContent[keys[i]] = this.__content[keys[i]];
}
return returnContent;
};
Seq.prototype.fractionalContent = function() {
if (!this.__fractionalContent) {
var content = this.content();
var nts = Object.keys(content);
for (var i = 0, len = nts.length; i < len; i++) {
content[nts[i]] = content[nts[i]] / this.__length;
}
this.__fractionalContent = content;
}
var returnContent = Object.create(null);
var keys = Object.keys(this.__fractionalContent);
for (var i = 0, len = keys.length; i < len; i++) {
returnContent[keys[i]] = this.__fractionalContent[keys[i]];
}
return returnContent;
};
Seq.prototype.contentATGC = function() {
if (!this.__contentATGC) {
var ntToBin = nucleotideToBin;
var content = this.content();
var nts = Object.keys(content);
var contentATGC = Object.create(null);
contentATGC['A'] = 0;
contentATGC['T'] = 0;
contentATGC['G'] = 0;
contentATGC['C'] = 0;
var bits = 0;
var nt;
var ntBin;
var n;
var curContent;
for (var i = 0, len = nts.length; i < len; i++) {
nt = nts[i];
n = ntToBin(nt);
for (bits = 0; n; bits++) { n &= n - 1; }
ntBin = ntToBin(nt);
curContent = content[nts[i]] * (1 / bits);
contentATGC['A'] += (((ntToBin('A') & ntBin) | 0) && curContent);
contentATGC['T'] += (((ntToBin('T') & ntBin) | 0) && curContent);
contentATGC['G'] += (((ntToBin('G') & ntBin) | 0) && curContent);
contentATGC['C'] += (((ntToBin('C') & ntBin) | 0) && curContent);
}
if (this.__isRNA) {
contentATGC['U'] = contentATGC['T'];
delete contentATGC['T'];
}
this.__contentATGC = contentATGC;
}
var returnContent = Object.create(null);
var keys = Object.keys(this.__contentATGC);
for (var i = 0, len = keys.length; i < len; i++) {
returnContent[keys[i]] = this.__contentATGC[keys[i]];
}
return returnContent;
};
Seq.prototype.fractionalContentATGC = function() {
if (!this.__fractionalContentATGC) {
var content = this.contentATGC();
var nts = Object.keys(content);
for (var i = 0, len = nts.length; i < len; i++) {
content[nts[i]] = content[nts[i]] / this.__length;
}
this.__fractionalContentATGC = content;
}
var returnContent = Object.create(null);
var keys = Object.keys(this.__fractionalContentATGC);
for (var i = 0, len = keys.length; i < len; i++) {
returnContent[keys[i]] = this.__fractionalContentATGC[keys[i]];
}
return returnContent;
};
Seq.prototype.translate = function(ntOffset, ntCount) {
var binToAA = __12BitToAminoAcid;
ntOffset |= 0;
if (ntCount === undefined) {
ntCount = this.__length - ntOffset;
}
ntCount |= 0;
ntCount -= (ntCount % 3);
var offset = (ntOffset >>> 1) + 4;
var max = offset + (ntCount >>> 1) + (ntCount & 1);
var dataArray = new Uint8Array(this.__buffer);
var aminoAcids = makeArray(ntCount / 3);
/**/
var aa = 0;
var lastByte, byte1, byte2, byte3;
if ((ntOffset & 1) === 0) {
for (var i = offset; i < max; i += 3) {
var byte1 = dataArray[i];
var byte2 = dataArray[i+1];
var byte3 = dataArray[i+2];
aminoAcids[aa++] = binToAA[byte1 | ((byte2 & 0xF) << 8)];
aminoAcids[aa++] = binToAA[(byte3 << 4) | (byte2 >>> 4)];
}
} else {
lastByte = dataArray[offset];
for (var i = offset + 1; i < max; i += 3) {
byte1 = dataArray[i];
byte2 = dataArray[i+1];
byte3 = dataArray[i+2];
aminoAcids[aa++] = binToAA[(lastByte >> 4) | (byte1 << 4)];
aminoAcids[aa++] = binToAA[byte2 | ((byte3 & 0xF) << 8)];
lastByte = byte3;
}
}
if (ntCount & 1) { aminoAcids.pop(); }
return aminoAcids.join('');
};
Seq.prototype.translateFrame = function(frame, AAoffset, AAcount) {
if (frame === undefined) {
frame = 0;
}
if (frame !== 0 && frame !== 1 && frame !== 2) {
throw new Error('Invalid translation frame, must be 0, 1 or 2.');
}
if (AAoffset === undefined) {
return this.translate(frame);
}
if (AAcount === undefined) {
return this.translate(frame + ((AAoffset | 0) * 3));
}
return this.translate(frame + ((AAoffset | 0) * 3), (AAcount * 3) | 0);
};
Seq.prototype.mapSequence = function(seq, offset) {
if (!(seq instanceof Seq)) {
throw new Error('.mapSequence requires valid Seq');
}
return new MatchMap(seq, this, offset);
};
/* MatchResult */
function MatchResult(matchMap, pos, score) {
Object.defineProperty(this, '__matchMap', {value: matchMap});
this.position = pos;
this.score = score;
this.__align = null;
};
MatchResult.prototype.alignment = function() {
if (!this.__align) {
var map = this.__matchMap;
if (this.position < 0) {
this.__align = (new Nt.Seq())
.read('-')
.repeat(-this.position)
.polymerize(map.__searchSpace.replicate(0, map.__query.__length + this.position));
} else if (this.position + map.__query.__length > map.__searchSpace.__length) {
this.__align = map.__searchSpace
.replicate(this.position)
.polymerize((new Nt.Seq()).read('-').repeat(map.__searchSpace.__length - this.position));
} else {
this.__align = map.__searchSpace.replicate(this.position, map.__query.__length);
}
}
return this.__align;
};
MatchResult.prototype.alignmentMask = function() {
return this.__matchMap.__query.mask(this.alignment());
};
MatchResult.prototype.alignmentCover = function() {
return this.__matchMap.__query.cover(this.alignment());
};
/* MatchMap */
function MatchMap(query, searchSpace, offset) {
if (!(query instanceof Seq) || !(searchSpace instanceof Seq)) {
throw new Error('MatchMap requires valid Seq');
}
this.__query = query.replicate();
this.__searchSpace = searchSpace.replicate();
this.__results = [];
this.__orderedResults = [];
this.__matchFrequencyData = null;
this.__initialized = false;
this.__offset = Math.max(0, offset | 0);
this.__positionAdjustment = this.__offset - (this.__query.size() - 1);
this.__debug = {
searchTime: null,
prepareTime: null,
sortTime: null
};
};
MatchMap.prototype.initialize = function(results) {
this.__orderedResults = [];
this.__matchFrequencyData = null;
this.__initialized = true;
var t = (new Date).valueOf();
if (!results) {
var dataArray = new Uint32Array(this.__execute(this.__query.__buffer, this.__searchSpace.__buffer));
this.__debug.searchTime = (-t) + (t = (new Date).valueOf());
var queryLen = this.__query.size();
var searchLen = this.__searchSpace.size();
var resultsLen = ((8 - (queryLen % 8)) % 8) + 1;
var totalLen = searchLen + queryLen - 1;
results = [].slice.call(dataArray, resultsLen, resultsLen + totalLen);
}
this.__results = results;
this.__debug.prepareTime = (-t) + (t = (new Date).valueOf());
return this;
};
MatchMap.prototype.sort = function() {
if (!this.__initialized) {
throw new Error('MatchMap must be initialized first.');
}
var t = new Date().valueOf();
if (this.__debug.sortTime !== null) {
return this;
}
var adjust = this.__positionAdjustment;
this.__orderedResults = this.__results
.map(function(v, i) { return {n: i + adjust, s: v}; })
.sort(function(a, b) { return b.s - a.s; });
this.__debug.sortTime = new Date().valueOf() - t;
return this;
};
MatchMap.prototype.__calculate_p_match = function(query, searchSpace) {
/*
The approximate probability that two randomly chosen nucleotides
from QUERY and SEARCH match each other
*/
var queryContent = query.fractionalContentATGC();
var searchSpaceContent = searchSpace.fractionalContentATGC();
return (queryContent['A'] * searchSpaceContent['A']) +
(queryContent['T'] * searchSpaceContent['T']) +
(queryContent['G'] * searchSpaceContent['G']) +
(queryContent['C'] * searchSpaceContent['C']);
};
MatchMap.prototype.results = function(offset, count) {
if (!this.__initialized) {
throw new Error('MatchMap must be initialized first.');
}
if (offset === undefined) {
return this.__results.slice();
}
if (count === undefined) {
return this.__results.slice(offset | 0);
}
return this.__results.slice(offset | 0, count | 0);
};
MatchMap.prototype.best = function() {
if (!this.__initialized) {
throw new Error('MatchMap must be initialized first.');
}
if (!this.__orderedResults.length) {
throw new Error('MatchMap must be sorted first.');
}
var result = this.__orderedResults[0];
return new MatchResult(this, result.n, result.s);
};
MatchMap.prototype.top = function(n) {
if (!this.__initialized) {
throw new Error('MatchMap must be initialized first.');
}
if (!this.__orderedResults.length) {
throw new Error('MatchMap must be sorted first.');
}
var self = this;
return this.__orderedResults.slice(0, n).map(function(result) {
return new MatchResult(self, result.n, result.s);
});
};
MatchMap.prototype.bottom = function(n) {
if (!this.__initialized) {
throw new Error('MatchMap must be initialized first.');
}
if (!this.__orderedResults.length) {
throw new Error('MatchMap must be sorted first.');
}
var self = this;
var adjust = this.__positionAdjustment;
var len = this.__orderedResults.length;
return this.__orderedResults.slice(this.__orderedResults.length - n, n).map(function(result) {
return new MatchResult(self, result.n, result.s);
});
};
/* Can be optimized with binary splitting */
MatchMap.prototype.matchFrequencyData = function() {
if (!this.__initialized) {
throw new Error('MatchMap must be initialized first.');
}
if (!this.__orderedResults.length) {
throw new Error('MatchMap must be sorted first.');
}
if (this.__matchFrequencyData) {
return this.__matchFrequencyData;
}
var ordered = this.__orderedResults;
var matchFrequencyData = makeArray(this.__query.size() + 1);
var maxMatch = this.__query.size();
var lastIndex = 0;
var num;
for (var i = 0, len = ordered.length; i < len; i++) {
num = ordered[i].s;
if (num < maxMatch) {
matchFrequencyData[maxMatch] = i - lastIndex;
lastIndex = i;
maxMatch = num;
}
if (num === 0) {
matchFrequencyData[0] = len - i;
break;
}
}
return (this.__matchFrequencyData = matchFrequencyData);
};
MatchMap.prototype.__countMatches = function(int, bitCount) {
int |= int >>> 1;
int |= int >>> 2;
int &= 0x11111111;
int |= int >>> 3;
int |= int >>> 6;
return bitCount[((int >>> 12) & 0xF0) | (int & 0xF)];
};
MatchMap.prototype.__execute = function(queryBuffer, searchSpaceBuffer) {
var queryInts, spaceInts, queryIntsLength, spaceIntsLength,
arrLen, mapBuffer, mapArray,
A, B, A1, A2, T, cur, pos, move, i, k,
adjustNeg, adjustPos,
fnCountMatches, bitCount;
queryInts = new Uint32Array(queryBuffer, 4);
spaceInts = new Uint32Array(searchSpaceBuffer, 4);
fnCountMatches = this.__countMatches;
bitCount = __bitCount;
queryIntsLength = queryInts.length|0;
spaceIntsLength = spaceInts.length|0;
arrLen = (queryIntsLength + spaceIntsLength) << 3;
mapBuffer = new ArrayBuffer(4 * arrLen);
mapArray = new Uint32Array(mapBuffer);
for (k = 0|0; k < queryIntsLength; k++) {
A = queryInts[k];
cur = (queryIntsLength - k) << 3;
for (i = 0|0; i < spaceIntsLength; i++) {
(T = A & spaceInts[i]) && (mapArray[(i << 3) + cur] += fnCountMatches(T, bitCount));
}
A1 = A >>> 4;
A2 = A << 4;
adjustNeg = cur - 1;
adjustPos = cur + 1;
while(A1 || A2) {
for (i = 0|0; i < spaceIntsLength; i++) {
B = spaceInts[i];
pos = (i << 3);
(T = A1 & B) && (mapArray[pos + adjustNeg] += fnCountMatches(T, bitCount));
(T = A2 & B) && (mapArray[pos + adjustPos] += fnCountMatches(T, bitCount));
}
A1 >>>= 4;
A2 <<= 4;
--adjustNeg;
++adjustPos;
}
}
return mapBuffer;
};
return {
Seq: Seq,
MatchMap: MatchMap
};
}();
/* BEGIN node2umd POSTFIX */
}); })(typeof define === 'function' && define.amd ? define : function(factory) {
var isNode,
exportsObj = (isNode = typeof exports === 'object') ? exports : {},
moduleObj = isNode ? module : { exports: exportsObj };
var requireFn = isNode ? require : function(dependency) {
return this[dependency];
};
var def = factory(requireFn, exportsObj, moduleObj) || moduleObj.exports;
if (!isNode) {
this[def.globalName] = def;
}
});
/* END node2umd POSTFIX */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment