archaeopteryx 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -7
- package/archaeopteryx.js +922 -416
- package/forester.js +37 -3
- package/package.json +1 -1
package/forester.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
// v 3.
|
|
23
|
+
// v 3.6.0
|
|
24
24
|
// 2026-09-10
|
|
25
25
|
//
|
|
26
26
|
// forester.js is a general suite for dealing with phylogenetic trees.
|
|
@@ -455,6 +455,14 @@
|
|
|
455
455
|
forester.MAD_CONFIDENCE_TYPE = 'MAD';
|
|
456
456
|
|
|
457
457
|
const MAD_EPSILON = 1e-9;
|
|
458
|
+
// Tip pairs closer than this share of the tree's diameter are left out of
|
|
459
|
+
// every sum, like pairs at distance 0. Their 1/d^2 terms (tips 1e-8 apart,
|
|
460
|
+
// as FastTree's 5e-9 "zero" branches make them, reach 1e16) cancel
|
|
461
|
+
// catastrophically in the subtractions below and swamp every other pair:
|
|
462
|
+
// MAD then answered differently from every rooting, and re-rooting moved
|
|
463
|
+
// the root back and forth. The diameter does not depend on the rooting, so
|
|
464
|
+
// neither does the cut. Joint with the desktop (Christian, 2026-09-14).
|
|
465
|
+
const MAD_NEAR_FRACTION = 1e-5;
|
|
458
466
|
|
|
459
467
|
/**
|
|
460
468
|
* Roots the tree by Minimal Ancestor Deviation (Tria, Landan & Dagan,
|
|
@@ -472,6 +480,11 @@
|
|
|
472
480
|
* and the root's branch carries the smallest. Pendant branches get none,
|
|
473
481
|
* and MAD values from an earlier run are replaced.
|
|
474
482
|
*
|
|
483
|
+
* Tip pairs closer than 1e-5 of the tree's diameter (identical sequences,
|
|
484
|
+
* FastTree's 5e-9 "zero" branches) are left out of the deviation sums:
|
|
485
|
+
* their deviation measures noise, and their terms would swamp the
|
|
486
|
+
* precision of all the others.
|
|
487
|
+
*
|
|
475
488
|
* A no-op for fewer than three tips or a tree without branch lengths.
|
|
476
489
|
* O(n^2) time and O(n) memory: the desktop fills an n x n distance matrix
|
|
477
490
|
* only to sum its columns (1.4 GB at 13,000 tips), so the column sums are
|
|
@@ -513,6 +526,27 @@
|
|
|
513
526
|
if (maxDepth <= 0) {
|
|
514
527
|
return false; // no usable branch lengths
|
|
515
528
|
}
|
|
529
|
+
// the diameter, the longest tip-to-tip path: at every node, its two
|
|
530
|
+
// longest paths down through different children
|
|
531
|
+
let longestDown = new Float64Array(m);
|
|
532
|
+
let diameter = 0;
|
|
533
|
+
for (let q = 0; q < m; ++q) {
|
|
534
|
+
let k = post[q];
|
|
535
|
+
let first = 0;
|
|
536
|
+
let second = 0;
|
|
537
|
+
for (let c = 0; c < kids[k].length; ++c) {
|
|
538
|
+
let path = longestDown[kids[k][c]] + madLength(pre[kids[k][c]]);
|
|
539
|
+
if (path > first) {
|
|
540
|
+
second = first;
|
|
541
|
+
first = path;
|
|
542
|
+
} else if (path > second) {
|
|
543
|
+
second = path;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
longestDown[k] = first;
|
|
547
|
+
diameter = Math.max(diameter, first + second);
|
|
548
|
+
}
|
|
549
|
+
let nearEps = Math.max(MAD_EPSILON, MAD_NEAR_FRACTION * diameter);
|
|
516
550
|
let tipDepth = new Float64Array(n);
|
|
517
551
|
for (let i = 0; i < n; ++i) {
|
|
518
552
|
tipDepth[i] = depth[tipPos[i]];
|
|
@@ -529,7 +563,7 @@
|
|
|
529
563
|
let w2 = new Float64Array(m); // sum_{i!=j in subtree} (2*depth[j]/d - 1)^2 (j second)
|
|
530
564
|
let col0 = new Float64Array(n);
|
|
531
565
|
let colInv = new Float64Array(n);
|
|
532
|
-
let partners = new Int32Array(n); // the tips each tip is
|
|
566
|
+
let partners = new Int32Array(n); // the tips each tip is counted against (d > nearEps)
|
|
533
567
|
for (let q = 0; q < m; ++q) {
|
|
534
568
|
let k = post[q];
|
|
535
569
|
let ch = kids[k];
|
|
@@ -554,7 +588,7 @@
|
|
|
554
588
|
for (let j = lo[ch[b]]; j < hi[ch[b]]; ++j) {
|
|
555
589
|
let dj = tipDepth[j];
|
|
556
590
|
let dij = (di - dm) + (dj - dm);
|
|
557
|
-
if (dij >
|
|
591
|
+
if (dij > nearEps) {
|
|
558
592
|
let inv = 1.0 / dij;
|
|
559
593
|
let inv2 = inv * inv;
|
|
560
594
|
let dev = (2.0 * (di - dm) * inv) - 1.0;
|
package/package.json
CHANGED