d-ary-heap 2.4.0 → 2.5.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 CHANGED
@@ -1,10 +1,12 @@
1
1
  ![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg)
2
2
  ![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-green.svg)
3
3
 
4
- # d-Heap Priority Queue (TypeScript) v2.4.0
4
+ # d-Heap Priority Queue (TypeScript) v2.5.0
5
5
 
6
6
  A high-performance, generic d-ary heap priority queue with O(1) item lookup, supporting both min-heap and max-heap behavior.
7
7
 
8
+ **[Live Demo](https://pcfvw.github.io/d-Heap-priority-queue/)** — Interactive visualization with Dijkstra's algorithm
9
+
8
10
  ## Strengths
9
11
 
10
12
  - **Flexible behavior**: min-heap or max-heap via comparator functions, and configurable arity `d` at construction time.
@@ -13,7 +15,7 @@ A high-performance, generic d-ary heap priority queue with O(1) item lookup, sup
13
15
  - O(log_d n): `insert()` and upward reheapification.
14
16
  - O(d · log_d n): delete-top (`pop()`), with up to d children examined per level.
15
17
  - **O(1) item lookup**: internal Map tracks positions by item key, enabling efficient priority updates.
16
- - **Practical API**: `insert`, `front`, `peek`, `pop`, `increasePriority`, `decreasePriority`, `isEmpty`, `len`, `contains`.
18
+ - **Practical API**: `insert`, `front`, `peek`, `pop`, `increasePriority`, `decreasePriority`, `updatePriority`, `isEmpty`, `len`, `contains`.
17
19
  - **Unified API**: Cross-language standardized methods matching C++, Rust, and Zig implementations.
18
20
  - **TypeScript-native**: Full type safety, generics, and IDE support.
19
21
  - **Zero dependencies**: No runtime dependencies.
@@ -107,8 +109,12 @@ Options:
107
109
  | `increase_priority(item)` | Alias for `increasePriority()` (cross-language compatibility) | O(log_d n) |
108
110
  | `increasePriorityByIndex(i)` | Update by index (primary method) | O(log_d n) |
109
111
  | `increase_priority_by_index(i)` | Alias for `increasePriorityByIndex()` (cross-language compatibility) | O(log_d n) |
112
+ | `decreasePriorityByIndex(i)` | Update by index (primary method) | O(d · log_d n) |
113
+ | `decrease_priority_by_index(i)` | Alias for `decreasePriorityByIndex()` (cross-language compatibility) | O(d · log_d n) |
110
114
  | `decreasePriority(item)` | Update item to lower priority (primary method) | O(d · log_d n) |
111
115
  | `decrease_priority(item)` | Alias for `decreasePriority()` (cross-language compatibility) | O(d · log_d n) |
116
+ | `updatePriority(item)` | Update item when direction unknown (primary method) | O((d+1) · log_d n) |
117
+ | `update_priority(item)` | Alias for `updatePriority()` (cross-language compatibility) | O((d+1) · log_d n) |
112
118
  | `clear(newD?)` | Remove all items, optionally change arity | O(1) |
113
119
 
114
120
  ### Utility Methods
@@ -124,8 +130,8 @@ Options:
124
130
 
125
131
  This TypeScript implementation follows **camelCase** as the primary naming convention (TypeScript/JavaScript standard), with **snake_case aliases** provided for cross-language compatibility:
126
132
 
127
- - **Primary methods**: `isEmpty()`, `increasePriority()`, `decreasePriority()`, `toString()`
128
- - **Compatibility aliases**: `is_empty()`, `increase_priority()`, `decrease_priority()`, `to_string()`
133
+ - **Primary methods**: `isEmpty()`, `increasePriority()`, `increasePriorityByIndex()`, `decreasePriority()`, `decreasePriorityByIndex()`, `updatePriority()`, `toString()`
134
+ - **Compatibility aliases**: `is_empty()`, `increase_priority()`, `increase_priority_by_index()`, `decrease_priority()`, `decrease_priority_by_index()`, `update_priority()`, `to_string()`
129
135
 
130
136
  Use the primary camelCase methods for TypeScript/JavaScript projects, and the snake_case aliases when porting code from C++/Rust implementations.
131
137
 
@@ -167,7 +173,7 @@ The library provides opt-in instrumentation for counting comparisons during heap
167
173
  Instrumentation follows a zero-overhead design:
168
174
  - No performance impact when not using instrumentation
169
175
  - Existing code works unchanged
170
- - Per-operation tracking distinguishes insert/pop/decreasePriority comparisons
176
+ - Per-operation tracking distinguishes insert/pop/increasePriority/decreasePriority/updatePriority comparisons
171
177
 
172
178
  ### Usage
173
179
 
@@ -200,7 +206,7 @@ pq.pop();
200
206
 
201
207
  // 4. Access statistics
202
208
  console.log(comparator.stats);
203
- // { insert: 3, pop: 2, decreasePriority: 0, total: 5 }
209
+ // { insert: 3, pop: 2, decreasePriority: 0, increasePriority: 0, updatePriority: 0, total: 5 }
204
210
 
205
211
  // 5. Compare with theoretical bounds
206
212
  const n = 3;
@@ -216,12 +222,13 @@ comparator.stats.reset();
216
222
 
217
223
  For a d-ary heap with n elements:
218
224
 
219
- | Operation | Comparisons (worst case) |
220
- |------------------|----------------------------|
221
- | insert | floor(log_d(n)) |
222
- | pop | d × floor(log_d(n)) |
223
- | decreasePriority | floor(log_d(n)) (upward) |
224
- | increasePriority | d × floor(log_d(n)) (downward) |
225
+ | Operation | Comparisons (worst case) |
226
+ |------------------|--------------------------------|
227
+ | insert | floor(log_d(n)) |
228
+ | pop | d × floor(log_d(n)) |
229
+ | increasePriority | floor(log_d(n)) (moveUp only) |
230
+ | decreasePriority | d × floor(log_d(n)) (moveDown only) |
231
+ | updatePriority | (d+1) × floor(log_d(n)) (both) |
225
232
 
226
233
  ### Cross-Language Consistency
227
234
 
@@ -237,10 +244,16 @@ Currently, instrumentation is implemented in TypeScript only. The table below sh
237
244
 
238
245
  ## Priority Update Semantics
239
246
 
240
- The `increasePriority()` and `decreasePriority()` methods have an intentionally **asymmetric design**:
247
+ This library uses **importance-based** semantics:
241
248
 
242
249
  - **`increasePriority()`**: Make an item **more important** (moves toward heap root). Only moves up for O(log_d n) performance.
243
- - **`decreasePriority()`**: Make an item **less important** (moves toward leaves). Checks both directions for robustness.
250
+ - **`decreasePriority()`**: Make an item **less important** (moves toward leaves). Only moves down for O(d · log_d n) performance.
251
+ - **`updatePriority()`**: Update when direction is **unknown**. Checks both directions for O((d+1) · log_d n) performance.
252
+
253
+ **When to use each:**
254
+ - Use `increasePriority()` when you know the item became more important
255
+ - Use `decreasePriority()` when you know the item became less important
256
+ - Use `updatePriority()` when you don't know which direction the priority changed
244
257
 
245
258
  **Heap Context:**
246
259
  - **Min-heap**: Lower priority values = higher importance
package/dist/index.cjs CHANGED
@@ -273,6 +273,28 @@ var PriorityQueue = class _PriorityQueue {
273
273
  increase_priority_by_index(index) {
274
274
  this.increasePriorityByIndex(index);
275
275
  }
276
+ /**
277
+ * Decrease the priority of the item at the given index.
278
+ * Time complexity: O(d · log_d n)
279
+ *
280
+ * @param index - Index of the item in the heap array
281
+ * @throws Error if index is out of bounds
282
+ *
283
+ * @remarks
284
+ * This is a lower-level method. Prefer decreasePriority() with the item itself.
285
+ * The item at the given index should already have its priority value updated
286
+ * in the container before calling this method.
287
+ */
288
+ decreasePriorityByIndex(index) {
289
+ if (index < 0 || index >= this.container.length) {
290
+ throw new Error("Index out of bounds");
291
+ }
292
+ this.moveDown(index);
293
+ }
294
+ /** Alias for decreasePriorityByIndex() - snake_case for cross-language consistency */
295
+ decrease_priority_by_index(index) {
296
+ this.decreasePriorityByIndex(index);
297
+ }
276
298
  /**
277
299
  * Decrease the priority of an existing item (move toward leaves).
278
300
  * Time complexity: O(d · log_d n)
@@ -283,7 +305,7 @@ var PriorityQueue = class _PriorityQueue {
283
305
  * @remarks
284
306
  * For min-heap: increasing the priority value decreases importance.
285
307
  * For max-heap: decreasing the priority value decreases importance.
286
- * This method checks both directions for robustness.
308
+ * This method only moves items downward. Use updatePriority() if direction is unknown.
287
309
  */
288
310
  decreasePriority(updatedItem) {
289
311
  this.onBeforeOperation?.("decreasePriority");
@@ -294,7 +316,6 @@ var PriorityQueue = class _PriorityQueue {
294
316
  throw new Error("Item not found in priority queue");
295
317
  }
296
318
  this.container[index] = updatedItem;
297
- this.moveUp(index);
298
319
  this.moveDown(index);
299
320
  this.onAfterOperation?.();
300
321
  }
@@ -302,6 +323,35 @@ var PriorityQueue = class _PriorityQueue {
302
323
  decrease_priority(updatedItem) {
303
324
  this.decreasePriority(updatedItem);
304
325
  }
326
+ /**
327
+ * Update the priority of an existing item when direction is unknown.
328
+ * Time complexity: O((d+1) · log_d n) - checks both directions
329
+ *
330
+ * @param updatedItem - Item with same identity but updated priority
331
+ * @throws Error if item not found
332
+ *
333
+ * @remarks
334
+ * Use this method when you don't know whether the priority increased or decreased.
335
+ * If you know the direction, prefer increasePriority() or decreasePriority() for
336
+ * better performance (log_d n vs (d+1) · log_d n comparisons).
337
+ */
338
+ updatePriority(updatedItem) {
339
+ this.onBeforeOperation?.("updatePriority");
340
+ const key = this.keyExtractor(updatedItem);
341
+ const index = this.positions.get(key);
342
+ if (index === void 0) {
343
+ this.onAfterOperation?.();
344
+ throw new Error("Item not found in priority queue");
345
+ }
346
+ this.container[index] = updatedItem;
347
+ this.moveUp(index);
348
+ this.moveDown(index);
349
+ this.onAfterOperation?.();
350
+ }
351
+ /** Alias for updatePriority() - snake_case for cross-language consistency */
352
+ update_priority(updatedItem) {
353
+ this.updatePriority(updatedItem);
354
+ }
305
355
  /**
306
356
  * Remove and return the highest-priority item.
307
357
  * Time complexity: O(d · log_d n)
@@ -499,14 +549,16 @@ function createComparisonStats() {
499
549
  pop: 0,
500
550
  decreasePriority: 0,
501
551
  increasePriority: 0,
552
+ updatePriority: 0,
502
553
  get total() {
503
- return this.insert + this.pop + this.decreasePriority + this.increasePriority;
554
+ return this.insert + this.pop + this.decreasePriority + this.increasePriority + this.updatePriority;
504
555
  },
505
556
  reset() {
506
557
  this.insert = 0;
507
558
  this.pop = 0;
508
559
  this.decreasePriority = 0;
509
560
  this.increasePriority = 0;
561
+ this.updatePriority = 0;
510
562
  }
511
563
  };
512
564
  return stats;
@@ -542,10 +594,20 @@ function theoreticalPopComparisons(n, d) {
542
594
  const height = Math.floor(Math.log(n) / Math.log(d));
543
595
  return d * height;
544
596
  }
545
- function theoreticalDecreasePriorityComparisons(n, d) {
597
+ function theoreticalIncreasePriorityComparisons(n, d) {
546
598
  if (n <= 1) return 0;
547
599
  return Math.floor(Math.log(n) / Math.log(d));
548
600
  }
601
+ function theoreticalDecreasePriorityComparisons(n, d) {
602
+ if (n <= 1) return 0;
603
+ const height = Math.floor(Math.log(n) / Math.log(d));
604
+ return d * height;
605
+ }
606
+ function theoreticalUpdatePriorityComparisons(n, d) {
607
+ if (n <= 1) return 0;
608
+ const height = Math.floor(Math.log(n) / Math.log(d));
609
+ return (d + 1) * height;
610
+ }
549
611
  /**
550
612
  * d-ary Heap Priority Queue - TypeScript Implementation
551
613
  *
@@ -554,8 +616,9 @@ function theoreticalDecreasePriorityComparisons(n, d) {
554
616
  * - Min-heap or max-heap behavior via comparator functions
555
617
  * - O(1) item lookup using Map for efficient priority updates
556
618
  * - O(1) access to highest-priority item
557
- * - O(log_d n) insert and priority increase operations
558
- * - O(d · log_d n) pop and priority decrease operations
619
+ * - O(log_d n) insert and increasePriority operations
620
+ * - O(d · log_d n) pop and decreasePriority operations
621
+ * - O((d+1) · log_d n) updatePriority (bidirectional)
559
622
  * - Optional instrumentation hooks for performance analysis
560
623
  *
561
624
  * @version 2.4.0
@@ -624,7 +687,7 @@ function theoreticalDecreasePriorityComparisons(n, d) {
624
687
  *
625
688
  * // 4. Access statistics
626
689
  * console.log(comparator.stats);
627
- * // { insert: 1, pop: 2, decreasePriority: 0, total: 3 }
690
+ * // { insert: 1, pop: 2, decreasePriority: 0, increasePriority: 0, updatePriority: 0, total: 3 }
628
691
  *
629
692
  * // 5. Reset for next measurement
630
693
  * comparator.stats.reset();
@@ -634,12 +697,13 @@ function theoreticalDecreasePriorityComparisons(n, d) {
634
697
  *
635
698
  * For a d-ary heap with n elements:
636
699
  *
637
- * | Operation | Comparisons (worst case) |
638
- * |------------------|----------------------------|
639
- * | insert | ⌊log_d(n)⌋ |
640
- * | pop | d × ⌊log_d(n)⌋ |
641
- * | decreasePriority | ⌊log_d(n)⌋ (upward only) |
642
- * | increasePriority | d × ⌊log_d(n)⌋ (downward) |
700
+ * | Operation | Comparisons (worst case) |
701
+ * |------------------|-------------------------------|
702
+ * | insert | ⌊log_d(n)⌋ |
703
+ * | pop | d × ⌊log_d(n)⌋ |
704
+ * | increasePriority | ⌊log_d(n)⌋ (moveUp only) |
705
+ * | decreasePriority | d × ⌊log_d(n)⌋ (moveDown only)|
706
+ * | updatePriority | (d+1) × ⌊log_d(n)⌋ (both) |
643
707
  *
644
708
  * The demo visualization compares actual counts against these theoretical bounds.
645
709
  *
@@ -671,7 +735,9 @@ exports.minNumber = minNumber;
671
735
  exports.minString = minString;
672
736
  exports.reverse = reverse;
673
737
  exports.theoreticalDecreasePriorityComparisons = theoreticalDecreasePriorityComparisons;
738
+ exports.theoreticalIncreasePriorityComparisons = theoreticalIncreasePriorityComparisons;
674
739
  exports.theoreticalInsertComparisons = theoreticalInsertComparisons;
675
740
  exports.theoreticalPopComparisons = theoreticalPopComparisons;
741
+ exports.theoreticalUpdatePriorityComparisons = theoreticalUpdatePriorityComparisons;
676
742
  //# sourceMappingURL=index.cjs.map
677
743
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/PriorityQueue.ts","../src/comparators.ts","../src/instrumentation.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * d-ary Heap Priority Queue - TypeScript Implementation\r\n *\r\n * A generic d-ary heap (d-heap) priority queue with:\r\n * - Configurable arity (d): number of children per node\r\n * - Min-heap or max-heap behavior via comparator functions\r\n * - O(1) item lookup using Map for efficient priority updates\r\n * - O(1) access to highest-priority item\r\n * - O(log_d n) insert and priority increase operations\r\n * - O(d · log_d n) pop and priority decrease operations\r\n * - Optional instrumentation hooks for performance analysis\r\n *\r\n * @version 2.4.0\r\n * @license Apache-2.0\r\n * @copyright 2023-2025 Eric Jacopin\r\n */\r\n\r\nimport type { OperationType } from './instrumentation';\r\n\r\n/** Type alias for position indices (cross-language consistency) */\r\nexport type Position = number;\r\n\r\n/**\r\n * Comparator function type for priority comparison.\r\n * Returns true if `a` has higher priority than `b`.\r\n */\r\nexport type Comparator<T> = (a: T, b: T) => boolean;\r\n\r\n/**\r\n * Key extractor function type for identity-based lookup.\r\n * Must return a value that can be used as a Map key (string or number recommended).\r\n */\r\nexport type KeyExtractor<T, K> = (item: T) => K;\r\n\r\n/**\r\n * Configuration options for PriorityQueue construction.\r\n */\r\nexport interface PriorityQueueOptions<T, K> {\r\n /** Number of children per node (arity). Must be >= 1. Default: 2 */\r\n d?: number;\r\n /** Comparator function. Returns true if first arg has higher priority. */\r\n comparator: Comparator<T>;\r\n /** Key extractor for identity-based lookup. Required for decrease/increase priority. */\r\n keyExtractor: KeyExtractor<T, K>;\r\n /** Initial capacity hint for pre-allocation */\r\n initialCapacity?: number;\r\n\r\n /**\r\n * Optional hook called before each heap operation.\r\n *\r\n * This enables opt-in instrumentation for performance analysis without\r\n * adding overhead when not used. Pair with an instrumented comparator\r\n * to track comparison counts per operation type.\r\n *\r\n * @param type - The operation about to be performed\r\n *\r\n * @example\r\n * ```typescript\r\n * const cmp = instrumentComparator(minBy((v) => v.priority));\r\n * const pq = new PriorityQueue({\r\n * comparator: cmp,\r\n * keyExtractor: (v) => v.id,\r\n * onBeforeOperation: (op) => cmp.startOperation(op),\r\n * onAfterOperation: () => cmp.endOperation(),\r\n * });\r\n * ```\r\n *\r\n * @see instrumentComparator from './instrumentation'\r\n */\r\n onBeforeOperation?: (type: OperationType) => void;\r\n\r\n /**\r\n * Optional hook called after each heap operation completes.\r\n *\r\n * @see onBeforeOperation for usage example\r\n */\r\n onAfterOperation?: () => void;\r\n}\r\n\r\n/**\r\n * Generic d-ary heap priority queue with O(1) lookup.\r\n *\r\n * A d-ary heap is a tree structure where:\r\n * - Each node has at most d children\r\n * - The root contains the highest-priority item\r\n * - Each parent has higher priority than all its children\r\n * - The tree is complete (filled left-to-right, level by level)\r\n *\r\n * This implementation uses an array-based representation with O(1) item lookup\r\n * via a Map that tracks each item's position in the heap.\r\n *\r\n * ## Time Complexities\r\n * - front(), peek(): O(1)\r\n * - insert(): O(log_d n)\r\n * - pop(): O(d · log_d n)\r\n * - increasePriority(): O(log_d n)\r\n * - decreasePriority(): O(d · log_d n)\r\n * - contains(): O(1)\r\n * - len(), isEmpty(), d(): O(1)\r\n *\r\n * @typeParam T - Item type stored in the queue\r\n * @typeParam K - Key type for identity lookup (typically string or number)\r\n */\r\nexport class PriorityQueue<T, K = string | number> {\r\n /** Array-based heap storage (complete tree representation) */\r\n private container: T[];\r\n\r\n /** Maps each item's key to its position in the container for O(1) lookup */\r\n private positions: Map<K, Position>;\r\n\r\n /** Number of children per node (arity of the heap) */\r\n private depth: number;\r\n\r\n /** Comparator determining heap order (min vs max) */\r\n private readonly comparator: Comparator<T>;\r\n\r\n /** Key extractor for identity-based lookup */\r\n private readonly keyExtractor: KeyExtractor<T, K>;\r\n\r\n /** Optional hook called before operations (for instrumentation) */\r\n private readonly onBeforeOperation: ((type: OperationType) => void) | undefined;\r\n\r\n /** Optional hook called after operations (for instrumentation) */\r\n private readonly onAfterOperation: (() => void) | undefined;\r\n\r\n /**\r\n * Create a new d-ary heap priority queue.\r\n *\r\n * @param options - Configuration options\r\n * @throws Error if d < 1\r\n *\r\n * @example\r\n * ```typescript\r\n * // Min-heap by cost\r\n * const pq = new PriorityQueue<Item, number>({\r\n * d: 4,\r\n * comparator: (a, b) => a.cost < b.cost,\r\n * keyExtractor: (item) => item.id\r\n * });\r\n * ```\r\n */\r\n constructor(options: PriorityQueueOptions<T, K>) {\r\n const d = options.d ?? 2;\r\n if (d < 1) {\r\n throw new Error('Heap arity (d) must be >= 1');\r\n }\r\n\r\n this.depth = d;\r\n this.comparator = options.comparator;\r\n this.keyExtractor = options.keyExtractor;\r\n this.onBeforeOperation = options.onBeforeOperation;\r\n this.onAfterOperation = options.onAfterOperation;\r\n\r\n // Pre-allocate if capacity hint provided\r\n const capacity = options.initialCapacity ?? 0;\r\n this.container = capacity > 0 ? new Array<T>(capacity) : [];\r\n if (capacity > 0) this.container.length = 0; // Reset length but keep capacity\r\n this.positions = new Map<K, Position>();\r\n }\r\n\r\n /**\r\n * Create a new priority queue with an initial item already inserted.\r\n * Equivalent to Rust's `with_first()` constructor.\r\n *\r\n * @param options - Configuration options\r\n * @param firstItem - First item to insert\r\n * @returns New PriorityQueue with the item already inserted\r\n */\r\n static withFirst<T, K>(\r\n options: PriorityQueueOptions<T, K>,\r\n firstItem: T\r\n ): PriorityQueue<T, K> {\r\n const pq = new PriorityQueue<T, K>(options);\r\n pq.insert(firstItem);\r\n return pq;\r\n }\r\n\r\n // ===========================================================================\r\n // Public API - Query Operations\r\n // ===========================================================================\r\n\r\n /**\r\n * Get the number of items in the heap.\r\n * Time complexity: O(1)\r\n */\r\n len(): number {\r\n return this.container.length;\r\n }\r\n\r\n /** Alias for len() - backward compatibility */\r\n get size(): number {\r\n return this.container.length;\r\n }\r\n\r\n /**\r\n * Check if the heap is empty.\r\n * Time complexity: O(1)\r\n */\r\n isEmpty(): boolean {\r\n return this.container.length === 0;\r\n }\r\n\r\n /** Alias for isEmpty() - snake_case for cross-language consistency */\r\n is_empty(): boolean {\r\n return this.isEmpty();\r\n }\r\n\r\n /**\r\n * Get the arity (number of children per node) of the heap.\r\n * Time complexity: O(1)\r\n */\r\n d(): number {\r\n return this.depth;\r\n }\r\n\r\n /**\r\n * Check if an item with the given key exists in the heap.\r\n * Time complexity: O(1)\r\n *\r\n * @param item - Item to check (uses keyExtractor for identity)\r\n */\r\n contains(item: T): boolean {\r\n return this.positions.has(this.keyExtractor(item));\r\n }\r\n\r\n /**\r\n * Check if an item with the given key exists in the heap.\r\n * Time complexity: O(1)\r\n *\r\n * @param key - Key to check directly\r\n */\r\n containsKey(key: K): boolean {\r\n return this.positions.has(key);\r\n }\r\n\r\n /**\r\n * Get the current position (index) of an item in the heap.\r\n * Time complexity: O(1)\r\n *\r\n * @param item - Item to find (uses keyExtractor for identity)\r\n * @returns Position index, or undefined if not found\r\n */\r\n getPosition(item: T): Position | undefined {\r\n return this.positions.get(this.keyExtractor(item));\r\n }\r\n\r\n /**\r\n * Get the current position (index) of an item by its key.\r\n * Time complexity: O(1)\r\n *\r\n * @param key - Key to find\r\n * @returns Position index, or undefined if not found\r\n */\r\n getPositionByKey(key: K): Position | undefined {\r\n return this.positions.get(key);\r\n }\r\n\r\n /**\r\n * Get the highest-priority item without removing it.\r\n * Time complexity: O(1)\r\n *\r\n * @returns The highest-priority item\r\n * @throws Error if heap is empty\r\n */\r\n front(): T {\r\n const item = this.container[0];\r\n if (item === undefined) {\r\n throw new Error('front() called on empty priority queue');\r\n }\r\n return item;\r\n }\r\n\r\n /**\r\n * Get the highest-priority item without removing it.\r\n * Safe alternative to front().\r\n * Time complexity: O(1)\r\n *\r\n * @returns The highest-priority item, or undefined if empty\r\n */\r\n peek(): T | undefined {\r\n return this.container.length > 0 ? this.container[0] : undefined;\r\n }\r\n\r\n // ===========================================================================\r\n // Public API - Modification Operations\r\n // ===========================================================================\r\n\r\n /**\r\n * Insert a new item into the heap.\r\n * Time complexity: O(log_d n)\r\n *\r\n * @param item - Item to insert\r\n *\r\n * @remarks\r\n * If an item with the same key already exists, behavior is undefined.\r\n * Use contains() to check first, or use increasePriority()/decreasePriority()\r\n * to update existing items.\r\n */\r\n insert(item: T): void {\r\n this.onBeforeOperation?.('insert');\r\n\r\n const index = this.container.length;\r\n this.container.push(item);\r\n\r\n // Fast path: first item doesn't need sift-up\r\n if (index === 0) {\r\n this.positions.set(this.keyExtractor(item), 0);\r\n this.onAfterOperation?.();\r\n return;\r\n }\r\n\r\n this.positions.set(this.keyExtractor(item), index);\r\n this.moveUp(index);\r\n\r\n this.onAfterOperation?.();\r\n }\r\n\r\n /**\r\n * Insert multiple items into the heap.\r\n * Uses heapify algorithm which is O(n) for bulk insertion vs O(n log n) for individual inserts.\r\n * Time complexity: O(n) where n is total items after insertion\r\n *\r\n * @param items - Array of items to insert\r\n *\r\n * @remarks\r\n * More efficient than calling insert() repeatedly when adding many items at once.\r\n * If any item has a key that already exists, behavior is undefined.\r\n */\r\n insertMany(items: T[]): void {\r\n if (items.length === 0) return;\r\n\r\n const keyExtractor = this.keyExtractor;\r\n const container = this.container;\r\n const positions = this.positions;\r\n const startIndex = container.length;\r\n\r\n // Add all items to container and positions map\r\n for (let i = 0; i < items.length; i++) {\r\n const item = items[i]!;\r\n container.push(item);\r\n positions.set(keyExtractor(item), startIndex + i);\r\n }\r\n\r\n // If this was an empty heap, use heapify (O(n)) instead of n insertions (O(n log n))\r\n if (startIndex === 0 && items.length > 1) {\r\n this.heapify();\r\n } else {\r\n // Otherwise, sift up each new item\r\n for (let i = startIndex; i < container.length; i++) {\r\n this.moveUp(i);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Build heap property from unordered array.\r\n * Uses Floyd's algorithm - O(n) time complexity.\r\n * Called internally by insertMany when starting from empty heap.\r\n */\r\n private heapify(): void {\r\n const n = this.container.length;\r\n if (n <= 1) return;\r\n\r\n const d = this.depth;\r\n // Start from last non-leaf node and sift down each\r\n // Last non-leaf is parent of last element: floor((n-2)/d)\r\n const lastNonLeaf = ((n - 2) / d) | 0;\r\n\r\n for (let i = lastNonLeaf; i >= 0; i--) {\r\n this.moveDown(i);\r\n }\r\n }\r\n\r\n /**\r\n * Increase the priority of an existing item (move toward root).\r\n * Time complexity: O(log_d n)\r\n *\r\n * @param updatedItem - Item with same identity but updated priority\r\n * @throws Error if item not found\r\n *\r\n * @remarks\r\n * For min-heap: decreasing the priority value increases importance.\r\n * For max-heap: increasing the priority value increases importance.\r\n * This method only moves items upward for performance.\r\n */\r\n increasePriority(updatedItem: T): void {\r\n this.onBeforeOperation?.('increasePriority');\r\n\r\n const key = this.keyExtractor(updatedItem);\r\n const index = this.positions.get(key);\r\n\r\n if (index === undefined) {\r\n this.onAfterOperation?.();\r\n throw new Error('Item not found in priority queue');\r\n }\r\n\r\n this.container[index] = updatedItem;\r\n this.moveUp(index);\r\n\r\n this.onAfterOperation?.();\r\n }\r\n\r\n /** Alias for increasePriority() - snake_case for cross-language consistency */\r\n increase_priority(updatedItem: T): void {\r\n this.increasePriority(updatedItem);\r\n }\r\n\r\n /**\r\n * Increase the priority of the item at the given index.\r\n * Time complexity: O(log_d n)\r\n *\r\n * @param index - Index of the item in the heap array\r\n * @throws Error if index is out of bounds\r\n *\r\n * @remarks\r\n * This is a lower-level method. Prefer increasePriority() with the item itself.\r\n */\r\n increasePriorityByIndex(index: number): void {\r\n if (index < 0 || index >= this.container.length) {\r\n throw new Error('Index out of bounds');\r\n }\r\n this.moveUp(index);\r\n }\r\n\r\n /** Alias for increasePriorityByIndex() - snake_case for cross-language consistency */\r\n increase_priority_by_index(index: number): void {\r\n this.increasePriorityByIndex(index);\r\n }\r\n\r\n /**\r\n * Decrease the priority of an existing item (move toward leaves).\r\n * Time complexity: O(d · log_d n)\r\n *\r\n * @param updatedItem - Item with same identity but updated priority\r\n * @throws Error if item not found\r\n *\r\n * @remarks\r\n * For min-heap: increasing the priority value decreases importance.\r\n * For max-heap: decreasing the priority value decreases importance.\r\n * This method checks both directions for robustness.\r\n */\r\n decreasePriority(updatedItem: T): void {\r\n this.onBeforeOperation?.('decreasePriority');\r\n\r\n const key = this.keyExtractor(updatedItem);\r\n const index = this.positions.get(key);\r\n\r\n if (index === undefined) {\r\n this.onAfterOperation?.();\r\n throw new Error('Item not found in priority queue');\r\n }\r\n\r\n this.container[index] = updatedItem;\r\n // Check both directions since we don't know if priority actually decreased\r\n this.moveUp(index);\r\n this.moveDown(index);\r\n\r\n this.onAfterOperation?.();\r\n }\r\n\r\n /** Alias for decreasePriority() - snake_case for cross-language consistency */\r\n decrease_priority(updatedItem: T): void {\r\n this.decreasePriority(updatedItem);\r\n }\r\n\r\n /**\r\n * Remove and return the highest-priority item.\r\n * Time complexity: O(d · log_d n)\r\n *\r\n * @returns The removed item, or undefined if empty\r\n */\r\n pop(): T | undefined {\r\n this.onBeforeOperation?.('pop');\r\n\r\n const container = this.container;\r\n const n = container.length;\r\n\r\n if (n === 0) {\r\n this.onAfterOperation?.();\r\n return undefined;\r\n }\r\n\r\n const keyExtractor = this.keyExtractor;\r\n const top = container[0]!;\r\n this.positions.delete(keyExtractor(top));\r\n\r\n if (n === 1) {\r\n container.length = 0;\r\n this.onAfterOperation?.();\r\n return top;\r\n }\r\n\r\n // Move last item to root and sift down\r\n const lastItem = container[n - 1]!;\r\n container[0] = lastItem;\r\n this.positions.set(keyExtractor(lastItem), 0);\r\n container.length = n - 1;\r\n\r\n this.moveDown(0);\r\n\r\n this.onAfterOperation?.();\r\n return top;\r\n }\r\n\r\n /**\r\n * Remove and return multiple highest-priority items.\r\n * More efficient than calling pop() repeatedly.\r\n * Time complexity: O(count · d · log_d n)\r\n *\r\n * @param count - Number of items to remove\r\n * @returns Array of removed items in priority order\r\n */\r\n popMany(count: number): T[] {\r\n const result: T[] = [];\r\n const actualCount = count < this.container.length ? count : this.container.length;\r\n\r\n for (let i = 0; i < actualCount; i++) {\r\n const item = this.pop();\r\n if (item !== undefined) {\r\n result.push(item);\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Clear all items from the heap, optionally changing the arity.\r\n * Time complexity: O(1) (references cleared, GC handles memory)\r\n *\r\n * @param newD - Optional new arity value (must be >= 1 if provided)\r\n * @throws Error if newD < 1\r\n */\r\n clear(newD?: number): void {\r\n this.container.length = 0;\r\n this.positions.clear();\r\n\r\n if (newD !== undefined) {\r\n if (newD < 1) {\r\n throw new Error('Heap arity (d) must be >= 1');\r\n }\r\n this.depth = newD;\r\n }\r\n }\r\n\r\n /**\r\n * Get a string representation of the heap contents.\r\n * Time complexity: O(n)\r\n *\r\n * @returns Formatted string showing all items in heap order\r\n */\r\n toString(): string {\r\n return '{' + this.container.map(String).join(', ') + '}';\r\n }\r\n\r\n /** Alias for toString() - snake_case for cross-language consistency */\r\n to_string(): string {\r\n return this.toString();\r\n }\r\n\r\n /**\r\n * Get all items in heap order (for debugging/iteration).\r\n * Time complexity: O(n) - creates a copy\r\n *\r\n * @returns Copy of internal array\r\n */\r\n toArray(): T[] {\r\n return [...this.container];\r\n }\r\n\r\n /**\r\n * Iterate over items in heap order (not priority order).\r\n */\r\n *[Symbol.iterator](): Iterator<T> {\r\n for (const item of this.container) {\r\n yield item;\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // Private Methods - Heap Operations\r\n // ===========================================================================\r\n\r\n /**\r\n * Swap two items in the heap and update their position mappings.\r\n * V8 optimizes simple swap patterns well.\r\n */\r\n private swap(i: number, j: number): void {\r\n const container = this.container;\r\n const temp = container[i]!;\r\n container[i] = container[j]!;\r\n container[j] = temp;\r\n\r\n // Update positions\r\n this.positions.set(this.keyExtractor(container[i]!), i);\r\n this.positions.set(this.keyExtractor(container[j]!), j);\r\n }\r\n\r\n /**\r\n * Find the child with highest priority among all children of node i.\r\n */\r\n private bestChildPosition(i: number): number {\r\n const d = this.depth;\r\n const container = this.container;\r\n const n = container.length;\r\n const left = i * d + 1;\r\n\r\n if (left >= n) return left;\r\n\r\n let best = left;\r\n const right = Math.min((i + 1) * d, n - 1);\r\n\r\n for (let j = left + 1; j <= right; j++) {\r\n if (this.comparator(container[j]!, container[best]!)) {\r\n best = j;\r\n }\r\n }\r\n\r\n return best;\r\n }\r\n\r\n /**\r\n * Move an item upward in the heap to restore heap property.\r\n * Uses simple swap pattern which V8 optimizes well.\r\n */\r\n private moveUp(i: number): void {\r\n const d = this.depth;\r\n const container = this.container;\r\n\r\n while (i > 0) {\r\n const p = Math.floor((i - 1) / d);\r\n if (this.comparator(container[i]!, container[p]!)) {\r\n this.swap(i, p);\r\n i = p;\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Move an item downward in the heap to restore heap property.\r\n */\r\n private moveDown(i: number): void {\r\n const d = this.depth;\r\n const container = this.container;\r\n\r\n while (true) {\r\n const firstChild = i * d + 1;\r\n if (firstChild >= container.length) break;\r\n\r\n const best = this.bestChildPosition(i);\r\n if (this.comparator(container[best]!, container[i]!)) {\r\n this.swap(i, best);\r\n i = best;\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * Pre-built comparator factories for common use cases.\r\n *\r\n * @module comparators\r\n * @version 2.4.0\r\n * @license Apache-2.0\r\n */\r\n\r\nimport type { Comparator } from './PriorityQueue';\r\n\r\n/**\r\n * Create a min-heap comparator using a key extractor.\r\n * Lower key values have higher priority (appear closer to root).\r\n *\r\n * @param keyFn - Function to extract the comparable key from an item\r\n * @returns Comparator function for min-heap behavior\r\n *\r\n * @example\r\n * ```typescript\r\n * const minByCost = minBy<Item, number>(item => item.cost);\r\n * ```\r\n */\r\nexport function minBy<T, K>(keyFn: (item: T) => K): Comparator<T> {\r\n return (a: T, b: T) => keyFn(a) < keyFn(b);\r\n}\r\n\r\n/**\r\n * Create a max-heap comparator using a key extractor.\r\n * Higher key values have higher priority (appear closer to root).\r\n *\r\n * @param keyFn - Function to extract the comparable key from an item\r\n * @returns Comparator function for max-heap behavior\r\n *\r\n * @example\r\n * ```typescript\r\n * const maxByCost = maxBy<Item, number>(item => item.cost);\r\n * ```\r\n */\r\nexport function maxBy<T, K>(keyFn: (item: T) => K): Comparator<T> {\r\n return (a: T, b: T) => keyFn(a) > keyFn(b);\r\n}\r\n\r\n/**\r\n * Min-heap comparator for primitive number values.\r\n * Lower numbers have higher priority.\r\n */\r\nexport const minNumber: Comparator<number> = (a, b) => a < b;\r\n\r\n/**\r\n * Max-heap comparator for primitive number values.\r\n * Higher numbers have higher priority.\r\n */\r\nexport const maxNumber: Comparator<number> = (a, b) => a > b;\r\n\r\n/**\r\n * Min-heap comparator for primitive string values.\r\n * Lexicographically smaller strings have higher priority.\r\n */\r\nexport const minString: Comparator<string> = (a, b) => a < b;\r\n\r\n/**\r\n * Max-heap comparator for primitive string values.\r\n * Lexicographically larger strings have higher priority.\r\n */\r\nexport const maxString: Comparator<string> = (a, b) => a > b;\r\n\r\n/**\r\n * Create a comparator that reverses another comparator.\r\n *\r\n * @param cmp - Original comparator to reverse\r\n * @returns Reversed comparator\r\n *\r\n * @example\r\n * ```typescript\r\n * const maxByCost = reverse(minBy<Item, number>(item => item.cost));\r\n * ```\r\n */\r\nexport function reverse<T>(cmp: Comparator<T>): Comparator<T> {\r\n return (a: T, b: T) => cmp(b, a);\r\n}\r\n\r\n/**\r\n * Create a comparator that compares by multiple keys in order.\r\n * Falls back to subsequent comparators when items are equal.\r\n *\r\n * @param comparators - Array of comparators to apply in order\r\n * @returns Combined comparator\r\n *\r\n * @example\r\n * ```typescript\r\n * // Sort by priority first, then by timestamp\r\n * const cmp = chain(\r\n * minBy<Task, number>(t => t.priority),\r\n * minBy<Task, number>(t => t.timestamp)\r\n * );\r\n * ```\r\n */\r\nexport function chain<T>(...comparators: Comparator<T>[]): Comparator<T> {\r\n return (a: T, b: T) => {\r\n for (const cmp of comparators) {\r\n if (cmp(a, b)) return true;\r\n if (cmp(b, a)) return false;\r\n }\r\n return false;\r\n };\r\n}\r\n","/**\r\n * Instrumentation utilities for d-ary heap performance analysis.\r\n *\r\n * This module provides opt-in instrumentation to count comparisons performed\r\n * during heap operations. It is designed for:\r\n *\r\n * - **Educational purposes**: Understanding the theoretical vs actual cost of heap operations\r\n * - **Benchmarking**: Measuring real comparison counts across different arities\r\n * - **Visualization**: Powering interactive demos that show heap behavior\r\n *\r\n * ## Design Philosophy: Zero-Cost When Disabled\r\n *\r\n * Instrumentation follows these principles:\r\n *\r\n * 1. **Opt-in only**: No overhead when not using instrumentation\r\n * 2. **Non-breaking**: Existing code continues to work unchanged\r\n * 3. **Per-operation tracking**: Distinguish insert/pop/decreasePriority comparisons\r\n *\r\n * ## Cross-Language Consistency\r\n *\r\n * Currently, instrumentation is implemented in TypeScript only. The table below\r\n * shows the idiomatic zero-cost approach for each language, planned for v2.5.0:\r\n *\r\n * | Language | Mechanism | Overhead When Disabled | Status |\r\n * |------------|----------------------------------|------------------------|--------|\r\n * | TypeScript | Optional hooks + instrumented comparator | Zero (JIT optimization) | ✅ Implemented |\r\n * | Go | Nil stats pointer | ~1 cycle (nil check) | Planned v2.5.0 |\r\n * | Rust | Generic over StatsCollector trait | Zero (monomorphization) | Planned v2.5.0 |\r\n * | C++ | Template policy class | Zero (inlining) | Planned v2.5.0 |\r\n * | Zig | Comptime bool parameter | Zero (branch elimination) | Planned v2.5.0 |\r\n *\r\n * ## Usage Example\r\n *\r\n * ```typescript\r\n * import { PriorityQueue, minBy, instrumentComparator } from 'd-ary-heap';\r\n *\r\n * // 1. Wrap your comparator with instrumentation\r\n * const comparator = instrumentComparator(minBy((v: Vertex) => v.distance));\r\n *\r\n * // 2. Create priority queue with operation hooks\r\n * const pq = new PriorityQueue({\r\n * d: 4,\r\n * comparator,\r\n * keyExtractor: (v) => v.id,\r\n * onBeforeOperation: (op) => comparator.startOperation(op),\r\n * onAfterOperation: () => comparator.endOperation(),\r\n * });\r\n *\r\n * // 3. Use normally - comparisons are tracked automatically\r\n * pq.insert({ id: 'A', distance: 0 });\r\n * pq.insert({ id: 'B', distance: 5 });\r\n * pq.pop();\r\n *\r\n * // 4. Access statistics\r\n * console.log(comparator.stats);\r\n * // { insert: 1, pop: 2, decreasePriority: 0, total: 3 }\r\n *\r\n * // 5. Reset for next measurement\r\n * comparator.stats.reset();\r\n * ```\r\n *\r\n * ## Theoretical Complexity Reference\r\n *\r\n * For a d-ary heap with n elements:\r\n *\r\n * | Operation | Comparisons (worst case) |\r\n * |------------------|----------------------------|\r\n * | insert | ⌊log_d(n)⌋ |\r\n * | pop | d × ⌊log_d(n)⌋ |\r\n * | decreasePriority | ⌊log_d(n)⌋ (upward only) |\r\n * | increasePriority | d × ⌊log_d(n)⌋ (downward) |\r\n *\r\n * The demo visualization compares actual counts against these theoretical bounds.\r\n *\r\n * @module instrumentation\r\n * @version 2.4.0\r\n * @license Apache-2.0\r\n */\r\n\r\nimport type { Comparator } from './PriorityQueue';\r\n\r\n/**\r\n * Operation types that can be tracked.\r\n *\r\n * Note: `increasePriority` is tracked separately because in Dijkstra's algorithm\r\n * it manifests as decreasePriority (lowering distance = higher priority in min-heap).\r\n */\r\nexport type OperationType = 'insert' | 'pop' | 'decreasePriority' | 'increasePriority';\r\n\r\n/**\r\n * Statistics tracking comparison counts per operation type.\r\n *\r\n * All counts start at zero and accumulate until `reset()` is called.\r\n */\r\nexport interface ComparisonStats {\r\n /** Comparisons during insert operations (moveUp) */\r\n insert: number;\r\n\r\n /** Comparisons during pop operations (moveDown + bestChildPosition) */\r\n pop: number;\r\n\r\n /** Comparisons during decreasePriority operations (moveUp + moveDown) */\r\n decreasePriority: number;\r\n\r\n /** Comparisons during increasePriority operations (moveUp) */\r\n increasePriority: number;\r\n\r\n /** Total comparisons across all operation types */\r\n readonly total: number;\r\n\r\n /** Reset all counters to zero */\r\n reset(): void;\r\n}\r\n\r\n/**\r\n * An instrumented comparator that tracks comparison counts.\r\n *\r\n * This extends a regular comparator with:\r\n * - `stats`: Current comparison counts\r\n * - `startOperation(type)`: Begin tracking for an operation\r\n * - `endOperation()`: Stop tracking current operation\r\n *\r\n * The comparator itself remains a valid `Comparator<T>` and can be used\r\n * anywhere a regular comparator is expected.\r\n */\r\nexport interface InstrumentedComparator<T> extends Comparator<T> {\r\n /** Current comparison statistics */\r\n readonly stats: ComparisonStats;\r\n\r\n /**\r\n * Signal the start of a heap operation.\r\n * Comparisons will be attributed to this operation type until `endOperation()`.\r\n *\r\n * @param type - The operation type being started\r\n */\r\n startOperation(type: OperationType): void;\r\n\r\n /**\r\n * Signal the end of the current heap operation.\r\n * Subsequent comparisons will not be counted until the next `startOperation()`.\r\n */\r\n endOperation(): void;\r\n}\r\n\r\n/**\r\n * Create comparison statistics tracker.\r\n *\r\n * @returns Fresh stats object with all counts at zero\r\n *\r\n * @example\r\n * ```typescript\r\n * const stats = createComparisonStats();\r\n * stats.insert = 5;\r\n * stats.pop = 10;\r\n * console.log(stats.total); // 15\r\n * stats.reset();\r\n * console.log(stats.total); // 0\r\n * ```\r\n */\r\nexport function createComparisonStats(): ComparisonStats {\r\n const stats: ComparisonStats = {\r\n insert: 0,\r\n pop: 0,\r\n decreasePriority: 0,\r\n increasePriority: 0,\r\n\r\n get total(): number {\r\n return this.insert + this.pop + this.decreasePriority + this.increasePriority;\r\n },\r\n\r\n reset(): void {\r\n this.insert = 0;\r\n this.pop = 0;\r\n this.decreasePriority = 0;\r\n this.increasePriority = 0;\r\n },\r\n };\r\n\r\n return stats;\r\n}\r\n\r\n/**\r\n * Wrap a comparator with instrumentation to track comparison counts.\r\n *\r\n * The returned comparator:\r\n * - Behaves identically to the original for comparison purposes\r\n * - Tracks how many times it's called, attributed to operation types\r\n * - Has zero overhead when `startOperation()` hasn't been called\r\n *\r\n * ## How It Works\r\n *\r\n * 1. Call `startOperation('insert')` before `pq.insert()`\r\n * 2. The comparator increments `stats.insert` for each comparison\r\n * 3. Call `endOperation()` after the operation completes\r\n * 4. Repeat for other operations\r\n *\r\n * The `PriorityQueue` class supports `onBeforeOperation` and `onAfterOperation`\r\n * hooks to automate this.\r\n *\r\n * ## Performance Note\r\n *\r\n * When `currentOperation` is null (between operations), the instrumented\r\n * comparator performs only a single null check before calling the original.\r\n * Modern JavaScript engines optimize this extremely well.\r\n *\r\n * @param comparator - The original comparator to instrument\r\n * @returns An instrumented comparator with stats tracking\r\n *\r\n * @example\r\n * ```typescript\r\n * import { minBy, instrumentComparator } from 'd-ary-heap';\r\n *\r\n * const cmp = instrumentComparator(minBy<number, number>(x => x));\r\n *\r\n * // Manual usage (without hooks)\r\n * cmp.startOperation('insert');\r\n * console.log(cmp(5, 3)); // false, and stats.insert++\r\n * console.log(cmp(3, 5)); // true, and stats.insert++\r\n * cmp.endOperation();\r\n *\r\n * console.log(cmp.stats.insert); // 2\r\n * ```\r\n */\r\nexport function instrumentComparator<T>(comparator: Comparator<T>): InstrumentedComparator<T> {\r\n const stats = createComparisonStats();\r\n let currentOperation: OperationType | null = null;\r\n\r\n // Create the instrumented function\r\n const instrumented = ((a: T, b: T): boolean => {\r\n // Only count when actively tracking an operation\r\n if (currentOperation !== null) {\r\n stats[currentOperation]++;\r\n }\r\n return comparator(a, b);\r\n }) as InstrumentedComparator<T>;\r\n\r\n // Attach stats (read-only from outside)\r\n Object.defineProperty(instrumented, 'stats', {\r\n value: stats,\r\n writable: false,\r\n enumerable: true,\r\n });\r\n\r\n // Attach operation control methods\r\n instrumented.startOperation = (type: OperationType): void => {\r\n currentOperation = type;\r\n };\r\n\r\n instrumented.endOperation = (): void => {\r\n currentOperation = null;\r\n };\r\n\r\n return instrumented;\r\n}\r\n\r\n/**\r\n * Calculate theoretical comparison count for an insert operation.\r\n *\r\n * Insert performs at most ⌊log_d(n)⌋ comparisons (one per level during moveUp).\r\n *\r\n * @param n - Number of elements in heap AFTER insert\r\n * @param d - Heap arity\r\n * @returns Theoretical worst-case comparison count\r\n */\r\nexport function theoreticalInsertComparisons(n: number, d: number): number {\r\n if (n <= 1) return 0;\r\n return Math.floor(Math.log(n) / Math.log(d));\r\n}\r\n\r\n/**\r\n * Calculate theoretical comparison count for a pop operation.\r\n *\r\n * Pop performs at most d × ⌊log_d(n)⌋ comparisons:\r\n * - At each level, find best among d children (d-1 comparisons)\r\n * - Compare best child with current (1 comparison)\r\n * - Total: d comparisons per level × ⌊log_d(n)⌋ levels\r\n *\r\n * @param n - Number of elements in heap BEFORE pop\r\n * @param d - Heap arity\r\n * @returns Theoretical worst-case comparison count\r\n */\r\nexport function theoreticalPopComparisons(n: number, d: number): number {\r\n if (n <= 1) return 0;\r\n const height = Math.floor(Math.log(n) / Math.log(d));\r\n return d * height;\r\n}\r\n\r\n/**\r\n * Calculate theoretical comparison count for a decreasePriority operation.\r\n *\r\n * DecreasePriority in our implementation calls both moveUp and moveDown\r\n * for safety, but typically only moveUp executes (upward movement).\r\n * Worst case: ⌊log_d(n)⌋ comparisons.\r\n *\r\n * @param n - Number of elements in heap\r\n * @param d - Heap arity\r\n * @returns Theoretical worst-case comparison count (moveUp path)\r\n */\r\nexport function theoreticalDecreasePriorityComparisons(n: number, d: number): number {\r\n if (n <= 1) return 0;\r\n return Math.floor(Math.log(n) / Math.log(d));\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/PriorityQueue.ts","../src/comparators.ts","../src/instrumentation.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * d-ary Heap Priority Queue - TypeScript Implementation\r\n *\r\n * A generic d-ary heap (d-heap) priority queue with:\r\n * - Configurable arity (d): number of children per node\r\n * - Min-heap or max-heap behavior via comparator functions\r\n * - O(1) item lookup using Map for efficient priority updates\r\n * - O(1) access to highest-priority item\r\n * - O(log_d n) insert and increasePriority operations\r\n * - O(d · log_d n) pop and decreasePriority operations\r\n * - O((d+1) · log_d n) updatePriority (bidirectional)\r\n * - Optional instrumentation hooks for performance analysis\r\n *\r\n * @version 2.4.0\r\n * @license Apache-2.0\r\n * @copyright 2023-2025 Eric Jacopin\r\n */\r\n\r\nimport type { OperationType } from './instrumentation';\r\n\r\n/** Type alias for position indices (cross-language consistency) */\r\nexport type Position = number;\r\n\r\n/**\r\n * Comparator function type for priority comparison.\r\n * Returns true if `a` has higher priority than `b`.\r\n */\r\nexport type Comparator<T> = (a: T, b: T) => boolean;\r\n\r\n/**\r\n * Key extractor function type for identity-based lookup.\r\n * Must return a value that can be used as a Map key (string or number recommended).\r\n */\r\nexport type KeyExtractor<T, K> = (item: T) => K;\r\n\r\n/**\r\n * Configuration options for PriorityQueue construction.\r\n */\r\nexport interface PriorityQueueOptions<T, K> {\r\n /** Number of children per node (arity). Must be >= 1. Default: 2 */\r\n d?: number;\r\n /** Comparator function. Returns true if first arg has higher priority. */\r\n comparator: Comparator<T>;\r\n /** Key extractor for identity-based lookup. Required for decrease/increase priority. */\r\n keyExtractor: KeyExtractor<T, K>;\r\n /** Initial capacity hint for pre-allocation */\r\n initialCapacity?: number;\r\n\r\n /**\r\n * Optional hook called before each heap operation.\r\n *\r\n * This enables opt-in instrumentation for performance analysis without\r\n * adding overhead when not used. Pair with an instrumented comparator\r\n * to track comparison counts per operation type.\r\n *\r\n * @param type - The operation about to be performed\r\n *\r\n * @example\r\n * ```typescript\r\n * const cmp = instrumentComparator(minBy((v) => v.priority));\r\n * const pq = new PriorityQueue({\r\n * comparator: cmp,\r\n * keyExtractor: (v) => v.id,\r\n * onBeforeOperation: (op) => cmp.startOperation(op),\r\n * onAfterOperation: () => cmp.endOperation(),\r\n * });\r\n * ```\r\n *\r\n * @see instrumentComparator from './instrumentation'\r\n */\r\n onBeforeOperation?: (type: OperationType) => void;\r\n\r\n /**\r\n * Optional hook called after each heap operation completes.\r\n *\r\n * @see onBeforeOperation for usage example\r\n */\r\n onAfterOperation?: () => void;\r\n}\r\n\r\n/**\r\n * Generic d-ary heap priority queue with O(1) lookup.\r\n *\r\n * A d-ary heap is a tree structure where:\r\n * - Each node has at most d children\r\n * - The root contains the highest-priority item\r\n * - Each parent has higher priority than all its children\r\n * - The tree is complete (filled left-to-right, level by level)\r\n *\r\n * This implementation uses an array-based representation with O(1) item lookup\r\n * via a Map that tracks each item's position in the heap.\r\n *\r\n * ## Time Complexities\r\n * - front(), peek(): O(1)\r\n * - insert(): O(log_d n)\r\n * - pop(): O(d · log_d n)\r\n * - increasePriority(): O(log_d n)\r\n * - decreasePriority(): O(d · log_d n)\r\n * - updatePriority(): O((d+1) · log_d n)\r\n * - contains(): O(1)\r\n * - len(), isEmpty(), d(): O(1)\r\n *\r\n * @typeParam T - Item type stored in the queue\r\n * @typeParam K - Key type for identity lookup (typically string or number)\r\n */\r\nexport class PriorityQueue<T, K = string | number> {\r\n /** Array-based heap storage (complete tree representation) */\r\n private container: T[];\r\n\r\n /** Maps each item's key to its position in the container for O(1) lookup */\r\n private positions: Map<K, Position>;\r\n\r\n /** Number of children per node (arity of the heap) */\r\n private depth: number;\r\n\r\n /** Comparator determining heap order (min vs max) */\r\n private readonly comparator: Comparator<T>;\r\n\r\n /** Key extractor for identity-based lookup */\r\n private readonly keyExtractor: KeyExtractor<T, K>;\r\n\r\n /** Optional hook called before operations (for instrumentation) */\r\n private readonly onBeforeOperation: ((type: OperationType) => void) | undefined;\r\n\r\n /** Optional hook called after operations (for instrumentation) */\r\n private readonly onAfterOperation: (() => void) | undefined;\r\n\r\n /**\r\n * Create a new d-ary heap priority queue.\r\n *\r\n * @param options - Configuration options\r\n * @throws Error if d < 1\r\n *\r\n * @example\r\n * ```typescript\r\n * // Min-heap by cost\r\n * const pq = new PriorityQueue<Item, number>({\r\n * d: 4,\r\n * comparator: (a, b) => a.cost < b.cost,\r\n * keyExtractor: (item) => item.id\r\n * });\r\n * ```\r\n */\r\n constructor(options: PriorityQueueOptions<T, K>) {\r\n const d = options.d ?? 2;\r\n if (d < 1) {\r\n throw new Error('Heap arity (d) must be >= 1');\r\n }\r\n\r\n this.depth = d;\r\n this.comparator = options.comparator;\r\n this.keyExtractor = options.keyExtractor;\r\n this.onBeforeOperation = options.onBeforeOperation;\r\n this.onAfterOperation = options.onAfterOperation;\r\n\r\n // Pre-allocate if capacity hint provided\r\n const capacity = options.initialCapacity ?? 0;\r\n this.container = capacity > 0 ? new Array<T>(capacity) : [];\r\n if (capacity > 0) this.container.length = 0; // Reset length but keep capacity\r\n this.positions = new Map<K, Position>();\r\n }\r\n\r\n /**\r\n * Create a new priority queue with an initial item already inserted.\r\n * Equivalent to Rust's `with_first()` constructor.\r\n *\r\n * @param options - Configuration options\r\n * @param firstItem - First item to insert\r\n * @returns New PriorityQueue with the item already inserted\r\n */\r\n static withFirst<T, K>(\r\n options: PriorityQueueOptions<T, K>,\r\n firstItem: T\r\n ): PriorityQueue<T, K> {\r\n const pq = new PriorityQueue<T, K>(options);\r\n pq.insert(firstItem);\r\n return pq;\r\n }\r\n\r\n // ===========================================================================\r\n // Public API - Query Operations\r\n // ===========================================================================\r\n\r\n /**\r\n * Get the number of items in the heap.\r\n * Time complexity: O(1)\r\n */\r\n len(): number {\r\n return this.container.length;\r\n }\r\n\r\n /** Alias for len() - backward compatibility */\r\n get size(): number {\r\n return this.container.length;\r\n }\r\n\r\n /**\r\n * Check if the heap is empty.\r\n * Time complexity: O(1)\r\n */\r\n isEmpty(): boolean {\r\n return this.container.length === 0;\r\n }\r\n\r\n /** Alias for isEmpty() - snake_case for cross-language consistency */\r\n is_empty(): boolean {\r\n return this.isEmpty();\r\n }\r\n\r\n /**\r\n * Get the arity (number of children per node) of the heap.\r\n * Time complexity: O(1)\r\n */\r\n d(): number {\r\n return this.depth;\r\n }\r\n\r\n /**\r\n * Check if an item with the given key exists in the heap.\r\n * Time complexity: O(1)\r\n *\r\n * @param item - Item to check (uses keyExtractor for identity)\r\n */\r\n contains(item: T): boolean {\r\n return this.positions.has(this.keyExtractor(item));\r\n }\r\n\r\n /**\r\n * Check if an item with the given key exists in the heap.\r\n * Time complexity: O(1)\r\n *\r\n * @param key - Key to check directly\r\n */\r\n containsKey(key: K): boolean {\r\n return this.positions.has(key);\r\n }\r\n\r\n /**\r\n * Get the current position (index) of an item in the heap.\r\n * Time complexity: O(1)\r\n *\r\n * @param item - Item to find (uses keyExtractor for identity)\r\n * @returns Position index, or undefined if not found\r\n */\r\n getPosition(item: T): Position | undefined {\r\n return this.positions.get(this.keyExtractor(item));\r\n }\r\n\r\n /**\r\n * Get the current position (index) of an item by its key.\r\n * Time complexity: O(1)\r\n *\r\n * @param key - Key to find\r\n * @returns Position index, or undefined if not found\r\n */\r\n getPositionByKey(key: K): Position | undefined {\r\n return this.positions.get(key);\r\n }\r\n\r\n /**\r\n * Get the highest-priority item without removing it.\r\n * Time complexity: O(1)\r\n *\r\n * @returns The highest-priority item\r\n * @throws Error if heap is empty\r\n */\r\n front(): T {\r\n const item = this.container[0];\r\n if (item === undefined) {\r\n throw new Error('front() called on empty priority queue');\r\n }\r\n return item;\r\n }\r\n\r\n /**\r\n * Get the highest-priority item without removing it.\r\n * Safe alternative to front().\r\n * Time complexity: O(1)\r\n *\r\n * @returns The highest-priority item, or undefined if empty\r\n */\r\n peek(): T | undefined {\r\n return this.container.length > 0 ? this.container[0] : undefined;\r\n }\r\n\r\n // ===========================================================================\r\n // Public API - Modification Operations\r\n // ===========================================================================\r\n\r\n /**\r\n * Insert a new item into the heap.\r\n * Time complexity: O(log_d n)\r\n *\r\n * @param item - Item to insert\r\n *\r\n * @remarks\r\n * If an item with the same key already exists, behavior is undefined.\r\n * Use contains() to check first, or use increasePriority()/decreasePriority()\r\n * to update existing items.\r\n */\r\n insert(item: T): void {\r\n this.onBeforeOperation?.('insert');\r\n\r\n const index = this.container.length;\r\n this.container.push(item);\r\n\r\n // Fast path: first item doesn't need sift-up\r\n if (index === 0) {\r\n this.positions.set(this.keyExtractor(item), 0);\r\n this.onAfterOperation?.();\r\n return;\r\n }\r\n\r\n this.positions.set(this.keyExtractor(item), index);\r\n this.moveUp(index);\r\n\r\n this.onAfterOperation?.();\r\n }\r\n\r\n /**\r\n * Insert multiple items into the heap.\r\n * Uses heapify algorithm which is O(n) for bulk insertion vs O(n log n) for individual inserts.\r\n * Time complexity: O(n) where n is total items after insertion\r\n *\r\n * @param items - Array of items to insert\r\n *\r\n * @remarks\r\n * More efficient than calling insert() repeatedly when adding many items at once.\r\n * If any item has a key that already exists, behavior is undefined.\r\n */\r\n insertMany(items: T[]): void {\r\n if (items.length === 0) return;\r\n\r\n const keyExtractor = this.keyExtractor;\r\n const container = this.container;\r\n const positions = this.positions;\r\n const startIndex = container.length;\r\n\r\n // Add all items to container and positions map\r\n for (let i = 0; i < items.length; i++) {\r\n const item = items[i]!;\r\n container.push(item);\r\n positions.set(keyExtractor(item), startIndex + i);\r\n }\r\n\r\n // If this was an empty heap, use heapify (O(n)) instead of n insertions (O(n log n))\r\n if (startIndex === 0 && items.length > 1) {\r\n this.heapify();\r\n } else {\r\n // Otherwise, sift up each new item\r\n for (let i = startIndex; i < container.length; i++) {\r\n this.moveUp(i);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Build heap property from unordered array.\r\n * Uses Floyd's algorithm - O(n) time complexity.\r\n * Called internally by insertMany when starting from empty heap.\r\n */\r\n private heapify(): void {\r\n const n = this.container.length;\r\n if (n <= 1) return;\r\n\r\n const d = this.depth;\r\n // Start from last non-leaf node and sift down each\r\n // Last non-leaf is parent of last element: floor((n-2)/d)\r\n const lastNonLeaf = ((n - 2) / d) | 0;\r\n\r\n for (let i = lastNonLeaf; i >= 0; i--) {\r\n this.moveDown(i);\r\n }\r\n }\r\n\r\n /**\r\n * Increase the priority of an existing item (move toward root).\r\n * Time complexity: O(log_d n)\r\n *\r\n * @param updatedItem - Item with same identity but updated priority\r\n * @throws Error if item not found\r\n *\r\n * @remarks\r\n * For min-heap: decreasing the priority value increases importance.\r\n * For max-heap: increasing the priority value increases importance.\r\n * This method only moves items upward for performance.\r\n */\r\n increasePriority(updatedItem: T): void {\r\n this.onBeforeOperation?.('increasePriority');\r\n\r\n const key = this.keyExtractor(updatedItem);\r\n const index = this.positions.get(key);\r\n\r\n if (index === undefined) {\r\n this.onAfterOperation?.();\r\n throw new Error('Item not found in priority queue');\r\n }\r\n\r\n this.container[index] = updatedItem;\r\n this.moveUp(index);\r\n\r\n this.onAfterOperation?.();\r\n }\r\n\r\n /** Alias for increasePriority() - snake_case for cross-language consistency */\r\n increase_priority(updatedItem: T): void {\r\n this.increasePriority(updatedItem);\r\n }\r\n\r\n /**\r\n * Increase the priority of the item at the given index.\r\n * Time complexity: O(log_d n)\r\n *\r\n * @param index - Index of the item in the heap array\r\n * @throws Error if index is out of bounds\r\n *\r\n * @remarks\r\n * This is a lower-level method. Prefer increasePriority() with the item itself.\r\n */\r\n increasePriorityByIndex(index: number): void {\r\n if (index < 0 || index >= this.container.length) {\r\n throw new Error('Index out of bounds');\r\n }\r\n this.moveUp(index);\r\n }\r\n\r\n /** Alias for increasePriorityByIndex() - snake_case for cross-language consistency */\r\n increase_priority_by_index(index: number): void {\r\n this.increasePriorityByIndex(index);\r\n }\r\n\r\n /**\r\n * Decrease the priority of the item at the given index.\r\n * Time complexity: O(d · log_d n)\r\n *\r\n * @param index - Index of the item in the heap array\r\n * @throws Error if index is out of bounds\r\n *\r\n * @remarks\r\n * This is a lower-level method. Prefer decreasePriority() with the item itself.\r\n * The item at the given index should already have its priority value updated\r\n * in the container before calling this method.\r\n */\r\n decreasePriorityByIndex(index: number): void {\r\n if (index < 0 || index >= this.container.length) {\r\n throw new Error('Index out of bounds');\r\n }\r\n this.moveDown(index);\r\n }\r\n\r\n /** Alias for decreasePriorityByIndex() - snake_case for cross-language consistency */\r\n decrease_priority_by_index(index: number): void {\r\n this.decreasePriorityByIndex(index);\r\n }\r\n\r\n /**\r\n * Decrease the priority of an existing item (move toward leaves).\r\n * Time complexity: O(d · log_d n)\r\n *\r\n * @param updatedItem - Item with same identity but updated priority\r\n * @throws Error if item not found\r\n *\r\n * @remarks\r\n * For min-heap: increasing the priority value decreases importance.\r\n * For max-heap: decreasing the priority value decreases importance.\r\n * This method only moves items downward. Use updatePriority() if direction is unknown.\r\n */\r\n decreasePriority(updatedItem: T): void {\r\n this.onBeforeOperation?.('decreasePriority');\r\n\r\n const key = this.keyExtractor(updatedItem);\r\n const index = this.positions.get(key);\r\n\r\n if (index === undefined) {\r\n this.onAfterOperation?.();\r\n throw new Error('Item not found in priority queue');\r\n }\r\n\r\n this.container[index] = updatedItem;\r\n this.moveDown(index);\r\n\r\n this.onAfterOperation?.();\r\n }\r\n\r\n /** Alias for decreasePriority() - snake_case for cross-language consistency */\r\n decrease_priority(updatedItem: T): void {\r\n this.decreasePriority(updatedItem);\r\n }\r\n\r\n /**\r\n * Update the priority of an existing item when direction is unknown.\r\n * Time complexity: O((d+1) · log_d n) - checks both directions\r\n *\r\n * @param updatedItem - Item with same identity but updated priority\r\n * @throws Error if item not found\r\n *\r\n * @remarks\r\n * Use this method when you don't know whether the priority increased or decreased.\r\n * If you know the direction, prefer increasePriority() or decreasePriority() for\r\n * better performance (log_d n vs (d+1) · log_d n comparisons).\r\n */\r\n updatePriority(updatedItem: T): void {\r\n this.onBeforeOperation?.('updatePriority');\r\n\r\n const key = this.keyExtractor(updatedItem);\r\n const index = this.positions.get(key);\r\n\r\n if (index === undefined) {\r\n this.onAfterOperation?.();\r\n throw new Error('Item not found in priority queue');\r\n }\r\n\r\n this.container[index] = updatedItem;\r\n // Check both directions since we don't know which way priority changed\r\n this.moveUp(index);\r\n this.moveDown(index);\r\n\r\n this.onAfterOperation?.();\r\n }\r\n\r\n /** Alias for updatePriority() - snake_case for cross-language consistency */\r\n update_priority(updatedItem: T): void {\r\n this.updatePriority(updatedItem);\r\n }\r\n\r\n /**\r\n * Remove and return the highest-priority item.\r\n * Time complexity: O(d · log_d n)\r\n *\r\n * @returns The removed item, or undefined if empty\r\n */\r\n pop(): T | undefined {\r\n this.onBeforeOperation?.('pop');\r\n\r\n const container = this.container;\r\n const n = container.length;\r\n\r\n if (n === 0) {\r\n this.onAfterOperation?.();\r\n return undefined;\r\n }\r\n\r\n const keyExtractor = this.keyExtractor;\r\n const top = container[0]!;\r\n this.positions.delete(keyExtractor(top));\r\n\r\n if (n === 1) {\r\n container.length = 0;\r\n this.onAfterOperation?.();\r\n return top;\r\n }\r\n\r\n // Move last item to root and sift down\r\n const lastItem = container[n - 1]!;\r\n container[0] = lastItem;\r\n this.positions.set(keyExtractor(lastItem), 0);\r\n container.length = n - 1;\r\n\r\n this.moveDown(0);\r\n\r\n this.onAfterOperation?.();\r\n return top;\r\n }\r\n\r\n /**\r\n * Remove and return multiple highest-priority items.\r\n * More efficient than calling pop() repeatedly.\r\n * Time complexity: O(count · d · log_d n)\r\n *\r\n * @param count - Number of items to remove\r\n * @returns Array of removed items in priority order\r\n */\r\n popMany(count: number): T[] {\r\n const result: T[] = [];\r\n const actualCount = count < this.container.length ? count : this.container.length;\r\n\r\n for (let i = 0; i < actualCount; i++) {\r\n const item = this.pop();\r\n if (item !== undefined) {\r\n result.push(item);\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Clear all items from the heap, optionally changing the arity.\r\n * Time complexity: O(1) (references cleared, GC handles memory)\r\n *\r\n * @param newD - Optional new arity value (must be >= 1 if provided)\r\n * @throws Error if newD < 1\r\n */\r\n clear(newD?: number): void {\r\n this.container.length = 0;\r\n this.positions.clear();\r\n\r\n if (newD !== undefined) {\r\n if (newD < 1) {\r\n throw new Error('Heap arity (d) must be >= 1');\r\n }\r\n this.depth = newD;\r\n }\r\n }\r\n\r\n /**\r\n * Get a string representation of the heap contents.\r\n * Time complexity: O(n)\r\n *\r\n * @returns Formatted string showing all items in heap order\r\n */\r\n toString(): string {\r\n return '{' + this.container.map(String).join(', ') + '}';\r\n }\r\n\r\n /** Alias for toString() - snake_case for cross-language consistency */\r\n to_string(): string {\r\n return this.toString();\r\n }\r\n\r\n /**\r\n * Get all items in heap order (for debugging/iteration).\r\n * Time complexity: O(n) - creates a copy\r\n *\r\n * @returns Copy of internal array\r\n */\r\n toArray(): T[] {\r\n return [...this.container];\r\n }\r\n\r\n /**\r\n * Iterate over items in heap order (not priority order).\r\n */\r\n *[Symbol.iterator](): Iterator<T> {\r\n for (const item of this.container) {\r\n yield item;\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // Private Methods - Heap Operations\r\n // ===========================================================================\r\n\r\n /**\r\n * Swap two items in the heap and update their position mappings.\r\n * V8 optimizes simple swap patterns well.\r\n */\r\n private swap(i: number, j: number): void {\r\n const container = this.container;\r\n const temp = container[i]!;\r\n container[i] = container[j]!;\r\n container[j] = temp;\r\n\r\n // Update positions\r\n this.positions.set(this.keyExtractor(container[i]!), i);\r\n this.positions.set(this.keyExtractor(container[j]!), j);\r\n }\r\n\r\n /**\r\n * Find the child with highest priority among all children of node i.\r\n */\r\n private bestChildPosition(i: number): number {\r\n const d = this.depth;\r\n const container = this.container;\r\n const n = container.length;\r\n const left = i * d + 1;\r\n\r\n if (left >= n) return left;\r\n\r\n let best = left;\r\n const right = Math.min((i + 1) * d, n - 1);\r\n\r\n for (let j = left + 1; j <= right; j++) {\r\n if (this.comparator(container[j]!, container[best]!)) {\r\n best = j;\r\n }\r\n }\r\n\r\n return best;\r\n }\r\n\r\n /**\r\n * Move an item upward in the heap to restore heap property.\r\n * Uses simple swap pattern which V8 optimizes well.\r\n */\r\n private moveUp(i: number): void {\r\n const d = this.depth;\r\n const container = this.container;\r\n\r\n while (i > 0) {\r\n const p = Math.floor((i - 1) / d);\r\n if (this.comparator(container[i]!, container[p]!)) {\r\n this.swap(i, p);\r\n i = p;\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Move an item downward in the heap to restore heap property.\r\n */\r\n private moveDown(i: number): void {\r\n const d = this.depth;\r\n const container = this.container;\r\n\r\n while (true) {\r\n const firstChild = i * d + 1;\r\n if (firstChild >= container.length) break;\r\n\r\n const best = this.bestChildPosition(i);\r\n if (this.comparator(container[best]!, container[i]!)) {\r\n this.swap(i, best);\r\n i = best;\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * Pre-built comparator factories for common use cases.\r\n *\r\n * @module comparators\r\n * @version 2.4.0\r\n * @license Apache-2.0\r\n */\r\n\r\nimport type { Comparator } from './PriorityQueue';\r\n\r\n/**\r\n * Create a min-heap comparator using a key extractor.\r\n * Lower key values have higher priority (appear closer to root).\r\n *\r\n * @param keyFn - Function to extract the comparable key from an item\r\n * @returns Comparator function for min-heap behavior\r\n *\r\n * @example\r\n * ```typescript\r\n * const minByCost = minBy<Item, number>(item => item.cost);\r\n * ```\r\n */\r\nexport function minBy<T, K>(keyFn: (item: T) => K): Comparator<T> {\r\n return (a: T, b: T) => keyFn(a) < keyFn(b);\r\n}\r\n\r\n/**\r\n * Create a max-heap comparator using a key extractor.\r\n * Higher key values have higher priority (appear closer to root).\r\n *\r\n * @param keyFn - Function to extract the comparable key from an item\r\n * @returns Comparator function for max-heap behavior\r\n *\r\n * @example\r\n * ```typescript\r\n * const maxByCost = maxBy<Item, number>(item => item.cost);\r\n * ```\r\n */\r\nexport function maxBy<T, K>(keyFn: (item: T) => K): Comparator<T> {\r\n return (a: T, b: T) => keyFn(a) > keyFn(b);\r\n}\r\n\r\n/**\r\n * Min-heap comparator for primitive number values.\r\n * Lower numbers have higher priority.\r\n */\r\nexport const minNumber: Comparator<number> = (a, b) => a < b;\r\n\r\n/**\r\n * Max-heap comparator for primitive number values.\r\n * Higher numbers have higher priority.\r\n */\r\nexport const maxNumber: Comparator<number> = (a, b) => a > b;\r\n\r\n/**\r\n * Min-heap comparator for primitive string values.\r\n * Lexicographically smaller strings have higher priority.\r\n */\r\nexport const minString: Comparator<string> = (a, b) => a < b;\r\n\r\n/**\r\n * Max-heap comparator for primitive string values.\r\n * Lexicographically larger strings have higher priority.\r\n */\r\nexport const maxString: Comparator<string> = (a, b) => a > b;\r\n\r\n/**\r\n * Create a comparator that reverses another comparator.\r\n *\r\n * @param cmp - Original comparator to reverse\r\n * @returns Reversed comparator\r\n *\r\n * @example\r\n * ```typescript\r\n * const maxByCost = reverse(minBy<Item, number>(item => item.cost));\r\n * ```\r\n */\r\nexport function reverse<T>(cmp: Comparator<T>): Comparator<T> {\r\n return (a: T, b: T) => cmp(b, a);\r\n}\r\n\r\n/**\r\n * Create a comparator that compares by multiple keys in order.\r\n * Falls back to subsequent comparators when items are equal.\r\n *\r\n * @param comparators - Array of comparators to apply in order\r\n * @returns Combined comparator\r\n *\r\n * @example\r\n * ```typescript\r\n * // Sort by priority first, then by timestamp\r\n * const cmp = chain(\r\n * minBy<Task, number>(t => t.priority),\r\n * minBy<Task, number>(t => t.timestamp)\r\n * );\r\n * ```\r\n */\r\nexport function chain<T>(...comparators: Comparator<T>[]): Comparator<T> {\r\n return (a: T, b: T) => {\r\n for (const cmp of comparators) {\r\n if (cmp(a, b)) return true;\r\n if (cmp(b, a)) return false;\r\n }\r\n return false;\r\n };\r\n}\r\n","/**\r\n * Instrumentation utilities for d-ary heap performance analysis.\r\n *\r\n * This module provides opt-in instrumentation to count comparisons performed\r\n * during heap operations. It is designed for:\r\n *\r\n * - **Educational purposes**: Understanding the theoretical vs actual cost of heap operations\r\n * - **Benchmarking**: Measuring real comparison counts across different arities\r\n * - **Visualization**: Powering interactive demos that show heap behavior\r\n *\r\n * ## Design Philosophy: Zero-Cost When Disabled\r\n *\r\n * Instrumentation follows these principles:\r\n *\r\n * 1. **Opt-in only**: No overhead when not using instrumentation\r\n * 2. **Non-breaking**: Existing code continues to work unchanged\r\n * 3. **Per-operation tracking**: Distinguish insert/pop/decreasePriority comparisons\r\n *\r\n * ## Cross-Language Consistency\r\n *\r\n * Currently, instrumentation is implemented in TypeScript only. The table below\r\n * shows the idiomatic zero-cost approach for each language, planned for v2.5.0:\r\n *\r\n * | Language | Mechanism | Overhead When Disabled | Status |\r\n * |------------|----------------------------------|------------------------|--------|\r\n * | TypeScript | Optional hooks + instrumented comparator | Zero (JIT optimization) | ✅ Implemented |\r\n * | Go | Nil stats pointer | ~1 cycle (nil check) | Planned v2.5.0 |\r\n * | Rust | Generic over StatsCollector trait | Zero (monomorphization) | Planned v2.5.0 |\r\n * | C++ | Template policy class | Zero (inlining) | Planned v2.5.0 |\r\n * | Zig | Comptime bool parameter | Zero (branch elimination) | Planned v2.5.0 |\r\n *\r\n * ## Usage Example\r\n *\r\n * ```typescript\r\n * import { PriorityQueue, minBy, instrumentComparator } from 'd-ary-heap';\r\n *\r\n * // 1. Wrap your comparator with instrumentation\r\n * const comparator = instrumentComparator(minBy((v: Vertex) => v.distance));\r\n *\r\n * // 2. Create priority queue with operation hooks\r\n * const pq = new PriorityQueue({\r\n * d: 4,\r\n * comparator,\r\n * keyExtractor: (v) => v.id,\r\n * onBeforeOperation: (op) => comparator.startOperation(op),\r\n * onAfterOperation: () => comparator.endOperation(),\r\n * });\r\n *\r\n * // 3. Use normally - comparisons are tracked automatically\r\n * pq.insert({ id: 'A', distance: 0 });\r\n * pq.insert({ id: 'B', distance: 5 });\r\n * pq.pop();\r\n *\r\n * // 4. Access statistics\r\n * console.log(comparator.stats);\r\n * // { insert: 1, pop: 2, decreasePriority: 0, increasePriority: 0, updatePriority: 0, total: 3 }\r\n *\r\n * // 5. Reset for next measurement\r\n * comparator.stats.reset();\r\n * ```\r\n *\r\n * ## Theoretical Complexity Reference\r\n *\r\n * For a d-ary heap with n elements:\r\n *\r\n * | Operation | Comparisons (worst case) |\r\n * |------------------|-------------------------------|\r\n * | insert | ⌊log_d(n)⌋ |\r\n * | pop | d × ⌊log_d(n)⌋ |\r\n * | increasePriority | ⌊log_d(n)⌋ (moveUp only) |\r\n * | decreasePriority | d × ⌊log_d(n)⌋ (moveDown only)|\r\n * | updatePriority | (d+1) × ⌊log_d(n)⌋ (both) |\r\n *\r\n * The demo visualization compares actual counts against these theoretical bounds.\r\n *\r\n * @module instrumentation\r\n * @version 2.4.0\r\n * @license Apache-2.0\r\n */\r\n\r\nimport type { Comparator } from './PriorityQueue';\r\n\r\n/**\r\n * Operation types that can be tracked.\r\n *\r\n * Note: `updatePriority` is tracked separately for when the caller doesn't know\r\n * whether priority increased or decreased (checks both directions).\r\n */\r\nexport type OperationType = 'insert' | 'pop' | 'decreasePriority' | 'increasePriority' | 'updatePriority';\r\n\r\n/**\r\n * Statistics tracking comparison counts per operation type.\r\n *\r\n * All counts start at zero and accumulate until `reset()` is called.\r\n */\r\nexport interface ComparisonStats {\r\n /** Comparisons during insert operations (moveUp) */\r\n insert: number;\r\n\r\n /** Comparisons during pop operations (moveDown + bestChildPosition) */\r\n pop: number;\r\n\r\n /** Comparisons during decreasePriority operations (moveDown only) */\r\n decreasePriority: number;\r\n\r\n /** Comparisons during increasePriority operations (moveUp only) */\r\n increasePriority: number;\r\n\r\n /** Comparisons during updatePriority operations (moveUp + moveDown) */\r\n updatePriority: number;\r\n\r\n /** Total comparisons across all operation types */\r\n readonly total: number;\r\n\r\n /** Reset all counters to zero */\r\n reset(): void;\r\n}\r\n\r\n/**\r\n * An instrumented comparator that tracks comparison counts.\r\n *\r\n * This extends a regular comparator with:\r\n * - `stats`: Current comparison counts\r\n * - `startOperation(type)`: Begin tracking for an operation\r\n * - `endOperation()`: Stop tracking current operation\r\n *\r\n * The comparator itself remains a valid `Comparator<T>` and can be used\r\n * anywhere a regular comparator is expected.\r\n */\r\nexport interface InstrumentedComparator<T> extends Comparator<T> {\r\n /** Current comparison statistics */\r\n readonly stats: ComparisonStats;\r\n\r\n /**\r\n * Signal the start of a heap operation.\r\n * Comparisons will be attributed to this operation type until `endOperation()`.\r\n *\r\n * @param type - The operation type being started\r\n */\r\n startOperation(type: OperationType): void;\r\n\r\n /**\r\n * Signal the end of the current heap operation.\r\n * Subsequent comparisons will not be counted until the next `startOperation()`.\r\n */\r\n endOperation(): void;\r\n}\r\n\r\n/**\r\n * Create comparison statistics tracker.\r\n *\r\n * @returns Fresh stats object with all counts at zero\r\n *\r\n * @example\r\n * ```typescript\r\n * const stats = createComparisonStats();\r\n * stats.insert = 5;\r\n * stats.pop = 10;\r\n * console.log(stats.total); // 15\r\n * stats.reset();\r\n * console.log(stats.total); // 0\r\n * ```\r\n */\r\nexport function createComparisonStats(): ComparisonStats {\r\n const stats: ComparisonStats = {\r\n insert: 0,\r\n pop: 0,\r\n decreasePriority: 0,\r\n increasePriority: 0,\r\n updatePriority: 0,\r\n\r\n get total(): number {\r\n return this.insert + this.pop + this.decreasePriority + this.increasePriority + this.updatePriority;\r\n },\r\n\r\n reset(): void {\r\n this.insert = 0;\r\n this.pop = 0;\r\n this.decreasePriority = 0;\r\n this.increasePriority = 0;\r\n this.updatePriority = 0;\r\n },\r\n };\r\n\r\n return stats;\r\n}\r\n\r\n/**\r\n * Wrap a comparator with instrumentation to track comparison counts.\r\n *\r\n * The returned comparator:\r\n * - Behaves identically to the original for comparison purposes\r\n * - Tracks how many times it's called, attributed to operation types\r\n * - Has zero overhead when `startOperation()` hasn't been called\r\n *\r\n * ## How It Works\r\n *\r\n * 1. Call `startOperation('insert')` before `pq.insert()`\r\n * 2. The comparator increments `stats.insert` for each comparison\r\n * 3. Call `endOperation()` after the operation completes\r\n * 4. Repeat for other operations\r\n *\r\n * The `PriorityQueue` class supports `onBeforeOperation` and `onAfterOperation`\r\n * hooks to automate this.\r\n *\r\n * ## Performance Note\r\n *\r\n * When `currentOperation` is null (between operations), the instrumented\r\n * comparator performs only a single null check before calling the original.\r\n * Modern JavaScript engines optimize this extremely well.\r\n *\r\n * @param comparator - The original comparator to instrument\r\n * @returns An instrumented comparator with stats tracking\r\n *\r\n * @example\r\n * ```typescript\r\n * import { minBy, instrumentComparator } from 'd-ary-heap';\r\n *\r\n * const cmp = instrumentComparator(minBy<number, number>(x => x));\r\n *\r\n * // Manual usage (without hooks)\r\n * cmp.startOperation('insert');\r\n * console.log(cmp(5, 3)); // false, and stats.insert++\r\n * console.log(cmp(3, 5)); // true, and stats.insert++\r\n * cmp.endOperation();\r\n *\r\n * console.log(cmp.stats.insert); // 2\r\n * ```\r\n */\r\nexport function instrumentComparator<T>(comparator: Comparator<T>): InstrumentedComparator<T> {\r\n const stats = createComparisonStats();\r\n let currentOperation: OperationType | null = null;\r\n\r\n // Create the instrumented function\r\n const instrumented = ((a: T, b: T): boolean => {\r\n // Only count when actively tracking an operation\r\n if (currentOperation !== null) {\r\n stats[currentOperation]++;\r\n }\r\n return comparator(a, b);\r\n }) as InstrumentedComparator<T>;\r\n\r\n // Attach stats (read-only from outside)\r\n Object.defineProperty(instrumented, 'stats', {\r\n value: stats,\r\n writable: false,\r\n enumerable: true,\r\n });\r\n\r\n // Attach operation control methods\r\n instrumented.startOperation = (type: OperationType): void => {\r\n currentOperation = type;\r\n };\r\n\r\n instrumented.endOperation = (): void => {\r\n currentOperation = null;\r\n };\r\n\r\n return instrumented;\r\n}\r\n\r\n/**\r\n * Calculate theoretical comparison count for an insert operation.\r\n *\r\n * Insert performs at most ⌊log_d(n)⌋ comparisons (one per level during moveUp).\r\n *\r\n * @param n - Number of elements in heap AFTER insert\r\n * @param d - Heap arity\r\n * @returns Theoretical worst-case comparison count\r\n */\r\nexport function theoreticalInsertComparisons(n: number, d: number): number {\r\n if (n <= 1) return 0;\r\n return Math.floor(Math.log(n) / Math.log(d));\r\n}\r\n\r\n/**\r\n * Calculate theoretical comparison count for a pop operation.\r\n *\r\n * Pop performs at most d × ⌊log_d(n)⌋ comparisons:\r\n * - At each level, find best among d children (d-1 comparisons)\r\n * - Compare best child with current (1 comparison)\r\n * - Total: d comparisons per level × ⌊log_d(n)⌋ levels\r\n *\r\n * @param n - Number of elements in heap BEFORE pop\r\n * @param d - Heap arity\r\n * @returns Theoretical worst-case comparison count\r\n */\r\nexport function theoreticalPopComparisons(n: number, d: number): number {\r\n if (n <= 1) return 0;\r\n const height = Math.floor(Math.log(n) / Math.log(d));\r\n return d * height;\r\n}\r\n\r\n/**\r\n * Calculate theoretical comparison count for an increasePriority operation.\r\n *\r\n * IncreasePriority performs only moveUp (item became more important).\r\n * Worst case: ⌊log_d(n)⌋ comparisons (one per level).\r\n *\r\n * @param n - Number of elements in heap\r\n * @param d - Heap arity\r\n * @returns Theoretical worst-case comparison count\r\n */\r\nexport function theoreticalIncreasePriorityComparisons(n: number, d: number): number {\r\n if (n <= 1) return 0;\r\n return Math.floor(Math.log(n) / Math.log(d));\r\n}\r\n\r\n/**\r\n * Calculate theoretical comparison count for a decreasePriority operation.\r\n *\r\n * DecreasePriority performs only moveDown (item became less important).\r\n * Worst case: d × ⌊log_d(n)⌋ comparisons.\r\n *\r\n * @param n - Number of elements in heap\r\n * @param d - Heap arity\r\n * @returns Theoretical worst-case comparison count\r\n */\r\nexport function theoreticalDecreasePriorityComparisons(n: number, d: number): number {\r\n if (n <= 1) return 0;\r\n const height = Math.floor(Math.log(n) / Math.log(d));\r\n return d * height;\r\n}\r\n\r\n/**\r\n * Calculate theoretical comparison count for an updatePriority operation.\r\n *\r\n * UpdatePriority performs both moveUp and moveDown (direction unknown).\r\n * Worst case: (d + 1) × ⌊log_d(n)⌋ comparisons.\r\n *\r\n * @param n - Number of elements in heap\r\n * @param d - Heap arity\r\n * @returns Theoretical worst-case comparison count\r\n */\r\nexport function theoreticalUpdatePriorityComparisons(n: number, d: number): number {\r\n if (n <= 1) return 0;\r\n const height = Math.floor(Math.log(n) / Math.log(d));\r\n return (d + 1) * height;\r\n}\r\n"]}