@nshiab/simple-data-analysis-core 2.1.6 → 2.1.8

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.
Files changed (75) hide show
  1. package/esm/class/SimpleTable.d.ts +399 -90
  2. package/esm/class/SimpleTable.d.ts.map +1 -1
  3. package/esm/class/SimpleTable.js +393 -90
  4. package/esm/helpers/buildGraphTemporalCostStateSql.d.ts +1 -1
  5. package/esm/helpers/buildGraphTemporalCostStateSql.d.ts.map +1 -1
  6. package/esm/helpers/buildGraphTemporalCostStateSql.js +23 -9
  7. package/esm/helpers/graphRouteResultSchema.d.ts +1 -1
  8. package/esm/helpers/graphRouteResultSchema.d.ts.map +1 -1
  9. package/esm/helpers/graphRouteResultSchema.js +4 -3
  10. package/esm/helpers/graphRouteResultSelect.d.ts +1 -1
  11. package/esm/helpers/graphRouteResultSelect.d.ts.map +1 -1
  12. package/esm/helpers/graphRouteResultSelect.js +5 -2
  13. package/esm/helpers/prepareGraphMetricOptions.d.ts +14 -0
  14. package/esm/helpers/prepareGraphMetricOptions.d.ts.map +1 -0
  15. package/esm/helpers/prepareGraphMetricOptions.js +41 -0
  16. package/esm/helpers/prepareGraphRouteSql.d.ts +2 -2
  17. package/esm/helpers/prepareGraphRouteSql.d.ts.map +1 -1
  18. package/esm/helpers/prepareGraphRouteSql.js +4 -4
  19. package/esm/helpers/prepareGraphTemporalSql.d.ts +3 -0
  20. package/esm/helpers/prepareGraphTemporalSql.d.ts.map +1 -1
  21. package/esm/helpers/prepareGraphTemporalSql.js +7 -0
  22. package/esm/helpers/validateGraphRouteResultSchema.d.ts +1 -1
  23. package/esm/helpers/validateGraphRouteResultSchema.d.ts.map +1 -1
  24. package/esm/helpers/validateGraphRouteResultSchema.js +3 -1
  25. package/esm/methods/distances.d.ts +2 -0
  26. package/esm/methods/distances.d.ts.map +1 -1
  27. package/esm/methods/distances.js +274 -20
  28. package/esm/methods/findCycles.d.ts +1 -0
  29. package/esm/methods/findCycles.d.ts.map +1 -1
  30. package/esm/methods/findCycles.js +22 -15
  31. package/esm/methods/paths.d.ts +1 -0
  32. package/esm/methods/paths.d.ts.map +1 -1
  33. package/esm/methods/paths.js +21 -14
  34. package/esm/methods/shortestPath.d.ts +2 -0
  35. package/esm/methods/shortestPath.d.ts.map +1 -1
  36. package/esm/methods/shortestPath.js +155 -34
  37. package/llm.md +428 -108
  38. package/llms.txt +1 -1
  39. package/package.json +1 -1
  40. package/script/class/SimpleTable.d.ts +399 -90
  41. package/script/class/SimpleTable.d.ts.map +1 -1
  42. package/script/class/SimpleTable.js +393 -90
  43. package/script/helpers/buildGraphTemporalCostStateSql.d.ts +1 -1
  44. package/script/helpers/buildGraphTemporalCostStateSql.d.ts.map +1 -1
  45. package/script/helpers/buildGraphTemporalCostStateSql.js +23 -9
  46. package/script/helpers/graphRouteResultSchema.d.ts +1 -1
  47. package/script/helpers/graphRouteResultSchema.d.ts.map +1 -1
  48. package/script/helpers/graphRouteResultSchema.js +4 -3
  49. package/script/helpers/graphRouteResultSelect.d.ts +1 -1
  50. package/script/helpers/graphRouteResultSelect.d.ts.map +1 -1
  51. package/script/helpers/graphRouteResultSelect.js +5 -2
  52. package/script/helpers/prepareGraphMetricOptions.d.ts +14 -0
  53. package/script/helpers/prepareGraphMetricOptions.d.ts.map +1 -0
  54. package/script/helpers/prepareGraphMetricOptions.js +44 -0
  55. package/script/helpers/prepareGraphRouteSql.d.ts +2 -2
  56. package/script/helpers/prepareGraphRouteSql.d.ts.map +1 -1
  57. package/script/helpers/prepareGraphRouteSql.js +4 -4
  58. package/script/helpers/prepareGraphTemporalSql.d.ts +3 -0
  59. package/script/helpers/prepareGraphTemporalSql.d.ts.map +1 -1
  60. package/script/helpers/prepareGraphTemporalSql.js +7 -0
  61. package/script/helpers/validateGraphRouteResultSchema.d.ts +1 -1
  62. package/script/helpers/validateGraphRouteResultSchema.d.ts.map +1 -1
  63. package/script/helpers/validateGraphRouteResultSchema.js +3 -1
  64. package/script/methods/distances.d.ts +2 -0
  65. package/script/methods/distances.d.ts.map +1 -1
  66. package/script/methods/distances.js +274 -20
  67. package/script/methods/findCycles.d.ts +1 -0
  68. package/script/methods/findCycles.d.ts.map +1 -1
  69. package/script/methods/findCycles.js +22 -15
  70. package/script/methods/paths.d.ts +1 -0
  71. package/script/methods/paths.d.ts.map +1 -1
  72. package/script/methods/paths.js +21 -14
  73. package/script/methods/shortestPath.d.ts +2 -0
  74. package/script/methods/shortestPath.d.ts.map +1 -1
  75. package/script/methods/shortestPath.js +155 -34
@@ -2633,42 +2633,24 @@ export default class SimpleTable extends Simple {
2633
2633
  outputTable?: string | boolean;
2634
2634
  }): SimpleTable;
