@mark1russell7/highways 0.8.1 → 0.9.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
@@ -107,6 +107,8 @@ Two edges can go along several runs one after the other. The option `laneOrder`
107
107
  - The default of `trunks` and `shared` is `bundle`. The default of `sections` is `run`, so its runs keep the lane order of version 0.2.0.
108
108
  - `orderLanes(run, routes, order)` gives the order of one run. Its default order is `run`.
109
109
  - The option changes only the lane order. The routes, the runs and their keys stay the same.
110
+ - The option `stretchOrder` of `shared` and `shared-all` gives one order to each stretch of runs: `none` (the default), `consensus`, `periphery` or `sifting`. The default of `shared-stretch` is `sifting`. `siftPasses` sets the passes of `sifting`.
111
+ - `stretchLaneOrders(runs, options?)` gives the order of each run. `laneStretches` gives the stretches. [One lane order for each stretch](../../docs/research/XPLAT.md#one-lane-order-for-each-stretch-lane-stretch) gives the numbers.
110
112
 
111
113
  The benchmark measures the lanes of `highwayCurves` on the case boards, with each lane order. A crossing in the body is between the middles of the first and the last leg of a bundle. An end crossing is near a merge or a split.
112
114
 
@@ -345,10 +347,19 @@ The steps of the pipeline that vary have strategies. Each step has one interface
345
347
  | Step | Input | Output | Built-in strategies |
346
348
  |---|---|---|---|
347
349
  | `group` | `Graph` | `Section`: the tree of groups of the router `sections` | `quadtree`, `keys`, `kd`, `cut` |
350
+ | `plugs` | `PlugInput`: the graph, and optionally the ways of the router | `PlugPair[]`: the two plugs of each edge | `facing` |
348
351
  | `router` | `Graph` | `Result` | `straight`, `plugs`, `corners`, `corners-smooth`, `trunks`, `shared`, `shared-all`, `sections`, `sections-tree` |
349
352
  | `highway` | `HighwayInput`: the graph, optionally the first routes of a router, and optionally the plan before an edit | `HighwayPlan`: the highways as data | `keys`, `shared-ways`, `corridors`, `meet`, `weiszfeld`, `stubs`, `zipper`, `level-links`, `quickbundles`, `road-classes`, `flow-field`, `wspd`, `od-cells`, `select`, `mingle`, `spiral`, `flow-clusters`, `traclus`, `diffusion`, `nested`, `lanes`, `growth`, `edge-paths`, `soft-keys`, `hough`, `ridges`, `hdbscan`, `hub-arcs`, `divided`, `hierarchy`, `fdeb`, `mesh`, `kdeeb`, `cubu`, `mlseb`, `sbeb`, `areas`, `confluent`, `power`, `crossbars`, `frechet`, `spectral`, `resistance`, `link-communities`, `territories`, `consensus`, `p-hub`, `scale-space`, `corridors+breakeven`, `corridors+stretch`, `corridors+ambiguity`, `corridors+hysteresis`, `corridors+ids` |
353
+ | `levels` | `LevelInput`: the graph, the tree of groups and the routes | `Level[]`: the zoom levels of the router `sections` | `depths` |
350
354
  | `curve` | `CurveInput`: the points, the normals of the plugs, the free space and the lane on its board | `CurveSegment[]` | `straight`, `rounded`, `spline`, `arc`, `smooth`, `clothoid`, `highway` |
351
355
  | `room` | `RoomInput`: the boxes and the links of a board, and the tree of sections for `levels` | `Gap[]` | `routes`, `lines`, `levels` |
356
+ | `whole` | `Graph` | `WholeOutput`: the board and its `Result` | `pipeline` |
357
+
358
+ `STEPS` gives the steps in the order of the pipeline: `group`, `plugs`, `router`, `highway`, `levels`, `curve`, `room`, `whole`.
359
+
360
+ - The plugs come before the router, because the router finds its ways between the plugs.
361
+ - The levels come after the routes, because the last level uses the routes.
362
+ - The step `whole` runs the other steps, so it comes last.
352
363
 
353
364
  A strategy has a `step`, a `name`, a `describe` text, its `defaults` and the method `run(input, options?)`. The type of the options comes from `defaults`. Each option that a call does not give gets its default value.
354
365
 
@@ -357,7 +368,29 @@ A strategy has a `step`, a `name`, a `describe` text, its `defaults` and the met
357
368
  - `register(registry, ...strategies)` gives a new registry. It does not change the registry before it.
358
369
  - `listStrategies(registry, step)` gives the strategies of a step, in order. `findStrategy` and `getStrategy` give one strategy by its name.
359
370
  - `asRouter(strategy, options?)` gives a `Router`, and `routersOf(registry)` gives the routers of a registry.
360
- - `STRATEGIES` is the registry of `BUILT_IN_STRATEGIES`. The records `groupStrategies`, `routerStrategies`, `highwayStrategies`, `curveStrategies` and `roomStrategies` give each built-in strategy with its typed options.
371
+ - `STRATEGIES` is the registry of `BUILT_IN_STRATEGIES`. The records `groupStrategies`, `plugStrategies`, `routerStrategies`, `highwayStrategies`, `levelStrategies`, `curveStrategies`, `roomStrategies` and `wholeStrategies` give each built-in strategy with its typed options.
372
+
373
+ ### The steps `plugs`, `levels` and `whole`
374
+
375
+ Each of these steps has one default strategy. The default gives the output of the code before the step, so each route stays the same.
376
+
377
+ - `facing` (the step `plugs`) puts each free plug on the side that faces the other end of its edge. The router `corners` uses it by default.
378
+ The option `plug` of `corners` takes a plug strategy, and `plugOptions` gives its options.
379
+ - `depths` (the step `levels`) makes one zoom level for each depth of the tree, and a last level with each node alone (`depthLevels`).
380
+ The option `level` of `sections` takes a level strategy, and `levelOptions` gives its options. The strategy also gets the level options of the router.
381
+ - `pipeline` (the step `whole`) runs a room strategy, then a router or a highway plan, with the rules that the router reads (`runPipeline`).
382
+ Without options, it routes with `corners`. The demo of the site runs it. It does not draw the curves.
383
+ - `strategyKey(router, step)` gives the option of a router that takes a strategy of the step. `pipeline` uses it for the steps `group`, `plugs` and `levels`.
384
+ - `stepRouterStrategy(strategy)` runs a strategy of a step of `RoutedStep` as a router. `stepRouters(registry, step)` gives one router for each strategy of the step.
385
+
386
+ ```ts
387
+ import { asRouter, CASES, plugStrategies, routerStrategies, wholeStrategies } from "@mark1russell7/highways";
388
+
389
+ const graph = CASES.find((c) => c.name === "case-hub-chain")!.make();
390
+ // The two calls give the routes of `corners` with no option.
391
+ const a = asRouter(routerStrategies.corners, { plug: plugStrategies.facing }).route(graph);
392
+ const b = wholeStrategies.pipeline.run(graph).result;
393
+ ```
361
394
 
362
395
  ### The step `highway`
363
396
 
@@ -505,6 +538,7 @@ The router `portfolio` is opt-in. It is not in `STRATEGIES`, so the default outp
505
538
  - The result has the output, the winner, the trace of the pick and the move count `move.pick`.
506
539
  - `exactStretches(graph, options?)` gives a function from the routes to the stretch of each edge in the exact model. The router uses it for the cap. `exactStretch` gives the largest stretch.
507
540
  - `portfolioRouter(options?)` gives a `Router`, and `portfolioStrategy` is the router strategy. Add `portfolioStrategy` to a registry of your own to race it.
541
+ - `portfolioStrategy.schema` declares each option except the clock `now` (SCHEMA-GAPS). The lists of `rule`, `cap`, `k` and `hashes` come from `PORTFOLIO_RULES`, `PORTFOLIO_CAPS`, `PORTFOLIO_KS_API` and `PORTFOLIO_HASHES`.
508
542
 
509
543
  ```ts
510
544
  import { routePortfolio } from "@mark1russell7/highways";
@@ -512,15 +546,24 @@ import { routePortfolio } from "@mark1russell7/highways";
512
546
  const { result, winner } = routePortfolio(graph, { rule: "all", cap: 1.25, k: 5, budgetMs: 50 });
513
547
  ```
514
548
 
549
+ ### The router `shared-stretch`
550
+
551
+ The router `shared-stretch` is opt-in. It is `shared` with the stretch order `sifting`. It is not in `STRATEGIES`, so the default outputs do not change.
552
+
553
+ - `sharedStretchStrategy` is the router strategy. Add it to a registry of your own to race it.
554
+ - Its routes are the routes of `shared`. Only the lane order of the runs changes.
555
+ - On `screen-v1`, the order `sifting` cuts the lane crossings and the broken pairs of `shared` from 21 to 16.
556
+ - Each run calculates the relation of each pair of its lanes. On a dense board of 1000 boxes, a route takes 25 times the time of `shared`.
557
+
515
558
  ### Declarations of the options
516
559
 
517
560
  Each strategy declares its options in `schema`. A declaration tells the type, the range, the step and the meaning of one option. Tools make controls and sweeps from these declarations, with no other data.
518
561
 
519
562
  | Type | Fields | Values |
520
563
  |---|---|---|
521
- | `number`, `integer` | `min`, `max`, `step`, `scale`, `special`, `marks` | A number. An `integer` takes only whole numbers. |
564
+ | `number`, `integer` | `min`, `max`, `step`, `scale`, `special`, `marks`, `values` | A number. An `integer` takes only whole numbers. With `values`, only one of `values`. |
522
565
  | `boolean` | | `false` or `true`. |
523
- | `enum` | `values` | One of `values`. |
566
+ | `enum` | `values`, `custom` | One of `values`. With `custom: "function"`, also a rule of the caller. |
524
567
  | `function`, `strategy`, `list`, `object` | `step` (for `strategy`) | A rule, a strategy, an array or an object. A sweep cannot set them. |
525
568
 
526
569
  Each declaration has a `describe` sentence and an optional `default`.
@@ -529,18 +572,27 @@ Each declaration has a `describe` sentence and an optional `default`.
529
572
  - The `scale` is `linear` or `log`. A sweep on the scale `log` gives values with equal ratios.
530
573
  - The `special` values are valid outside the range. `Infinity` sets no limit.
531
574
  - The `marks` are the notable values: the default and the values of the sweeps of the benchmark.
575
+ - The `values` of a number option are its only valid values. A control shows them as a list, and a sweep gives them. The `cap` of the portfolio router uses them.
576
+ - An enum with `custom: "function"` names the known rules of an option that also takes a rule. A control sets the names, and a caller can still give its own rule.
532
577
  - The `default` is the value that the strategy uses when the caller and `defaults` give no value. A value of `defaults` comes first.
533
578
 
534
579
  The type `OptionSchema<O>` needs one declaration for each key of the options, and no other key. A number option needs a number declaration, and an enum declaration takes only the values of its type.
580
+ An option of a rule or its name, for example `GroupRule | "collection" | "all"`, takes an enum of the names or a declaration of the rule.
581
+
582
+ The option `rule` of the routers `trunks`, `shared` and `shared-all`, and of the highway strategies `keys`, `shared-ways` and `soft-keys`, takes a name (SCHEMA-GAPS):
583
+
584
+ - With `collection`, the rule is `byCollection`. With `all`, each edge has one key. For the router `shared`, `all` is the same as no rule.
585
+ - The `defaults` of each strategy keep the rule `byCollection`, as before. The declaration gives its name `collection` as its `default`. The router `shared-all` sets no rule.
586
+ - A rule of the caller stays valid. The name `collection` gives the same output as the rule `byCollection`.
535
587
 
536
588
  The helpers read the declarations:
537
589
 
538
590
  - `optionDefaults(strategy)` gives the effective default of each option. The strategy gives the same output with this object as with no options.
539
591
  - `listOptions(strategy)` gives each option with its key, its declaration and its default, in the order of the schema.
540
- - `checkOptions(strategy, options)` reports each value without a declaration, of the wrong type, out of the range or not a whole number. It changes no value.
541
- - `clampOptions(strategy, options)` moves each number into its range, for a control. A special value stays.
592
+ - `checkOptions(strategy, options)` reports each value without a declaration, of the wrong type, out of the range, not a whole number or not one of `values`. It changes no value.
593
+ - `clampOptions(strategy, options)` moves each number into its range, for a control. A number with `values` moves to the nearest value. A special value stays.
542
594
  - `checkSchema(strategy)` reports each option of `defaults` without a declaration, and each bad declaration.
543
- - `sweepValues(declaration, { count, special })` gives the values of a sweep. Without `count`, a number option gives its `marks`.
595
+ - `sweepValues(declaration, { count, special })` gives the values of a sweep. Without `count`, a number option gives its `marks`. Else, a number option with `values` gives its `values`.
544
596
  - `sweepOf(strategy, key, options)` gives one setting for each value of a sweep. The name of a setting is the key and the value.
545
597
  - `sweepGrid(strategy, keys, options)` gives one setting for each combination of the values of the keys.
546
598
 
@@ -556,7 +608,7 @@ const rows = sweepSections("case-hub-chain", graph, sweepOf(routerStrategies.sec
556
608
 
557
609
  A test examines each built-in strategy with `checkSchema`. Thus an option of `defaults` without a declaration makes the test fail.
558
610
 
559
- The plugs have one strategy, so they have no step yet. The step `group` gives the grouping rule of the zoom levels.
611
+ The step `plugs` gives the plugs of the router `corners`. The step `group` gives the grouping rule of the zoom levels, and the step `levels` makes the levels.
560
612
 
561
613
  ## Measures and the report
562
614
 
@@ -596,7 +648,20 @@ The script `bench` takes `--seeds <n>` and `--report <file>`. A family with more
596
648
 
597
649
  The workflow `Bench` runs the suite in parts. Each part writes its report, and `joinReports` joins the reports into the report of one run.
598
650
 
599
- `compareStep` runs each strategy of one step on one board, with the measures of the suite. It gives one row for each strategy and the Pareto front of the step. The options give each strategy its own options. The compare page of the site uses it.
651
+ Three options of `runSuite` keep each part short (BENCH-GREEN):
652
+
653
+ - `shard` runs one shard of the cells of the steps `router` and `highway`. The strategy at place `s` on the seed `k` belongs to the shard `(s + k) % count`.
654
+ - `caps` stops a strategy above a fixture size. The report lists each such cell in `capped`.
655
+ - `pair` names a baseline router, for example `shared`. On the first seed of each fixture to `pairMax` nodes, the baseline routes in turn with each strategy. The row gets `paired`, with the two medians and their ratio.
656
+
657
+ `compareStep` runs each strategy of one step on one board, with the measures of the suite. It gives one row for each strategy and the Pareto front of the step. The options give each strategy its own options.
658
+
659
+ `compareAnyStep` does the same for each step of `COMPARE_ALL_STEPS`, which is `STEPS`. The compare page of the site uses it.
660
+
661
+ - The step `highway` makes the plan of each strategy, and `follow` routes the plan, as in the screen. `highwayRouters` gives these routers.
662
+ - The steps `plugs`, `levels` and `whole` run each strategy as a router (`stepRouterStrategy`), and measure the routes as the step `router`.
663
+ - The step `room` opens the gaps of a packed board with each strategy and measures the open board with `roomValues`.
664
+ - The option `onRow` gets each row when its strategy is done, so a host can show the progress.
600
665
 
601
666
  With the option `lanes`, the step `curve` opens each shared way of the routes of `curveRouter` into lanes, and each curve draws the lanes. Each input then has its `lane`, so the curve `highway` bends the lanes of a bundle as one with each of its options.
602
667
 
@@ -615,6 +680,7 @@ A transcendental Math function, for example `Math.atan2` or `Math.hypot`, can gi
615
680
  - For a new decision, use exact arithmetic: a cross product, a dot product or a squared length.
616
681
  - A compare function of a sort must be a total order. Otherwise, two engines can give two orders.
617
682
  - The lane order of a run comes from a merge sort of the package, so each engine gives the same order (LANE-ORDER).
683
+ - Each sort of the stretch orders (LANE-STRETCH) has a total order. Its ties break by the key of the edge or of the run. Thus the 4 cells of `Xplat` agree.
618
684
  - Version 0.8.0 changes the default lane order of some shared runs. No route point moves. [The lane order](../../docs/research/XPLAT.md#the-lane-order-lane-order) gives the changes.
619
685
  - The note [`XPLAT.md`](../../docs/research/XPLAT.md) gives the result of the item XPLAT-HASH.
620
686