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/forester.js CHANGED
@@ -20,7 +20,7 @@
20
20
  *
21
21
  */
22
22
 
23
- // v 3.5.0
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 apart from (d > MAD_EPSILON)
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 > MAD_EPSILON) {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archaeopteryx",
3
- "version": "3.5.0",
3
+ "version": "3.6.0",
4
4
  "description": "Archaeopteryx.js is a software tool for the visualization and analysis of highly annotated phylogenetic trees.",
5
5
  "main": "archaeopteryx.js",
6
6
  "types": "archaeopteryx.d.ts",