2635
2635
  /**
2636
- * Finds the shortest distance from each starting node to every node it can
2637
- * reach by following one or more connections. By default, distance is the
2638
- * number of connections along the shortest route. Use the `weight` option
2639
- * to find the smallest sum of values from a numeric column, such as travel
2640
- * time.
2636
+ * Finds the shortest routes from each starting node to every reachable
2637
+ * node. Without options, shortest means the fewest connections. Use `weight`
2638
+ * to report total cost and `elapsedTime` to report duration including waiting
2639
+ * between connections. Use `minimize` to choose which metric defines shortest.
2641
2640
  *
2642
- * The `direction` option lets you follow connections from source to target,
2643
- * from target to source, or in either direction. The result has `start`,
2644
- * `node`, and `distance` columns, sorted by `start`, then by increasing
2645
- * `distance`, then by `node` to break ties. The closest nodes appear first
2646
- * for each start.
2647
- *
2648
- * Each row gives the shortest distance from `start` to `node`. Intermediate
2649
- * steps along the route are not returned. To get the steps between two
2650
- * different nodes, use `shortestPath()` for the shortest routes or `paths()`
2651
- * for all routes without repeated nodes.
2641
+ * Each row contains `start`, `node`, and `steps`, plus `total` when `weight`
2642
+ * is supplied and `elapsedTimeMs` when enabled. Routes tied on the chosen
2643
+ * metric produce separate rows only when their reported summaries differ;
2644
+ * identical summaries appear once.
2652
2645
  *
2653
- * A starting node appears in its own results only when a self-connection
2654
- * or a route leads back to it. Its distance is the shortest actual return
2655
- * route, using at least one connection. With `direction: "both"`, this
2656
- * can mean following the same connection out and back.
2646
+ * Routes cannot repeat nodes except for a final return to the start. A start
2647
+ * appears in its own results only through an actual return or self-connection,
2648
+ * never with zero steps. With `direction: "both"`, a return can follow the
2649
+ * same connection out and back. Use `shortestPath()` to inspect individual
2650
+ * connections between two different nodes.
2657
2651
  *
2658
- * Unknown starting IDs and starts with no connections to follow produce
2659
- * no rows. Empty start arrays and duplicate starting IDs throw an error.
2660
- * Weights must be non-null, finite, and non-negative.
2661
- *
2662
- * Use the `startTimeColumn` or `endTimeColumn` options to follow connections
2663
- * in chronological order. The `minGapMs` option sets the minimum gap between
2664
- * consecutive connections, in milliseconds. With both time columns, gaps are
2665
- * measured from one connection's end to the next connection's start; with one
2666
- * column, between their timestamps. The `strictOrdering` option defaults to
2667
- * `true`, rejecting zero-duration gaps. These options only work with
2668
- * `direction: "outgoing"` or `direction: "incoming"`.
2669
- *
2670
- * The minimum gap applies only between consecutive connections, not before
2671
- * the first connection.
2652
+ * Reporting weight or elapsed time can require substantial time and memory
2653
+ * on dense networks because many routes may need to be explored.
2672
2654
  *
2673
2655
  * The next five examples each start with this data:
2674
2656
  *
@@ -2688,12 +2670,12 @@ export default class SimpleTable extends Simple {
2688
2670
  * .log();
2689
2671
  * ```
2690
2672
  *
2691
- * | start | node | distance |
2673
+ * | start | node | steps |
2692
2674
  * | --- | --- | ---: |
2693
2675
  * | A | B | 1 |
2694
2676
  * | A | C | 2 |
2695
2677
  *
2696
- * With `weight: "minutes"`, distance is the shortest total travel time:
2678
+ * With `weight: "minutes"`, `total` is the sum of travel times:
2697
2679
  *
2698
2680
  * @example
2699
2681
  * ```ts
@@ -2702,10 +2684,10 @@ export default class SimpleTable extends Simple {
2702
2684
  * .log();
2703
2685
  * ```
2704
2686
  *
2705
- * | start | node | distance |
2706
- * | --- | --- | ---: |
2707
- * | A | B | 4 |
2708
- * | A | C | 5 |
2687
+ * | start | node | steps | total |
2688
+ * | --- | --- | ---: | ---: |
2689
+ * | A | B | 1 | 4 |
2690
+ * | A | C | 2 | 5 |
2709
2691
  *
2710
2692
  * With `direction: "incoming"`, connections are followed from target to
2711
2693
  * source. Starting at C:
@@ -2717,7 +2699,7 @@ export default class SimpleTable extends Simple {
2717
2699
  * .log();
2718
2700
  * ```
2719
2701
  *
2720
- * | start | node | distance |
2702
+ * | start | node | steps |
2721
2703
  * | --- | --- | ---: |
2722
2704
  * | C | B | 1 |
2723
2705
  * | C | A | 2 |
@@ -2733,14 +2715,14 @@ export default class SimpleTable extends Simple {
2733
2715
  * .log();
2734
2716
  * ```
2735
2717
  *
2736
- * | start | node | distance |
2718
+ * | start | node | steps |
2737
2719
  * | --- | --- | ---: |
2738
2720
  * | A | B | 1 |
2739
2721
  * | A | A | 2 |
2740
2722
  * | A | C | 2 |
2741
2723
  * | A | D | 2 |
2742
2724
  *
2743
- * A appears at distance 2 because A → B → A follows a connection out
2725
+ * A appears with 2 steps because A → B → A follows a connection out
2744
2726
  * and back.
2745
2727
  *
2746
2728
  * An array of starting nodes gives separate distances for each start:
@@ -2754,12 +2736,12 @@ export default class SimpleTable extends Simple {
2754
2736
  * .log();
2755
2737
  * ```
2756
2738
  *
2757
- * | start | node | distance |
2758
- * | --- | --- | ---: |
2759
- * | A | B | 4 |
2760
- * | A | C | 5 |
2761
- * | D | B | 2 |
2762
- * | D | C | 3 |
2739
+ * | start | node | steps | total |
2740
+ * | --- | --- | ---: | ---: |
2741
+ * | A | B | 1 | 4 |
2742
+ * | A | C | 2 | 5 |
2743
+ * | D | B | 1 | 2 |
2744
+ * | D | C | 2 | 3 |
2763
2745
  *
2764
2746
  * A direct self-connection and a longer return route can both lead back
2765
2747
  * to the start. This example uses different data:
@@ -2780,13 +2762,13 @@ export default class SimpleTable extends Simple {
2780
2762
  * .log();
2781
2763
  * ```
2782
2764
  *
2783
- * | start | node | distance |
2784
- * | --- | --- | ---: |
2785
- * | A | B | 2 |
2786
- * | A | A | 5 |
2765
+ * | start | node | steps | total |
2766
+ * | --- | --- | ---: | ---: |
2767
+ * | A | B | 1 | 2 |
2768
+ * | A | A | 2 | 5 |
2787
2769
  *
2788
2770
  * Chronological options can rule out a cheaper sequence that departs too
2789
- * early. For this example, F2 leaves before F1 arrives, while F3 meets the
2771
+ * early. Here, B → C leaves before A → B arrives, while B → D meets the
2790
2772
  * one-hour minimum exactly:
2791
2773
  *
2792
2774
  * | origin | destination | departureTime | arrivalTime | minutes |
@@ -2807,29 +2789,155 @@ export default class SimpleTable extends Simple {
2807
2789
  * .log();
2808
2790
  * ```
2809
2791
  *
2810
- * | start | node | distance |
2811
- * | --- | --- | ---: |
2812
- * | A | B | 2 |
2813
- * | A | D | 5 |
2792
+ * | start | node | steps | total |
2793
+ * | --- | --- | ---: | ---: |
2794
+ * | A | B | 1 | 2 |
2795
+ * | A | D | 2 | 5 |
2796
+ *
2797
+ * For the next four examples, `flights` contains these rows, with departure
2798
+ * and arrival stored as timestamps on the same day:
2799
+ *
2800
+ * | flightId | origin | destination | departure | arrival | price |
2801
+ * | --- | --- | --- | --- | --- | ---: |
2802
+ * | F1 | A | B | 2025-01-01 09:00 | 2025-01-01 10:00 | 40 |
2803
+ * | F2 | B | C | 2025-01-01 12:00 | 2025-01-01 13:00 | 40 |
2804
+ * | F3 | A | C | 2025-01-01 09:00 | 2025-01-01 12:00 | 120 |
2805
+ *
2806
+ * Find the fastest journey from A to each reachable destination, including
2807
+ * layovers:
2808
+ *
2809
+ * @example
2810
+ * ```ts
2811
+ * await flights
2812
+ * .distances("origin", "destination", "A", {
2813
+ * startTimeColumn: "departure",
2814
+ * endTimeColumn: "arrival",
2815
+ * minGapMs: 60 * 60 * 1000,
2816
+ * elapsedTime: true,
2817
+ * })
2818
+ * .log();
2819
+ * ```
2820
+ *
2821
+ * | start | node | steps | elapsedTimeMs |
2822
+ * | --- | --- | ---: | ---: |
2823
+ * | A | B | 1 | 3600000 |
2824
+ * | A | C | 1 | 10800000 |
2825
+ *
2826
+ * The direct flight to C takes three hours (10,800,000 milliseconds).
2827
+ * The route through B takes four hours including its layover.
2828
+ *
2829
+ * Find the fastest journeys from A while also adding up their prices:
2830
+ *
2831
+ * @example
2832
+ * ```ts
2833
+ * await flights
2834
+ * .distances("origin", "destination", "A", {
2835
+ * startTimeColumn: "departure",
2836
+ * endTimeColumn: "arrival",
2837
+ * minGapMs: 60 * 60 * 1000,
2838
+ * elapsedTime: true,
2839
+ * weight: "price",
2840
+ * minimize: "elapsedTime",
2841
+ * })
2842
+ * .log();
2843
+ * ```
2844
+ *
2845
+ * | start | node | steps | total | elapsedTimeMs |
2846
+ * | --- | --- | ---: | ---: | ---: |
2847
+ * | A | B | 1 | 40 | 3600000 |
2848
+ * | A | C | 1 | 120 | 10800000 |
2849
+ *
2850
+ * Use `minimize: "weight"` to find the cheapest journeys instead. The
2851
+ * selected route to C now takes two steps through B and costs 80:
2852
+ *
2853
+ * @example
2854
+ * ```ts
2855
+ * await flights
2856
+ * .distances("origin", "destination", "A", {
2857
+ * startTimeColumn: "departure",
2858
+ * endTimeColumn: "arrival",
2859
+ * minGapMs: 60 * 60 * 1000,
2860
+ * elapsedTime: true,
2861
+ * weight: "price",
2862
+ * minimize: "weight",
2863
+ * })
2864
+ * .log();
2865
+ * ```
2866
+ *
2867
+ * | start | node | steps | total | elapsedTimeMs |
2868
+ * | --- | --- | ---: | ---: | ---: |
2869
+ * | A | B | 1 | 40 | 3600000 |
2870
+ * | A | C | 2 | 80 | 14400000 |
2871
+ *
2872
+ * Choose the fewest connections while still reporting price and elapsed
2873
+ * time. The direct flight to C has one step, even though it costs more:
2874
+ *
2875
+ * @example
2876
+ * ```ts
2877
+ * await flights
2878
+ * .distances("origin", "destination", "A", {
2879
+ * startTimeColumn: "departure",
2880
+ * endTimeColumn: "arrival",
2881
+ * minGapMs: 60 * 60 * 1000,
2882
+ * elapsedTime: true,
2883
+ * weight: "price",
2884
+ * minimize: "steps",
2885
+ * })
2886
+ * .log();
2887
+ * ```
2888
+ *
2889
+ * | start | node | steps | total | elapsedTimeMs |
2890
+ * | --- | --- | ---: | ---: | ---: |
2891
+ * | A | B | 1 | 40 | 3600000 |
2892
+ * | A | C | 1 | 120 | 10800000 |
2893
+ *
2894
+ * When two routes to C both take two steps but have different prices,
2895
+ * minimizing steps while reporting price returns both summaries:
2896
+ *
2897
+ * @example
2898
+ * ```ts
2899
+ * await connections
2900
+ * .loadArray([
2901
+ * { origin: "A", destination: "B", price: 20 },
2902
+ * { origin: "B", destination: "C", price: 30 },
2903
+ * { origin: "A", destination: "D", price: 40 },
2904
+ * { origin: "D", destination: "C", price: 40 },
2905
+ * ])
2906
+ * .distances("origin", "destination", "A", {
2907
+ * weight: "price",
2908
+ * minimize: "steps",
2909
+ * })
2910
+ * .filter("node = 'C'")
2911
+ * .log();
2912
+ * ```
2913
+ *
2914
+ * | start | node | steps | total |
2915
+ * | --- | --- | ---: | ---: |
2916
+ * | A | C | 2 | 50 |
2917
+ * | A | C | 2 | 80 |
2814
2918
  *
2815
2919
  * @param sourceColumn - The name of the column containing each connection's source node ID.
2816
2920
  * @param targetColumn - The name of the column containing each connection's target node ID.
2817
- * @param startNodes - One starting node ID or an array of distinct starting node IDs.
2921
+ * @param startNodes - One starting node ID or a non-empty array of distinct IDs. Unknown IDs and starts with no connections to follow produce no rows. Empty arrays and duplicate IDs throw an error.
2818
2922
  * @param options - An optional object with direction, time, and result configuration.
2819
- * @param options.direction - The direction in which to follow connections. Defaults to `"outgoing"`.
2923
+ * @param options.direction - The direction in which to follow connections. Defaults to `"outgoing"`. Chronological traversal supports only `"outgoing"` and `"incoming"`.
2820
2924
  * @param options.startTimeColumn - The name of the column containing each connection's start time. Use this or `endTimeColumn` to follow connections in chronological order.
2821
2925
  * @param options.endTimeColumn - The name of the column containing each connection's end time. Use this or `startTimeColumn` to follow connections in chronological order.
2822
- * @param options.minGapMs - The minimum gap between consecutive connections, in milliseconds. Must be a non-negative integer. Defaults to `0`. Requires a time column.
2926
+ * @param options.minGapMs - The minimum gap between consecutive connections, in milliseconds; does not apply before the first connection. With both time columns, measured from one connection's end to the next's start; with one column, between timestamps. Must be a non-negative integer. Defaults to `0`. Requires a time column.
2823
2927
  * @param options.strictOrdering - Whether to reject zero-duration gaps between consecutive connections (equal timestamps). Defaults to `true`. Requires a time column.
2824
- * @param options.weight - The name of the numeric column used as the cost of each connection. If omitted, each connection costs one.
2928
+ * @param options.weight - The name of the numeric column used as the cost of each connection. Values must be non-null, finite, and non-negative. Adds `total`, the cumulative sum of those costs. If omitted, no `total` column is generated.
2929
+ * @param options.elapsedTime - Whether to add cumulative `elapsedTimeMs` in milliseconds, including connection gaps. Defaults to `false`. Requires both time columns. Optimization compares native timestamp precision before conversion to milliseconds.
2930
+ * @param options.minimize - The metric used to select optimal routes: `"steps"`, `"weight"`, or `"elapsedTime"`. Defaults to `"weight"` when only `weight` is enabled, `"elapsedTime"` when only elapsed-time reporting is enabled, and `"steps"` when neither is enabled. Required when both are enabled. `"steps"` is always available; the other metrics require their corresponding options.
2825
2931
  * @param options.outputTable - If `true`, stores the result in a new table with a generated name. If a string, uses it as the new table's name. If `false` or omitted, overwrites the current table. Defaults to `false`.
2826
- * @returns The result table, so methods can be chained.
2932
+ * @returns The table of distinct optimal summaries with `start`, `node`, and `steps`, plus `total` when `weight` is supplied and `elapsedTimeMs` when enabled, so methods can be chained. Sorted by start, the chosen metric, node, then remaining metrics in the order steps, total, elapsed time.
2827
2933
  * @category Graph Operations
2828
2934
  */
