diff --git a/README.md b/README.md index bb51dbe..1c7d586 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ * **[VariantKey Format](#vkformat)** * [VariantKey Properties](#vkproperties) * [VariantKey Input values](#vkinput) -* [RegionKey](#regionkey) +* **[RegionKey](#regionkey)** * [Binary file formats for lookup tables](#binaryfiles) * [C Library](#clib) * [GO Library](#golib) @@ -369,7 +369,11 @@ The VariantKey is composed of 3 sections arranged in 64 bit: ## RegionKey -This library also includes functions to represent a human genetic region as number. +*RegionKey* encodes a human genetic region (defined as the set of *chromosome*, *start position*, *end position* and *strand direction*) in a 64 bit unsigned integer number. + +RegionKey allows to repesent a region as a single entity, and provides analogous properties as the ones listed in [VariantKey Properties](#vkproperties). + +The encoding of the first 33 bit (CROM, STARTPOS) is the same as in VariantKey. The RegionKey is composed of 4 sections arranged in 64 bit: @@ -433,7 +437,9 @@ The RegionKey is composed of 4 sections arranged in 64 bit: +1 : 1 dec = "01" bin ``` -The last bit of RegionKey is reserved. +* The last bit of RegionKey is reserved. + +This software library provides several functions to operate with *RegionKey* and interact with *VariantKey*. diff --git a/VERSION b/VERSION index edcfe40..68e69e4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.14.0 +2.15.0 diff --git a/c/src/nrvk.c b/c/src/nrvk.c index 05c40ce..21f66c4 100644 --- a/c/src/nrvk.c +++ b/c/src/nrvk.c @@ -58,11 +58,9 @@ size_t find_ref_alt_by_variantkey(const unsigned char *src, uint64_t last, uint6 size_t reverse_variantkey(const unsigned char *src, uint64_t last, uint64_t vk, variantkey_rev_t *rev) { - variantkey_t h = {0,0,0}; - decode_variantkey(vk, &h); - decode_chrom(h.chrom, rev->chrom); - rev->pos = h.pos; - size_t len = decode_refalt(h.refalt, rev->ref, &rev->sizeref, rev->alt, &rev->sizealt); + decode_chrom(extract_variantkey_chrom(vk), rev->chrom); + rev->pos = extract_variantkey_pos(vk); + size_t len = decode_refalt(extract_variantkey_refalt(vk), rev->ref, &rev->sizeref, rev->alt, &rev->sizealt); if ((len == 0) && (last > 0)) { len = find_ref_alt_by_variantkey(src, last, vk, rev->ref, &rev->sizeref, rev->alt, &rev->sizealt); diff --git a/c/src/regionkey.c b/c/src/regionkey.c index c7d48dd..371148d 100644 --- a/c/src/regionkey.c +++ b/c/src/regionkey.c @@ -80,12 +80,10 @@ void decode_regionkey(uint64_t code, regionkey_t *rk) void reverse_regionkey(uint64_t rk, regionkey_rev_t *rev) { - regionkey_t h = {0,0,0,0}; - decode_regionkey(rk, &h); - decode_chrom(h.chrom, rev->chrom); - rev->startpos = h.startpos; - rev->endpos = h.endpos; - rev->strand = decode_region_strand(h.strand); + decode_chrom(extract_regionkey_chrom(rk), rev->chrom); + rev->startpos = extract_regionkey_startpos(rk); + rev->endpos = extract_regionkey_endpos(rk); + rev->strand = decode_region_strand(extract_regionkey_strand(rk)); } uint64_t regionkey(const char *chrom, size_t sizechrom, uint32_t startpos, uint32_t endpos, int8_t strand) diff --git a/conda/c.vk/meta.yaml b/conda/c.vk/meta.yaml index ad00a72..9cab2d1 100644 --- a/conda/c.vk/meta.yaml +++ b/conda/c.vk/meta.yaml @@ -1,6 +1,6 @@ package: name: vk - version: 2.14.0 + version: 2.15.0 source: path: ../.. diff --git a/conda/python/meta.yaml b/conda/python/meta.yaml index 274ec5f..3cc9ebd 100644 --- a/conda/python/meta.yaml +++ b/conda/python/meta.yaml @@ -1,6 +1,6 @@ package: name: variantkey - version: 2.14.0 + version: 2.15.0 source: path: ../.. diff --git a/conda/r/meta.yaml b/conda/r/meta.yaml index 5484775..79e0396 100644 --- a/conda/r/meta.yaml +++ b/conda/r/meta.yaml @@ -1,6 +1,6 @@ package: name: r-variantkey - version: 2.14.0 + version: 2.15.0 source: path: ../.. diff --git a/javascript/Makefile b/javascript/Makefile index 13297ae..5672640 100644 --- a/javascript/Makefile +++ b/javascript/Makefile @@ -33,6 +33,7 @@ build: @mkdir -p target/build uglifyjs --compress --keep-fnames --comments --output target/build/variantkey.js src/variantkey.js cd test && node test_variantkey.js '../target/build/variantkey.js' + cd test && node test_regionkey.js '../target/build/variantkey.js' # Format the source code format: diff --git a/javascript/src/variantkey.js b/javascript/src/variantkey.js index 692aa5e..be18af3 100644 --- a/javascript/src/variantkey.js +++ b/javascript/src/variantkey.js @@ -39,7 +39,7 @@ function encodeChrom(chrom) { return 0; } // X > 23 ; Y > 24 ; M > 25 - onecharmap = [ + var onecharmap = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* M X Y */ @@ -90,7 +90,7 @@ function encodeBase(c) { G > 2 T > 3 */ - map = [ + var map = [ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* A C G T */ @@ -259,7 +259,7 @@ function extractVariantKeyChrom(vk) { } function extractVariantKeyPos(vk) { - return (((vk.hi & 0x7FFFFFF) << 1) | (vk.lo >>> 31)) >>> 0; + return (((vk.hi & 0x07FFFFFF) << 1) | (vk.lo >>> 31)) >>> 0; } function extractVariantKeyRefAlt(vk) { @@ -274,6 +274,16 @@ function decodeVariantKey(vk) { }; } +function reverseVariantKey(vk) { + var ra = decodeRefAlt(extractVariantKeyRefAlt(vk)); + return { + "chrom": decodeChrom(extractVariantKeyChrom(vk)), + "pos": extractVariantKeyPos(vk), + "ref": ra.ref, + "alt": ra.alt + } +} + function variantKey(chrom, pos, ref, alt) { return encodeVariantKey(encodeChrom(chrom), pos, encodeRefAlt(ref, alt)); } @@ -322,14 +332,90 @@ function parseHex(vs) { }; } -function reverseVariantKey(dvk) { - var ra = decodeRefAlt(dvk.refalt); +function encodeRegionStrand(strand) { + var map = [2, 0, 1, 0]; + return map[((++strand) & 3)]; +} + +function decodeRegionStrand(strand) { + var map = [0, 1, -1, 0]; + return map[(strand & 3)]; +} + +function encodeRegionKey(chrom, startpos, endpos, strand) { return { - "chrom": decodeChrom(dvk.chrom), - "pos": dvk.pos, - "ref": ra.ref, - "alt": ra.alt - } + "hi": ((((chrom >>> 0) << 27) | (startpos >>> 1)) >>> 0), + "lo": ((((startpos >>> 0) << 31) | ((endpos >>> 0) << 3) | ((strand >>> 0) << 1)) >>> 0) + }; +} + +function extractRegionKeyChrom(rk) { + return ((rk.hi & 0xF8000000) >>> 27); +} + +function extractRegionKeyStartPos(rk) { + return (((rk.hi & 0x07FFFFFF) << 1) | (rk.lo >>> 31)) >>> 0; +} + +function extractRegionKeyEndPos(rk) { + return (rk.lo & 0x7FFFFFF8) >>> 3 +} + +function extractRegionKeyStrand(rk) { + return (rk.lo & 0x00000006) >>> 1; +} + +function decodeRegionKey(rk) { + return { + "chrom": extractRegionKeyChrom(rk), + "startpos": extractRegionKeyStartPos(rk), + "endpos": extractRegionKeyEndPos(rk), + "strand": extractRegionKeyStrand(rk) + }; +} + +function reverseRegionKey(rk) { + return { + "chrom": decodeChrom(extractRegionKeyChrom(rk)), + "startpos": extractRegionKeyStartPos(rk), + "endpos": extractRegionKeyEndPos(rk), + "strand": decodeRegionStrand(extractRegionKeyStrand(rk)) + }; +} + +function regionKey(chrom, startpos, endpos, strand) { + return encodeRegionKey(encodeChrom(chrom), startpos, endpos, encodeRegionStrand(strand)); +} + +function regionKeyString(rk) { + return padL08(rk.hi.toString(16)) + padL08(rk.lo.toString(16)); +} + +function getVariantKeyEndPos(vk) { + return extractVariantKeyPos(vk) + ((vk.lo & 0x78000000) >>> 27); +} + +function areOverlappingRegions(a_chrom, a_startpos, a_endpos, b_chrom, b_startpos, b_endpos) { + return ((a_chrom == b_chrom) && (a_startpos < b_endpos) && (a_endpos > b_startpos)); +} + +function areOverlappingRegionRegionKey(chrom, startpos, endpos, rk) { + return ((chrom == extractRegionKeyChrom(rk)) && (startpos < extractRegionKeyEndPos(rk)) && (endpos > extractRegionKeyStartPos(rk))); +} + +function areOverlappingRegionKeys(rka, rkb) { + return ((extractRegionKeyChrom(rka) == extractRegionKeyChrom(rkb)) && (extractRegionKeyStartPos(rka) < extractRegionKeyEndPos(rkb)) && (extractRegionKeyEndPos(rka) > extractRegionKeyStartPos(rkb))); +} + +function areOverlappingVariantKeyRegionKey(vk, rk) { + return ((extractVariantKeyChrom(vk) == extractRegionKeyChrom(rk)) && (extractVariantKeyPos(vk) < extractRegionKeyEndPos(rk)) && (getVariantKeyEndPos(vk) > extractRegionKeyStartPos(rk))); +} + +function variantKeyToRegionKey(vk) { + return { + "hi": vk.hi, + "lo": ((vk.lo & 0x80000000) | ((getVariantKeyEndPos(vk) << 3) >>> 0)) >>> 0 + }; } if (typeof(module) !== 'undefined') { @@ -351,5 +437,22 @@ if (typeof(module) !== 'undefined') { compareVariantKeyChromPos: compareVariantKeyChromPos, variantKeyString: variantKeyString, reverseVariantKey: reverseVariantKey, + encodeRegionStrand: encodeRegionStrand, + decodeRegionStrand: decodeRegionStrand, + encodeRegionKey: encodeRegionKey, + extractRegionKeyChrom: extractRegionKeyChrom, + extractRegionKeyStartPos: extractRegionKeyStartPos, + extractRegionKeyEndPos: extractRegionKeyEndPos, + extractRegionKeyStrand: extractRegionKeyStrand, + decodeRegionKey: decodeRegionKey, + reverseRegionKey: reverseRegionKey, + regionKey: regionKey, + regionKeyString: regionKeyString, + getVariantKeyEndPos: getVariantKeyEndPos, + areOverlappingRegions: areOverlappingRegions, + areOverlappingRegionRegionKey: areOverlappingRegionRegionKey, + areOverlappingRegionKeys: areOverlappingRegionKeys, + areOverlappingVariantKeyRegionKey: areOverlappingVariantKeyRegionKey, + variantKeyToRegionKey: variantKeyToRegionKey, } } \ No newline at end of file diff --git a/javascript/test/test_regionkey.js b/javascript/test/test_regionkey.js new file mode 100644 index 0000000..ec5b9df --- /dev/null +++ b/javascript/test/test_regionkey.js @@ -0,0 +1,376 @@ +/** VariantKey Javascript Library Test + * + * regionkey.js + * + * @category Tools + * @author Nicola Asuni + * @copyright 2017-2018 GENOMICS plc + * @license MIT (see LICENSE) + * @link https://github.com/genomicsplc/variantkey + */ + +// LICENSE +// +// Copyright (c) 2017-2018 GENOMICS plc +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +const { + encodeRegionStrand, + decodeRegionStrand, + encodeRegionKey, + extractRegionKeyChrom, + extractRegionKeyStartPos, + extractRegionKeyEndPos, + extractRegionKeyStrand, + decodeRegionKey, + reverseRegionKey, + regionKey, + regionKeyString, + getVariantKeyEndPos, + areOverlappingRegions, + areOverlappingRegionRegionKey, + areOverlappingRegionKeys, + areOverlappingVariantKeyRegionKey, + variantKeyToRegionKey, +} = require(process.argv[2]); + +var k_test_size = 10; +// 0 1 2 3 4 5 6 7 8 9 +// chrom, startpos, endpos, strand, echrom, estrand, rk, rs, chrom_startpos, chrom_endpos +var test_data = [ + [ "1", 1000, 1100, 0, 1, 0, {"hi": 0x080001f4, "lo": 0x00002260}, "080001f400002260", {"hi": 0x00000000, "lo": 0x100003e8}, {"hi": 0x00000000, "lo": 0x1000044c}], + [ "2", 1001, 1201, 1, 2, 1, {"hi": 0x100001f4, "lo": 0x8000258a}, "100001f48000258a", {"hi": 0x00000000, "lo": 0x200003e9}, {"hi": 0x00000000, "lo": 0x200004b1}], + [ "3", 1002, 1302, -1, 3, 2, {"hi": 0x180001f5, "lo": 0x000028b4}, "180001f5000028b4", {"hi": 0x00000000, "lo": 0x300003ea}, {"hi": 0x00000000, "lo": 0x30000516}], + [ "4", 1003, 1403, 0, 4, 0, {"hi": 0x200001f5, "lo": 0x80002bd8}, "200001f580002bd8", {"hi": 0x00000000, "lo": 0x400003eb}, {"hi": 0x00000000, "lo": 0x4000057b}], + [ "5", 1004, 1504, 1, 5, 1, {"hi": 0x280001f6, "lo": 0x00002f02}, "280001f600002f02", {"hi": 0x00000000, "lo": 0x500003ec}, {"hi": 0x00000000, "lo": 0x500005e0}], + ["10", 1005, 1605, -1, 10, 2, {"hi": 0x500001f6, "lo": 0x8000322c}, "500001f68000322c", {"hi": 0x00000000, "lo": 0xa00003ed}, {"hi": 0x00000000, "lo": 0xa0000645}], + ["22", 1006, 1706, 0, 22, 0, {"hi": 0xb00001f7, "lo": 0x00003550}, "b00001f700003550", {"hi": 0x00000001, "lo": 0x600003ee}, {"hi": 0x00000001, "lo": 0x600006aa}], + [ "X", 1007, 1807, 1, 23, 1, {"hi": 0xb80001f7, "lo": 0x8000387a}, "b80001f78000387a", {"hi": 0x00000001, "lo": 0x700003ef}, {"hi": 0x00000001, "lo": 0x7000070f}], + [ "Y", 1008, 1908, -1, 24, 2, {"hi": 0xc00001f8, "lo": 0x00003ba4}, "c00001f800003ba4", {"hi": 0x00000001, "lo": 0x800003f0}, {"hi": 0x00000001, "lo": 0x80000774}], + ["MT", 1009, 2009, 0, 25, 0, {"hi": 0xc80001f8, "lo": 0x80003ec8}, "c80001f880003ec8", {"hi": 0x00000001, "lo": 0x900003f1}, {"hi": 0x00000001, "lo": 0x900007d9}], +]; + +var k_test_overlap_size = 12; +// 0 1 2 3 4 5 6 7 8 9 +// a_chrom, a_startpos, a_endpos, a_rk, a_vk, b_chrom, b_startpos, b_endpos, b_rk, res; +test_overlap = [ + [ 1, 5, 7, {"hi": 0x08000002, "lo": 0x80000038}, {"hi": 0x08000002, "lo": 0x90920000}, 2, 5, 7, {"hi": 0x10000002, "lo": 0x80000038}, false], // different chromosome + [ 1, 0, 2, {"hi": 0x08000000, "lo": 0x00000010}, {"hi": 0x08000000, "lo": 0x10920000}, 1, 3, 7, {"hi": 0x08000001, "lo": 0x80000038}, false], // -[-]|---|---- + [ 2, 1, 3, {"hi": 0x10000000, "lo": 0x80000018}, {"hi": 0x10000000, "lo": 0x90920000}, 2, 3, 7, {"hi": 0x10000001, "lo": 0x80000038}, false], // --[-]---|---- + [ 3, 2, 4, {"hi": 0x18000001, "lo": 0x00000020}, {"hi": 0x18000001, "lo": 0x10920000}, 3, 3, 7, {"hi": 0x18000001, "lo": 0x80000038}, true], // ---[|]--|---- + [ 4, 3, 5, {"hi": 0x20000001, "lo": 0x80000028}, {"hi": 0x20000001, "lo": 0x90920000}, 4, 3, 7, {"hi": 0x20000001, "lo": 0x80000038}, true], // ----[-]-|---- + [ 5, 4, 6, {"hi": 0x28000002, "lo": 0x00000030}, {"hi": 0x28000002, "lo": 0x10920000}, 5, 3, 7, {"hi": 0x28000001, "lo": 0x80000038}, true], // ----|[-]|---- + [ 6, 5, 7, {"hi": 0x30000002, "lo": 0x80000038}, {"hi": 0x30000002, "lo": 0x90920000}, 6, 3, 7, {"hi": 0x30000001, "lo": 0x80000038}, true], // ----|-[ ]---- + [10, 6, 8, {"hi": 0x50000003, "lo": 0x00000040}, {"hi": 0x50000003, "lo": 0x10920000}, 10, 3, 7, {"hi": 0x50000001, "lo": 0x80000038}, true], // ----|--[|]--- + [22, 7, 9, {"hi": 0xb0000003, "lo": 0x80000048}, {"hi": 0xb0000003, "lo": 0x90920000}, 22, 3, 7, {"hi": 0xb0000001, "lo": 0x80000038}, false], // ----|---[-]-- + [23, 8, 10, {"hi": 0xb8000004, "lo": 0x00000050}, {"hi": 0xb8000004, "lo": 0x10920000}, 23, 3, 7, {"hi": 0xb8000001, "lo": 0x80000038}, false], // ----|---|[-]- + [24, 2, 8, {"hi": 0xc0000001, "lo": 0x00000040}, {"hi": 0xc0000001, "lo": 0x30911200}, 24, 3, 7, {"hi": 0xc0000001, "lo": 0x80000038}, true], // ---[|---|]--- + [25, 3, 7, {"hi": 0xc8000001, "lo": 0x80000038}, {"hi": 0xc8000001, "lo": 0xa0912000}, 25, 3, 7, {"hi": 0xc8000001, "lo": 0x80000038}, true], // ----[---]---- +]; + +function test_encodeRegionStrand() { + var errors = 0; + var i; + var rk; + for (i = 0; i < k_test_size; i++) { + estrand = encodeRegionStrand(test_data[i][3]); + if (estrand != test_data[i][5]) { + console.error("(", i, "): Unexpected encoded strand: expected ", test_data[i][5], ", got ", estrand); + ++errors; + } + } + return errors; +} + +function test_decodeRegionStrand() { + var errors = 0; + var i; + var strand; + for (i = 0; i < k_test_size; i++) { + strand = decodeRegionStrand(test_data[i][5]); + if (strand != test_data[i][3]) { + console.error("(", i, "): Unexpected strand: expected ", test_data[i][3], ", got ", strand); + ++errors; + } + } + return errors; +} + +function test_encodeRegionKey() { + var errors = 0; + var i; + var rk; + for (i = 0; i < k_test_size; i++) { + rk = encodeRegionKey(test_data[i][4], test_data[i][1], test_data[i][2], test_data[i][5]); + if ((rk.hi != test_data[i][6].hi) || (rk.lo != test_data[i][6].lo)) { + console.error("(", i, "): Unexpected regionkey: expected ", test_data[i][6], ", got ", rk); + ++errors; + } + } + return errors; +} + +function test_extractRegionKeyChrom() { + var errors = 0; + var i; + var h; + for (i = 0; i < k_test_size; i++) { + h = extractRegionKeyChrom(test_data[i][6]); + if (h != test_data[i][4]) { + console.error("(", i, "): Unexpected chrom code: expected ", test_data[i][4], ", got ", h); + ++errors; + } + } + return errors; +} + +function test_extractRegionKeyStartPos() { + var errors = 0; + var i; + var h; + for (i = 0; i < k_test_size; i++) { + h = extractRegionKeyStartPos(test_data[i][6]); + if (h != test_data[i][1]) { + console.error("(", i, "): Unexpected START POS: expected ", test_data[i][1], ", got ", h); + ++errors; + } + } + return errors; +} + +function test_extractRegionKeyEndPos() { + var errors = 0; + var i; + var h; + for (i = 0; i < k_test_size; i++) { + h = extractRegionKeyEndPos(test_data[i][6]); + if (h != test_data[i][2]) { + console.error("(", i, "): Unexpected END POS: expected ", test_data[i][2], ", got ", h); + ++errors; + } + } + return errors; +} + +function test_extractRegionKeyStrand() { + var errors = 0; + var i; + var h; + for (i = 0; i < k_test_size; i++) { + h = extractRegionKeyStrand(test_data[i][6]); + if (h != test_data[i][5]) { + console.error("(", i, "): Unexpected STRAND code: expected ", test_data[i][5], ", got ", h); + ++errors; + } + } + return errors; +} + + +function test_decodeRegionKey() { + var errors = 0; + var i; + var h; + for (i = 0; i < k_test_size; i++) { + h = decodeRegionKey(test_data[i][6]); + if (h.chrom != test_data[i][4]) { + console.error("(", i, "): Unexpected CHROM code: expected ", test_data[i][4], ", got ", h.chrom); + ++errors; + } + if (h.startpos != test_data[i][1]) { + console.error("(", i, "): Unexpected START POS: expected ", test_data[i][1], ", got ", h.startpos); + ++errors; + } + if (h.endpos != test_data[i][2]) { + console.error("(", i, "): Unexpected END POS: expected ", test_data[i][2], ", got ", h.endpos); + ++errors; + } + if (h.strand != test_data[i][5]) { + console.error("(", i, "): Unexpected STRAND code: expected ", test_data[i][5], ", got ", h.strand); + ++errors; + } + } + return errors; +} + +function test_reverseRegionKey() { + var errors = 0; + var i; + var h; + for (i = 0; i < k_test_size; i++) { + h = reverseRegionKey(test_data[i][6]); + if (h.chrom != test_data[i][0]) { + console.error("(", i, "): Unexpected CHROM: expected ", test_data[i][0], ", got ", h.chrom); + ++errors; + } + if (h.startpos != test_data[i][1]) { + console.error("(", i, "): Unexpected START POS: expected ", test_data[i][1], ", got ", h.startpos); + ++errors; + } + if (h.endpos != test_data[i][2]) { + console.error("(", i, "): Unexpected END POS: expected ", test_data[i][2], ", got ", h.endpos); + ++errors; + } + if (h.strand != test_data[i][3]) { + console.error("(", i, "): Unexpected STRAND: expected ", test_data[i][3], ", got ", h.strand); + ++errors; + } + } + return errors; +} + +function test_regionKey() { + var errors = 0; + var i; + var rk; + for (i = 0; i < k_test_size; i++) { + rk = regionKey(test_data[i][0], test_data[i][1], test_data[i][2], test_data[i][3]); + if ((rk.hi != test_data[i][6].hi) || (rk.lo != test_data[i][6].lo)) { + console.error("(", i, "): Unexpected regionkey: expected ", test_data[i][6], ", got ", rk); + ++errors; + } + } + return errors; +} + +function test_regionKeyString() { + var errors = 0; + var rs = ""; + var i; + for (i = 0; i < k_test_size; i++) { + rs = regionKeyString(test_data[i][6]); + if (rs !== test_data[i][7]) { + console.error("(", i, "): Unexpected regionkey: expected ", test_data[i][7], ", got ", rs); + ++errors; + } + } + return errors; +} + +function test_getVariantKeyEndPos() { + var errors = 0; + var h; + var i; + for (i = 0; i < k_test_overlap_size; i++) { + h = getVariantKeyEndPos(test_overlap[i][4]); + if (h !== test_overlap[i][2]) { + console.error("(", i, "): Expected ", test_overlap[i][2], ", got ", h); + ++errors; + } + } + return errors; +} + +function test_areOverlappingRegions() { + var errors = 0; + var h; + var i; + for (i = 0; i < k_test_overlap_size; i++) { + h = areOverlappingRegions(test_overlap[i][0], test_overlap[i][1], test_overlap[i][2], test_overlap[i][5], test_overlap[i][6], test_overlap[i][7]); + if (h !== test_overlap[i][9]) { + console.error("(", i, "): Expected ", test_overlap[i][9], ", got ", h); + ++errors; + } + } + return errors; +} + +function test_areOverlappingRegionRegionKey() { + var errors = 0; + var h; + var i; + for (i = 0; i < k_test_overlap_size; i++) { + h = areOverlappingRegionRegionKey(test_overlap[i][0], test_overlap[i][1], test_overlap[i][2], test_overlap[i][8]); + if (h !== test_overlap[i][9]) { + console.error("(", i, "): Expected ", test_overlap[i][9], ", got ", h); + ++errors; + } + } + return errors; +} + +function test_areOverlappingRegionKeys() { + var errors = 0; + var h; + var i; + for (i = 0; i < k_test_overlap_size; i++) { + h = areOverlappingRegionKeys(test_overlap[i][3], test_overlap[i][8]); + if (h !== test_overlap[i][9]) { + console.error("(", i, "): Expected ", test_overlap[i][9], ", got ", h); + ++errors; + } + } + return errors; +} + +function test_areOverlappingVariantKeyRegionKey() { + var errors = 0; + var h; + var i; + for (i = 0; i < k_test_overlap_size; i++) { + h = areOverlappingVariantKeyRegionKey(test_overlap[i][4], test_overlap[i][8]); + if (h !== test_overlap[i][9]) { + console.error("(", i, "): Expected ", test_overlap[i][9], ", got ", h); + ++errors; + } + } + return errors; +} + +function test_variantKeyToRegionKey() { + var errors = 0; + var rk; + var i; + for (i = 0; i < k_test_overlap_size; i++) { + rk = variantKeyToRegionKey(test_overlap[i][4]); + if ((rk.hi != test_overlap[i][3].hi) || (rk.lo != test_overlap[i][3].lo)) { + console.error("(", i, "): Unexpected regionkey: expected ", test_overlap[i][3], ", got ", rk); + ++errors; + } + } + return errors; +} + +var errors = 0; + +errors += test_encodeRegionStrand(); +errors += test_decodeRegionStrand(); +errors += test_encodeRegionKey(); +errors += test_extractRegionKeyChrom(); +errors += test_extractRegionKeyStartPos(); +errors += test_extractRegionKeyEndPos(); +errors += test_extractRegionKeyStrand(); +errors += test_decodeRegionKey(); +errors += test_reverseRegionKey(); +errors += test_regionKey(); +errors += test_regionKeyString(); +errors += test_getVariantKeyEndPos(); +errors += test_areOverlappingRegions(); +errors += test_areOverlappingRegionRegionKey(); +errors += test_areOverlappingRegionKeys(); +errors += test_areOverlappingVariantKeyRegionKey(); +errors += test_variantKeyToRegionKey(); + +if (errors > 0) { + console.log("FAILED: " + errors); + process.exit(1); +} else { + console.log("OK"); +} diff --git a/javascript/test/test_variantkey.js b/javascript/test/test_variantkey.js index 3cd8644..cb2b1dd 100644 --- a/javascript/test/test_variantkey.js +++ b/javascript/test/test_variantkey.js @@ -32,10 +32,10 @@ // THE SOFTWARE. const { - parseHex, - azToUpper, encodeChrom, decodeChrom, + parseHex, + azToUpper, encodeRefAlt, decodeRefAlt, encodeVariantKey, @@ -48,7 +48,7 @@ const { compareVariantKeyChrom, compareVariantKeyChromPos, variantKeyString, - reverseVariantKey + reverseVariantKey, } = require(process.argv[2]); var k_test_size = 566; @@ -2510,7 +2510,7 @@ function test_extractVariantKeyChrom() { for (i = 0; i < k_test_size; i++) { h = extractVariantKeyChrom(test_data[i][4]); if (h != test_data[i][6]) { - console.error("(", i, "): Unexpected chrom code: expected ", test_data[i][6], ", got ", h.chrom); + console.error("(", i, "): Unexpected chrom code: expected ", test_data[i][6], ", got ", h); ++errors; } } @@ -2524,7 +2524,7 @@ function test_extractVariantKeyPos() { for (i = 0; i < k_test_size; i++) { h = extractVariantKeyPos(test_data[i][4]); if (h != test_data[i][7]) { - console.error("(", i, "): Unexpected pos code: expected ", test_data[i][7], ", got ", h.pos); + console.error("(", i, "): Unexpected pos code: expected ", test_data[i][7], ", got ", h); ++errors; } } @@ -2538,7 +2538,7 @@ function test_extractVariantKeyRefAlt() { for (i = 0; i < k_test_size; i++) { h = extractVariantKeyRefAlt(test_data[i][4]); if (h != test_data[i][8]) { - console.error("(", i, "): Unexpected ref+alt code: expected ", test_data[i][8], ", got ", h.refalt); + console.error("(", i, "): Unexpected ref+alt code: expected ", test_data[i][8], ", got ", h); ++errors; } } @@ -2567,6 +2567,34 @@ function test_decodeVariantKey() { return errors; } +function test_reverseVariantKey() { + var errors = 0; + var i; + var h; + for (i = 0; i < k_test_size; i++) { + h = reverseVariantKey(test_data[i][4]); + if (h.alt.length > 0) { + if (encodeChrom(h.chrom) != encodeChrom(test_data[i][0])) { + console.error("(", i, "): Unexpected chrom code: expected ", test_data[i][0], ", got ", h.chrom); + ++errors; + } + if (h.pos != test_data[i][1]) { + console.error("(", i, "): Unexpected pos code: expected ", test_data[i][1], ", got ", h.pos); + ++errors; + } + if (h.ref != test_data[i][2].toUpperCase()) { + console.error("(", i, "): Unexpected ref code: expected ", test_data[i][2].toUpperCase(), ", got ", h.ref); + ++errors; + } + if (h.alt != test_data[i][3].toUpperCase()) { + console.error("(", i, "): Unexpected alt code: expected ", test_data[i][3].toUpperCase(), ", got ", h.alt); + ++errors; + } + } + } + return errors; +} + function test_variantKey() { var errors = 0; var i; @@ -2901,38 +2929,6 @@ function test_parseHex() { return errors; } -function test_reverseVariantKey() { - var errors = 0; - var i; - var h; - for (i = 0; i < k_test_size; i++) { - h = reverseVariantKey({ - "chrom": test_data[i][6], - "pos": test_data[i][7], - "refalt": test_data[i][8] - }); - if (h.alt.length > 0) { - if (encodeChrom(h.chrom) != encodeChrom(test_data[i][0])) { - console.error("(", i, "): Unexpected chrom code: expected ", test_data[i][0], ", got ", h.chrom); - ++errors; - } - if (h.pos != test_data[i][1]) { - console.error("(", i, "): Unexpected pos code: expected ", test_data[i][1], ", got ", h.pos); - ++errors; - } - if (h.ref != test_data[i][2].toUpperCase()) { - console.error("(", i, "): Unexpected ref code: expected ", test_data[i][2].toUpperCase(), ", got ", h.ref); - ++errors; - } - if (h.alt != test_data[i][3].toUpperCase()) { - console.error("(", i, "): Unexpected alt code: expected ", test_data[i][3].toUpperCase(), ", got ", h.alt); - ++errors; - } - } - } - return errors; -} - var errors = 0; errors += test_azToUpper(); @@ -2944,13 +2940,13 @@ errors += test_extractVariantKeyChrom(); errors += test_extractVariantKeyPos(); errors += test_extractVariantKeyRefAlt(); errors += test_decodeVariantKey(); +errors += test_reverseVariantKey(); errors += test_variantKey(); errors += test_variantKeyRange(); errors += test_compareVariantKeyChrom(); errors += test_compareVariantKeyChromPos(); errors += test_variantKeyString(); errors += test_parseHex(); -errors += test_reverseVariantKey(); if (errors > 0) { console.log("FAILED: " + errors); diff --git a/python/setup.py b/python/setup.py index c38d430..6a2a55a 100644 --- a/python/setup.py +++ b/python/setup.py @@ -30,7 +30,7 @@ def run(self): setup( name='variantkey', - version='2.14.0', + version='2.15.0', keywords=('variantkey variant key genetic genomics'), description="VariantKey Bindings for Python", long_description=read('../README.md'), diff --git a/r/variantkey/DESCRIPTION b/r/variantkey/DESCRIPTION index 037a03a..eb66f00 100644 --- a/r/variantkey/DESCRIPTION +++ b/r/variantkey/DESCRIPTION @@ -1,6 +1,6 @@ Package: variantkey Title: Genetic VariantKey -Version: 2.14.0.1 +Version: 2.15.0.1 Authors@R: person("Nicola", "Asuni", email = "info@genomicsplc.com", role = c("aut", "cre")) Description: Tools to generate and process a 64 bit Unsigned Integer Keys for Human Genetic Variants. The VariantKey is sortable for chromosome and position,