2829
2935
  distances(sourceColumn: string, targetColumn: string, startNodes: string | number | bigint | (string | number | bigint)[], options?: {
2830
2936
  direction?: "outgoing" | "incoming" | "both";
2937
+ elapsedTime?: boolean;
2831
2938
  endTimeColumn?: string;
2832
2939
  minGapMs?: number;
2940
+ minimize?: "steps" | "weight" | "elapsedTime";
2833
2941
  outputTable?: string | boolean;
2834
2942
  startTimeColumn?: string;
2835
2943
  strictOrdering?: boolean;
@@ -2850,15 +2958,17 @@ export default class SimpleTable extends Simple {
2850
2958
  * containing these IDs as the `edgeId` argument. If your table is missing
2851
2959
  * an ID column, you can easily create one with `addId()`.
2852
2960
  *
2853
- * The result starts with the `pathId`, `step`, `weight`, and `total`
2854
- * columns, followed by all original columns. Steps start at one and follow
2855
- * the search direction. The `weight` column is the connection cost, and
2856
- * `total` is the sum of those costs up to and including the current step.
2857
- * Without the `weight` option, each connection costs one.
2961
+ * The result starts with `pathId`, `step`, and `weight`, followed by the
2962
+ * optional metric columns and all original columns. Steps start at one and
2963
+ * follow the search direction. The `weight` column is the connection cost,
2964
+ * or one when no `weight` option is supplied. Supplying `weight` also adds
2965
+ * `total`, the sum of those costs up to and including the current step.
2966
+ * Enabling `elapsedTime` adds cumulative `elapsedTimeMs`, including gaps.
2858
2967
  *
2859
- * If an input column is already named `pathId`, `step`, `weight`, or `total`
2860
- * (regardless of capitalization), the method throws an error. Rename it
2861
- * with `renameColumns()` first.
2968
+ * If an input column conflicts with a generated result column (regardless
2969
+ * of capitalization), the method throws an error. Rename it with
2970
+ * `renameColumns()` first. `total` is reserved only when `weight` is supplied,
2971
+ * and `elapsedTimeMs` only when elapsed-time reporting is enabled.
2862
2972
  *
2863
2973
  * Each row is one connection along a route.
2864
2974
  *
@@ -2873,6 +2983,16 @@ export default class SimpleTable extends Simple {
2873
2983
  * The minimum gap applies only between consecutive connections, not before
2874
2984
  * the first connection.
2875
2985
  *
2986
+ * Use `minimize: "steps"` to choose the fewest connections even when weight
2987
+ * or elapsed-time reporting is enabled. Without an explicit `minimize`, the
2988
+ * method minimizes weight when only `weight` is enabled, elapsed time when
2989
+ * only `elapsedTime` is enabled, and steps when neither is enabled. With
2990
+ * both enabled, specify `"steps"`, `"weight"`, or `"elapsedTime"` explicitly.
2991
+ * Elapsed-time reporting requires both time columns.
2992
+ *
2993
+ * All routes tied on the selected metric are returned, even if their other
2994
+ * metrics differ. Each route reports its own weights and elapsed times.
2995
+ *
2876
2996
  * Routes are numbered from zero by comparing their sequences of connection
2877
2997
  * IDs, element by element. Rows are sorted by `pathId`, then `step`.
2878
2998
  *
@@ -2903,14 +3023,14 @@ export default class SimpleTable extends Simple {
2903
3023
  * .log();
2904
3024
  * ```
2905
3025
  *
2906
- * | pathId | step | weight | total | edgeId | source | target |
2907
- * | ---: | ---: | ---: | ---: | --- | --- | --- |
2908
- * | 0 | 1 | 1 | 1 | E1 | A | B |
2909
- * | 0 | 2 | 1 | 2 | E3 | B | D |
2910
- * | 0 | 3 | 1 | 3 | E5 | D | E |
2911
- * | 1 | 1 | 1 | 1 | E2 | A | C |
2912
- * | 1 | 2 | 1 | 2 | E4 | C | D |
2913
- * | 1 | 3 | 1 | 3 | E5 | D | E |
3026
+ * | pathId | step | weight | edgeId | source | target |
3027
+ * | ---: | ---: | ---: | --- | --- | --- |
3028
+ * | 0 | 1 | 1 | E1 | A | B |
3029
+ * | 0 | 2 | 1 | E3 | B | D |
3030
+ * | 0 | 3 | 1 | E5 | D | E |
3031
+ * | 1 | 1 | 1 | E2 | A | C |
3032
+ * | 1 | 2 | 1 | E4 | C | D |
3033
+ * | 1 | 3 | 1 | E5 | D | E |
2914
3034
  *
2915
3035
  * For an input without connection IDs, use `addId()` first:
2916
3036
  *
@@ -2929,10 +3049,10 @@ export default class SimpleTable extends Simple {
2929
3049
  * .log();
2930
3050
  * ```
2931
3051
  *
2932
- * | pathId | step | weight | total | source | target | edgeId |
2933
- * | ---: | ---: | ---: | ---: | --- | --- | --- |
2934
- * | 0 | 1 | 1 | 1 | A | B | edge-0 |
2935
- * | 0 | 2 | 1 | 2 | B | E | edge-1 |
3052
+ * | pathId | step | weight | source | target | edgeId |
3053
+ * | ---: | ---: | ---: | --- | --- | --- |
3054
+ * | 0 | 1 | 1 | A | B | edge-0 |
3055
+ * | 0 | 2 | 1 | B | E | edge-1 |
2936
3056
  *
2937
3057
  * The next two examples each start with these flights. The direct flight
2938
3058
  * takes ten minutes; the route through B and D takes three:
@@ -2972,9 +3092,9 @@ export default class SimpleTable extends Simple {
2972
3092
  * .log();
2973
3093
  * ```
2974
3094
  *
2975
- * | pathId | step | weight | total | flightId | origin | destination | minutes |
2976
- * | ---: | ---: | ---: | ---: | --- | --- | --- | ---: |
2977
- * | 0 | 1 | 1 | 1 | F1 | A | E | 10 |
3095
+ * | pathId | step | weight | flightId | origin | destination | minutes |
3096
+ * | ---: | ---: | ---: | --- | --- | --- | ---: |
3097
+ * | 0 | 1 | 1 | F1 | A | E | 10 |
2978
3098
  *
2979
3099
  * With time options, the cheaper route through B is ruled out because F2
2980
3100
  * leaves before F1 arrives. The route through C meets the one-hour minimum
@@ -3021,9 +3141,87 @@ export default class SimpleTable extends Simple {
3021
3141
  * .log();
3022
3142
  * ```
3023
3143
  *
3024
- * | pathId | step | weight | total | edgeId | source | target |
3025
- * | ---: | ---: | ---: | ---: | --- | --- | --- |
3026
- * | 0 | 1 | 1 | 1 | F1 | A | B |
3144
+ * | pathId | step | weight | edgeId | source | target |
3145
+ * | ---: | ---: | ---: | --- | --- | --- |
3146
+ * | 0 | 1 | 1 | F1 | A | B |
3147
+ *
3148
+ * For the next three examples, `flights` contains these rows, with departure
3149
+ * and arrival stored as timestamps on the same day:
3150
+ *
3151
+ * | flightId | origin | destination | departure | arrival | price |
3152
+ * | --- | --- | --- | --- | --- | ---: |
3153
+ * | F1 | A | B | 2025-01-01 09:00 | 2025-01-01 10:00 | 40 |
3154
+ * | F2 | B | C | 2025-01-01 12:00 | 2025-01-01 13:00 | 40 |
3155
+ * | F3 | A | C | 2025-01-01 09:00 | 2025-01-01 12:00 | 120 |
3156
+ * | F4 | A | D | 2025-01-01 09:00 | 2025-01-01 09:30 | 60 |
3157
+ * | F5 | D | C | 2025-01-01 10:30 | 2025-01-01 11:00 | 80 |
3158
+ *
3159
+ * Find the fastest journey from A to C, including layovers:
3160
+ *
3161
+ * @example
3162
+ * ```ts
3163
+ * await flights
3164
+ * .shortestPath("origin", "destination", "flightId", "A", "C", {
3165
+ * startTimeColumn: "departure",
3166
+ * endTimeColumn: "arrival",
3167
+ * minGapMs: 60 * 60 * 1000,
3168
+ * elapsedTime: true,
3169
+ * })
3170
+ * .log();
3171
+ * ```
3172
+ *
3173
+ * | pathId | step | weight | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
3174
+ * | ---: | ---: | ---: | ---: | --- | --- | --- | --- | --- | ---: |
3175
+ * | 0 | 1 | 1 | 1800000 | F4 | A | D | 2025-01-01 09:00:00 | 2025-01-01 09:30:00 | 60 |
3176
+ * | 0 | 2 | 1 | 7200000 | F5 | D | C | 2025-01-01 10:30:00 | 2025-01-01 11:00:00 | 80 |
3177
+ *
3178
+ * The route through D takes two hours (7,200,000 milliseconds), including
3179
+ * a one-hour layover. The direct flight takes three hours.
3180
+ *
3181
+ * Find the fastest journey while also adding up its price:
3182
+ *
3183
+ * @example
3184
+ * ```ts
3185
+ * await flights
3186
+ * .shortestPath("origin", "destination", "flightId", "A", "C", {
3187
+ * startTimeColumn: "departure",
3188
+ * endTimeColumn: "arrival",
3189
+ * minGapMs: 60 * 60 * 1000,
3190
+ * elapsedTime: true,
3191
+ * weight: "price",
3192
+ * minimize: "elapsedTime",
3193
+ * })
3194
+ * .log();
3195
+ * ```
3196
+ *
3197
+ * | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
3198
+ * | ---: | ---: | ---: | ---: | ---: | --- | --- | --- | --- | --- | ---: |
3199
+ * | 0 | 1 | 60 | 60 | 1800000 | F4 | A | D | 2025-01-01 09:00:00 | 2025-01-01 09:30:00 | 60 |
3200
+ * | 0 | 2 | 80 | 140 | 7200000 | F5 | D | C | 2025-01-01 10:30:00 | 2025-01-01 11:00:00 | 80 |
3201
+ *
3202
+ * Use `minimize: "weight"` to find the cheapest journey instead.
3203
+ * All ties on the chosen metric are returned.
3204
+ *
3205
+ * Choose the fewest flights while still reporting price and elapsed time.
3206
+ * The direct flight takes one step, although the route through D is faster:
3207
+ *
3208
+ * @example
3209
+ * ```ts
3210
+ * await flights
3211
+ * .shortestPath("origin", "destination", "flightId", "A", "C", {
3212
+ * startTimeColumn: "departure",
3213
+ * endTimeColumn: "arrival",
3214
+ * minGapMs: 60 * 60 * 1000,
3215
+ * elapsedTime: true,
3216
+ * weight: "price",
3217
+ * minimize: "steps",
3218
+ * })
3219
+ * .log();
3220
+ * ```
3221
+ *
3222
+ * | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
3223
+ * | ---: | ---: | ---: | ---: | ---: | --- | --- | --- | --- | --- | ---: |
3224
+ * | 0 | 1 | 120 | 120 | 10800000 | F3 | A | C | 2025-01-01 09:00:00 | 2025-01-01 12:00:00 | 120 |
3027
3225
  *
3028
3226
  * @param sourceColumn - The name of the column containing each connection's source node ID.
3029
3227
  * @param targetColumn - The name of the column containing each connection's target node ID.
@@ -3036,15 +3234,19 @@ export default class SimpleTable extends Simple {
3036
3234
  * @param options.endTimeColumn - The name of the column containing each connection's end time. Use this or `startTimeColumn` to follow connections in chronological order.
3037
3235
  * @param options.minGapMs - The minimum gap between consecutive connections, in milliseconds. Must be a non-negative integer. Defaults to `0`. Requires a time column.
3038
3236
  * @param options.strictOrdering - Whether to reject zero-duration gaps between consecutive connections (equal timestamps). Defaults to `true`. Requires a time column.
3039
- * @param options.weight - The name of the numeric column used as the cost of each connection. If omitted, each connection costs one.
3237
+ * @param options.weight - The name of the numeric column used as the cost of each connection. Adds `total`, the cumulative sum of those costs. If omitted, no `total` column is generated.
3238
+ * @param options.elapsedTime - Whether to add cumulative `elapsedTimeMs` in milliseconds, including connection gaps. Defaults to `false`. Requires both time columns.
3239
+ * @param options.minimize - The metric used to select optimal routes: `"steps"`, `"weight"`, or `"elapsedTime"`. Defaults to `"weight"` when only `weight` is enabled, `"elapsedTime"` when only elapsed-time reporting is enabled, and `"steps"` when neither is enabled. Required when both are enabled. `"steps"` is always available; the other metrics require their corresponding options.
3040
3240
  * @param options.outputTable - If `true`, stores the result in a new table with a generated name. If a string, uses it as the new table's name. If `false` or omitted, overwrites the current table. Defaults to `false`.
3041
- * @returns The result table, so methods can be chained.
3241
+ * @returns The table of route connections with optional cumulative `total` and `elapsedTimeMs` metrics, so methods can be chained.
3042
3242
  * @category Graph Operations
3043
3243
  */
3044
3244
  shortestPath(sourceColumn: string, targetColumn: string, edgeId: string, start: string | number | bigint, end: string | number | bigint, options?: {
3045
3245
  direction?: "outgoing" | "incoming" | "both";
3246
+ elapsedTime?: boolean;
3046
3247
  endTimeColumn?: string;
3047
3248
  minGapMs?: number;
3249
+ minimize?: "steps" | "weight" | "elapsedTime";
3048
3250
  outputTable?: string | boolean;
3049
3251
  startTimeColumn?: string;
3050
3252
  strictOrdering?: boolean;
@@ -3256,6 +3458,59 @@ export default class SimpleTable extends Simple {
3256
3458
  * | 0 | 1 | 3 | 3 | F3 | B | D | 2025-01-01 11:00:00 | 2025-01-01 12:00:00 | 3 |
3257
3459
  * | 0 | 2 | 2 | 5 | F1 | A | B | 2025-01-01 08:00:00 | 2025-01-01 10:00:00 | 2 |
3258
3460
  *
3461
+ * For the next two examples, `flights` contains these rows, with departure
3462
+ * and arrival stored as timestamps on the same day:
3463
+ *
3464
+ * | flightId | origin | destination | departure | arrival | price |
3465
+ * | --- | --- | --- | --- | --- | ---: |
3466
+ * | F1 | A | B | 2025-01-01 09:00 | 2025-01-01 10:00 | 40 |
3467
+ * | F2 | B | C | 2025-01-01 12:00 | 2025-01-01 13:00 | 40 |
3468
+ * | F3 | A | C | 2025-01-01 09:00 | 2025-01-01 12:00 | 120 |
3469
+ *
3470
+ * Report elapsed time for every path, including layovers:
3471
+ *
3472
+ * @example
3473
+ * ```ts
3474
+ * await flights
3475
+ * .paths("origin", "destination", "flightId", "A", "C", {
3476
+ * startTimeColumn: "departure",
3477
+ * endTimeColumn: "arrival",
3478
+ * minGapMs: 60 * 60 * 1000,
3479
+ * elapsedTime: true,
3480
+ * })
3481
+ * .log();
3482
+ * ```
3483
+ *
3484
+ * | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
3485
+ * | ---: | ---: | ---: | ---: | ---: | --- | --- | --- | --- | --- | ---: |
3486
+ * | 0 | 1 | 1 | 1 | 3600000 | F1 | A | B | 2025-01-01 09:00:00 | 2025-01-01 10:00:00 | 40 |
3487
+ * | 0 | 2 | 1 | 2 | 14400000 | F2 | B | C | 2025-01-01 12:00:00 | 2025-01-01 13:00:00 | 40 |
3488
+ * | 1 | 1 | 1 | 1 | 10800000 | F3 | A | C | 2025-01-01 09:00:00 | 2025-01-01 12:00:00 | 120 |
3489
+ *
3490
+ * The route through B takes four hours (14,400,000 milliseconds),
3491
+ * including its two-hour layover. The direct flight takes three hours.
3492
+ *
3493
+ * Add up prices while continuing to report elapsed time for every path:
3494
+ *
3495
+ * @example
3496
+ * ```ts
3497
+ * await flights
3498
+ * .paths("origin", "destination", "flightId", "A", "C", {
3499
+ * startTimeColumn: "departure",
3500
+ * endTimeColumn: "arrival",
3501
+ * minGapMs: 60 * 60 * 1000,
3502
+ * elapsedTime: true,
3503
+ * weight: "price",
3504
+ * })
3505
+ * .log();
3506
+ * ```
3507
+ *
3508
+ * | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
3509
+ * | ---: | ---: | ---: | ---: | ---: | --- | --- | --- | --- | --- | ---: |
3510
+ * | 0 | 1 | 40 | 40 | 3600000 | F1 | A | B | 2025-01-01 09:00:00 | 2025-01-01 10:00:00 | 40 |
3511
+ * | 0 | 2 | 40 | 80 | 14400000 | F2 | B | C | 2025-01-01 12:00:00 | 2025-01-01 13:00:00 | 40 |
3512
+ * | 1 | 1 | 120 | 120 | 10800000 | F3 | A | C | 2025-01-01 09:00:00 | 2025-01-01 12:00:00 | 120 |
3513
+ *
3259
3514
  * @param sourceColumn - The name of the column containing each connection's source node ID.
3260
3515
  * @param targetColumn - The name of the column containing each connection's target node ID.
3261
3516
  * @param edgeId - The name of the column uniquely identifying each connection (edge).
@@ -3268,12 +3523,14 @@ export default class SimpleTable extends Simple {
3268
3523
  * @param options.minGapMs - The minimum gap between consecutive connections, in milliseconds. Must be a non-negative integer. Defaults to `0`. Requires a time column.
3269
3524
  * @param options.strictOrdering - Whether to reject zero-duration gaps between consecutive connections (equal timestamps). Defaults to `true`. Requires a time column.
3270
3525
  * @param options.weight - The name of the numeric column used as the cost of each connection. If omitted, each connection costs one.
3526
+ * @param options.elapsedTime - Whether to add cumulative `elapsedTimeMs` in milliseconds, including connection gaps. Defaults to `false`. Requires both time columns.
3271
3527
  * @param options.outputTable - If `true`, stores the result in a new table with a generated name. If a string, uses it as the new table's name. If `false` or omitted, overwrites the current table. Defaults to `false`.
3272
3528
  * @returns The result table, so methods can be chained.
3273
3529
  * @category Graph Operations
3274
3530
  */
3275
3531
  paths(sourceColumn: string, targetColumn: string, edgeId: string, start: string | number | bigint, end: string | number | bigint, options?: {
3276
3532
  direction?: "outgoing" | "incoming" | "both";
3533
+ elapsedTime?: boolean;
3277
3534
  endTimeColumn?: string;
3278
3535
  minGapMs?: number;
3279
3536
  outputTable?: string | boolean;
@@ -3529,6 +3786,56 @@ export default class SimpleTable extends Simple {
3529
3786
  * | B | 0 | 2 | 1 | 2 | F2 | C | A | 2025-01-01 10:00:00 |
3530
3787
  * | B | 0 | 3 | 1 | 3 | F1 | B | C | 2025-01-01 09:00:00 |
3531
3788
  *
3789
+ * For the next two examples, `flights` contains these rows, with departure
3790
+ * and arrival stored as timestamps on the same day:
3791
+ *
3792
+ * | flightId | origin | destination | departure | arrival | price |
3793
+ * | --- | --- | --- | --- | --- | ---: |
3794
+ * | F1 | A | B | 2025-01-01 09:00 | 2025-01-01 10:00 | 40 |
3795
+ * | F2 | B | A | 2025-01-01 12:00 | 2025-01-01 13:00 | 60 |
3796
+ *
3797
+ * Report elapsed time for every cycle, including layovers:
3798
+ *
3799
+ * @example
3800
+ * ```ts
3801
+ * await flights
3802
+ * .findCycles("origin", "destination", "flightId", "A", {
3803
+ * startTimeColumn: "departure",
3804
+ * endTimeColumn: "arrival",
3805
+ * minGapMs: 60 * 60 * 1000,
3806
+ * elapsedTime: true,
3807
+ * })
3808
+ * .log();
3809
+ * ```
3810
+ *
3811
+ * | start | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
3812
+ * | --- | ---: | ---: | ---: | ---: | ---: | --- | --- | --- | --- | --- | ---: |
3813
+ * | A | 0 | 1 | 1 | 1 | 3600000 | F1 | A | B | 2025-01-01 09:00:00 | 2025-01-01 10:00:00 | 40 |
3814
+ * | A | 0 | 2 | 1 | 2 | 14400000 | F2 | B | A | 2025-01-01 12:00:00 | 2025-01-01 13:00:00 | 60 |
3815
+ *
3816
+ * The return journey takes four hours (14,400,000 milliseconds),
3817
+ * including the two-hour layover at B.
3818
+ *
3819
+ * Add up prices while continuing to report elapsed time for every cycle:
3820
+ *
3821
+ * @example
3822
+ * ```ts
3823
+ * await flights
3824
+ * .findCycles("origin", "destination", "flightId", "A", {
3825
+ * startTimeColumn: "departure",
3826
+ * endTimeColumn: "arrival",
3827
+ * minGapMs: 60 * 60 * 1000,
3828
+ * elapsedTime: true,
3829
+ * weight: "price",
3830
+ * })
3831
+ * .log();
3832
+ * ```
3833
+ *
3834
+ * | start | pathId | step | weight | total | elapsedTimeMs | flightId | origin | destination | departure | arrival | price |
3835
+ * | --- | ---: | ---: | ---: | ---: | ---: | --- | --- | --- | --- | --- | ---: |
3836
+ * | A | 0 | 1 | 40 | 40 | 3600000 | F1 | A | B | 2025-01-01 09:00:00 | 2025-01-01 10:00:00 | 40 |
3837
+ * | A | 0 | 2 | 60 | 100 | 14400000 | F2 | B | A | 2025-01-01 12:00:00 | 2025-01-01 13:00:00 | 60 |
3838
+ *
3532
3839
  * @param sourceColumn - The name of the column containing each connection's source node ID.
3533
3840
  * @param targetColumn - The name of the column containing each connection's target node ID.
3534
3841
  * @param edgeId - The name of the column uniquely identifying each connection (edge).
@@ -3540,12 +3847,14 @@ export default class SimpleTable extends Simple {
3540
3847
  * @param options.minGapMs - The minimum gap between consecutive connections, in milliseconds. Must be a non-negative integer. Defaults to `0`. Requires a time column.
3541
3848
  * @param options.strictOrdering - Whether to reject zero-duration gaps between consecutive connections (equal timestamps). Defaults to `true`. Requires a time column.
3542
3849
  * @param options.weight - The name of the numeric column used as the cost of each connection. If omitted, each connection costs one.
3850
+ * @param options.elapsedTime - Whether to add cumulative `elapsedTimeMs` in milliseconds, including connection gaps. Defaults to `false`. Requires both time columns.
3543
3851
  * @param options.outputTable - If `true`, stores the result in a new table with a generated name. If a string, uses it as the new table's name. If `false` or omitted, overwrites the current table. Defaults to `false`.
3544
3852
  * @returns The result table, so methods can be chained.
3545
3853
  * @category Graph Operations
3546
3854
  */
3547
3855
  findCycles(sourceColumn: string, targetColumn: string, edgeId: string, startNodes: string | number | bigint | (string | number | bigint)[], options?: {
3548
3856
  direction?: "outgoing" | "incoming" | "both";
3857
+ elapsedTime?: boolean;
3549
3858
  endTimeColumn?: string;
3550
3859
  minGapMs?: number;
3551
3860
  outputTable?: string | boolean;