@mark1russell7/highways 0.9.0 → 0.9.1

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.
@@ -9,7 +9,8 @@ import { byCollection, trunksRouter } from "./trunks.ts";
9
9
  export { boxExit, straightRouter } from "./straight.ts";
10
10
  export { plugsRouter } from "./plugs.ts";
11
11
  export { cornersRouter, type CornersOptions } from "./corners.ts";
12
- export { sharedRouter, type ShareCost, type SharedOptions, type ShareMerge, type ShareOrder } from "./shared.ts";
12
+ export { sharedRouter, type ShareCost, type SharedNegotiation, type SharedOptions, type ShareMerge, type ShareOrder } from "./shared.ts";
13
+ export { ATTRACTION_DEFAULTS, ATTRACTION_SCHEMA, attractionRouter, attractionStrategy, type AttractionOptions } from "./attraction/index.ts";
13
14
  export { sectionsRouter, type SectionsOptions } from "./sections.ts";
14
15
  export { byCollection, groupEdges, laneOrder, splitPoint, trunksRouter, type TrunkFan, type TrunkSplit, type TrunksOptions } from "./trunks.ts";
15
16
 
@@ -1,6 +1,6 @@
1
1
  import { inflectionCurve } from "../curves.ts";
2
2
  import { center } from "../geom.ts";
3
- import { nodeIndex, type Graph, type Result, type Route, type Router } from "../model.ts";
3
+ import { nodeIndex, resolvePorts, type Graph, type Result, type Route, type Router } from "../model.ts";
4
4
  import { placePlug } from "../plugs.ts";
5
5
 
6
6
  /**
@@ -9,7 +9,8 @@ import { placePlug } from "../plugs.ts";
9
9
  */
10
10
  export const plugsRouter: Router = {
11
11
  name: "plugs",
12
- route(graph: Graph): Result {
12
+ route(input: Graph): Result {
13
+ const graph = resolvePorts(input);
13
14
  const byId = nodeIndex(graph);
14
15
  const routes: Route[] = [];
15
16
  for (const e of graph.edges) {
@@ -2,7 +2,7 @@ import { BACKTRACK_MIN, goesOutAndBack } from "../bench/links.ts";
2
2
  import { center, dist, pointSegmentDistance, polylineLength, type Point } from "../geom.ts";
3
3
  import { LEVEL_LINK_DEFAULTS, type LevelLinkOptions } from "../levels.ts";
4
4
  import { depthLevels, type DepthLevelOptions } from "../levels/depths/index.ts";
5
- import { nodeIndex, type Graph, type Level, type Node, type Result, type Route, type Router, type SharedRun } from "../model.ts";
5
+ import { nodeIndex, resolvePorts, type Graph, type Level, type Node, type Result, type Route, type Router, type SharedRun } from "../model.ts";
6
6
  import { placePlug } from "../plugs.ts";
7
7
  import { allSections, buildSections, checkSections, SECTION_DEFAULTS, type Section, type SectionOptions } from "../sections.ts";
8
8
  import { orderLanes, type RunOrder } from "../segments.ts";
@@ -91,7 +91,8 @@ const dedupe = (p: readonly Point[]): Point[] => p.filter((q, i) => i === 0 || d
91
91
  export function sectionsRouter(options: SectionsOptions): Router {
92
92
  const router: Router = {
93
93
  name: options.name,
94
- route(graph: Graph): Result {
94
+ route(input: Graph): Result {
95
+ const graph = resolvePorts(input);
95
96
  const stretch = options.stretch ?? SECTIONS_DEFAULTS.stretch;
96
97
  const stretchPad = options.stretchPad ?? SECTIONS_DEFAULTS.stretchPad;
97
98
  const hubSlack = options.hubSlack ?? SECTIONS_DEFAULTS.hubSlack;
@@ -1,5 +1,5 @@
1
1
  import { center, dist, type Point } from "../geom.ts";
2
- import { nodeIndex, type Edge, type Graph, type GroupRule, type Result, type Route, type Router, type SharedRun } from "../model.ts";
2
+ import { nodeIndex, resolvePorts, type Edge, type Graph, type GroupRule, type Result, type Route, type Router, type SharedRun } from "../model.ts";
3
3
  import { channelWidth } from "../channels.ts";
4
4
  import { orderRun } from "../lane-order.ts";
5
5
  import { stretchLaneOrders, type LaneStretchOrder } from "../lane-orders/stretch/index.ts";
@@ -77,6 +77,21 @@ export interface SharedOptions extends WayOptions {
77
77
  readonly maxNodes?: number;
78
78
  }
79
79
 
80
+ /**
81
+ * The negotiation of the router `attraction` (HWY-044, PathFinder turned around). Each pass routes each edge again from no ways.
82
+ * A link costs `len (1 - attraction h) (1 + weight max(0, use - cap))` more than in `shared`, with `h` the history of the link.
83
+ */
84
+ export interface SharedNegotiation {
85
+ /** The number of passes, 1 or more. */
86
+ readonly passes: number;
87
+ /** The pull of the history of a link, from 0 to 1. */
88
+ readonly attraction: number;
89
+ /** The cost weight of each edge over the capacity of a link, 0 or more. */
90
+ readonly capacityWeight: number;
91
+ /** The width of one lane. The capacity of a link is its free width divided by this width, and 1 or more. */
92
+ readonly laneWidth: number;
93
+ }
94
+
80
95
  /** A way of one edge through the corner graph. */
81
96
  export interface Way {
82
97
  readonly edge: Edge;
@@ -114,7 +129,7 @@ function turn(from: Point, base: Point, to: Point): number {
114
129
  * Thus the edges of a key come together on common ways. Each stretch that several edges share has the same points in each route.
115
130
  * The result gives each stretch as a run, with the order of its lanes.
116
131
  */
117
- export function sharedRouter(options: SharedOptions): Router {
132
+ export function sharedRouter(options: SharedOptions, negotiation?: SharedNegotiation): Router {
118
133
  const discount = Math.min(1, Math.max(0.05, options.discount ?? 0.5));
119
134
  const flow = options.cost === "flow";
120
135
  const alpha = Math.min(1, Math.max(0.1, options.alpha ?? 0.6));
@@ -133,7 +148,8 @@ export function sharedRouter(options: SharedOptions): Router {
133
148
  };
134
149
  const router: Router = {
135
150
  name: options.name,
136
- route(graph: Graph): Result {
151
+ route(input: Graph): Result {
152
+ const graph = resolvePorts(input);
137
153
  const byId = nodeIndex(graph);
138
154
  const ways = new WayFinder(graph.nodes, options);
139
155
  const corners = ways.corners;
@@ -172,8 +188,11 @@ export function sharedRouter(options: SharedOptions): Router {
172
188
  if (wd === undefined) widths.set(k, (wd = channelWidth(ways.obstacles, corners.points[i]!, corners.points[j]!)));
173
189
  return wd;
174
190
  };
175
- /** This function routes one way. `before` holds the edges of the key on each link in the pass before, for the option `reuse`. */
176
- const route = (w: Way, before?: ReadonlyMap<number, number>): void => {
191
+ /**
192
+ * This function routes one way. `before` holds the edges of the key on each link in the pass before, for the option `reuse`.
193
+ * `history` holds the history of each link of the key, for the negotiation of `attraction`.
194
+ */
195
+ const route = (w: Way, before?: ReadonlyMap<number, number>, history?: ReadonlyMap<number, number>): void => {
177
196
  let used = discounted.get(w.key);
178
197
  if (!used) discounted.set(w.key, (used = new Map()));
179
198
  const mine = used;
@@ -192,6 +211,20 @@ export function sharedRouter(options: SharedOptions): Router {
192
211
  cost = (i, j, d) => plain(i, j, d) / (1 + reuse * (before.get(link(i, j)) ?? 0)) ** reuseExponent;
193
212
  floor /= (1 + reuse * most) ** reuseExponent;
194
213
  }
214
+ if (negotiation !== undefined && history !== undefined) {
215
+ const plain = cost;
216
+ const a = negotiation.attraction;
217
+ const b = negotiation.capacityWeight;
218
+ let most = 0;
219
+ for (const h of history.values()) most = Math.max(most, h);
220
+ cost = (i, j, d) => {
221
+ const k = link(i, j);
222
+ const use = (mine.get(k)?.length ?? 0) + 1;
223
+ const cap = Math.max(1, Math.floor(widthOf(i, j) / negotiation.laneWidth));
224
+ return plain(i, j, d) * (1 - a * (history.get(k) ?? 0)) * (1 + b * Math.max(0, use - cap));
225
+ };
226
+ floor *= 1 - a * most;
227
+ }
195
228
  const way = corners.path(ways.out(w.ps), ways.out(w.pt), cost, floor);
196
229
  if (!way) return;
197
230
  w.found = true;
@@ -207,9 +240,39 @@ export function sharedRouter(options: SharedOptions): Router {
207
240
  if (flow) top.set(w.key, Math.max(top.get(w.key) ?? 0, mine.get(link(a, b))!.length));
208
241
  }
209
242
  };
210
- for (const w of order) route(w);
243
+ /**
244
+ * This function gives the passes of the negotiation (HWY-044). After each pass, the history of each link grows by `use / m`,
245
+ * with `m` the edges of the key, up to `0.9 / attraction`. Each later pass routes each edge again from no ways.
246
+ */
247
+ const negotiate = (list: readonly Way[]): void => {
248
+ const nego = negotiation!;
249
+ const histories = new Map<string, Map<number, number>>();
250
+ const size = new Map<string, number>();
251
+ for (const w of list) size.set(w.key, (size.get(w.key) ?? 0) + 1);
252
+ const most = nego.attraction > 0 ? 0.9 / nego.attraction : Infinity;
253
+ for (let pass = 0; pass < Math.max(1, Math.floor(nego.passes)); pass++) {
254
+ if (pass > 0) {
255
+ for (const [key, links] of discounted) {
256
+ let h = histories.get(key);
257
+ if (!h) histories.set(key, (h = new Map()));
258
+ const m = size.get(key) ?? 1;
259
+ for (const [k, users] of links) h.set(k, Math.min(most, (h.get(k) ?? 0) + users.length / m));
260
+ }
261
+ discounted.clear();
262
+ top.clear();
263
+ for (const w of list) {
264
+ w.found = false;
265
+ w.seq = [];
266
+ w.ids = [];
267
+ }
268
+ }
269
+ for (const w of list) route(w, undefined, histories.get(w.key) ?? new Map());
270
+ }
271
+ };
272
+ if (negotiation !== undefined) negotiate(order);
273
+ else for (const w of order) route(w);
211
274
  // Each later pass takes each edge off its links and finds its way again, with the ways of the other edges fixed.
212
- for (let pass = 1; pass < passes; pass++) {
275
+ for (let pass = 1; negotiation === undefined && pass < passes; pass++) {
213
276
  if (reuse > 0) {
214
277
  // Winding Roads (HWY-005): each edge finds its way again from no ways, and the busy links of the pass before pull it.
215
278
  const before = new Map<string, Map<number, number>>();
@@ -1,5 +1,5 @@
1
1
  import { center, type Box, type Point } from "../geom.ts";
2
- import { fixedPortPoint, nodeIndex, type Graph, type Result, type Route, type Router } from "../model.ts";
2
+ import { fixedPortPoint, nodeIndex, resolvePorts, type Graph, type Result, type Route, type Router } from "../model.ts";
3
3
 
4
4
  /** This function gives the point where the ray from the center of the box to `toward` leaves the box. */
5
5
  export function boxExit(box: Box, toward: Point): Point {
@@ -19,7 +19,8 @@ export function boxExit(box: Box, toward: Point): Point {
19
19
  */
20
20
  export const straightRouter: Router = {
21
21
  name: "straight",
22
- route(graph: Graph): Result {
22
+ route(input: Graph): Result {
23
+ const graph = resolvePorts(input);
23
24
  const byId = nodeIndex(graph);
24
25
  const routes: Route[] = [];
25
26
  for (const e of graph.edges) {
@@ -1,5 +1,5 @@
1
1
  import { center, dist, type Point } from "../geom.ts";
2
- import { nodeIndex, type Bundle, type Edge, type Graph, type GroupRule, type Node, type Result, type Route, type Router, type SharedRun } from "../model.ts";
2
+ import { nodeIndex, resolvePorts, type Bundle, type Edge, type Graph, type GroupRule, type Node, type Result, type Route, type Router, type SharedRun } from "../model.ts";
3
3
  import { placePlug, type Plug } from "../plugs.ts";
4
4
  import { orderLanes, type RunOrder } from "../segments.ts";
5
5
  import { WayFinder, type WayOptions } from "../ways.ts";
@@ -209,7 +209,8 @@ export function trunksRouter(options: TrunksOptions): Router {
209
209
  const rule = groupRuleOf(options.rule);
210
210
  const router: Router = {
211
211
  name: options.name,
212
- route(graph: Graph): Result {
212
+ route(input: Graph): Result {
213
+ const graph = resolvePorts(input);
213
214
  const byId = nodeIndex(graph);
214
215
  const ways = new WayFinder(graph.nodes, options);
215
216
  const points = new Map<string, readonly Point[]>();
@@ -44,6 +44,11 @@ import { TERRITORY_DEFAULTS, territoryPlan, type TerritoryOptions } from "../hig
44
44
  import { CONSENSUS_DEFAULTS, consensusPlan, type ConsensusOptions } from "../highways/consensus/index.ts";
45
45
  import { P_HUB_DEFAULTS, pHubPlan, type PHubOptions } from "../highways/p-hub/index.ts";
46
46
  import { SCALE_SPACE_DEFAULTS, scaleSpacePlan, type ScaleSpaceOptions } from "../highways/scale-space/index.ts";
47
+ import { GAP_DEFAULTS, gapPlan, type GapOptions } from "../highways/gaps/index.ts";
48
+ import { INTERCHANGE_DEFAULTS, interchangePlan, type InterchangeOptions } from "../highways/interchanges/index.ts";
49
+ import { SEARCH_DEFAULTS, searchPlan, type SearchOptions } from "../highways/search/index.ts";
50
+ import { STEINER_DEFAULTS, steinerPlan, type SteinerOptions } from "../highways/steiner/index.ts";
51
+ import { STREET_DEFAULTS, streetPlan, type StreetOptions } from "../highways/streets/index.ts";
47
52
  import { RIDGE_DEFAULTS, ridgePlan, type RidgeOptions } from "../highways/ridges/index.ts";
48
53
  import { SOFT_KEY_DEFAULTS, softKeyPlan, type SoftKeyOptions } from "../highways/soft-keys/index.ts";
49
54
  import { FLOW_FIELD_DEFAULTS, flowFieldPlan, type FlowFieldOptions } from "../highways/flow-field/index.ts";
@@ -83,7 +88,7 @@ import { createRegistry, defineStrategy, type AnyStrategy, type CurveInput, type
83
88
  import type { OptionSchema } from "./options.ts";
84
89
  import { AREA_SCHEMA, CONFLUENT_SCHEMA, CROSSBAR_SCHEMA, FRECHET_SCHEMA, MLSEB_SCHEMA, POWER_SCHEMA, SBEB_SCHEMA } from "./schemas.ts";
85
90
  import { DEPTHS_SCHEMA, PIPELINE_SCHEMA } from "./schemas.ts";
86
- import { CLOTHOID_SCHEMA, CORNERS_SCHEMA, CORRIDOR_SCHEMA, CONSENSUS_SCHEMA, CUBU_SCHEMA, CUT_SCHEMA, DIFFUSION_SCHEMA, DIVIDED_SCHEMA, EDGE_PATH_SCHEMA, FDEB_SCHEMA, FLOW_CLUSTER_SCHEMA, FLOW_FIELD_SCHEMA, GROWTH_SCHEMA, HDBSCAN_SCHEMA, HIERARCHY_SCHEMA, HIGHWAY_SCHEMA, HOUGH_SCHEMA, HUB_ARC_SCHEMA, KD_SCHEMA, KDEEB_SCHEMA, KEY_SCHEMA, LANES_SCHEMA, LEVEL_HIGHWAY_SCHEMA, LEVEL_ROOM_SCHEMA, LINK_COMMUNITY_SCHEMA, MEET_SCHEMA, MESH_SCHEMA, MINGLE_SCHEMA, NESTED_SCHEMA, OD_CELL_SCHEMA, P_HUB_SCHEMA, QUICKBUNDLES_SCHEMA, RADIUS_SCHEMA, RESISTANCE_SCHEMA, RIDGE_SCHEMA, ROAD_CLASS_SCHEMA, ROOM_SCHEMA, SCALE_SPACE_SCHEMA, SECTION_SCHEMA, SELECT_SCHEMA, SECTIONS_SCHEMA, SHARED_ALL_SCHEMA, SHARED_SCHEMA, SMOOTH_SCHEMA, SOFT_KEY_SCHEMA, SPECTRAL_SCHEMA, SPIRAL_SCHEMA, STUB_SCHEMA, TENSION_SCHEMA, TERRITORY_SCHEMA, TRACLUS_SCHEMA, TRUNKS_SCHEMA, WEISZFELD_SCHEMA, WSPD_SCHEMA, ZIPPER_SCHEMA } from "./schemas.ts";
91
+ import { CLOTHOID_SCHEMA, CORNERS_SCHEMA, CORRIDOR_SCHEMA, CONSENSUS_SCHEMA, CUBU_SCHEMA, CUT_SCHEMA, DIFFUSION_SCHEMA, DIVIDED_SCHEMA, EDGE_PATH_SCHEMA, FDEB_SCHEMA, FLOW_CLUSTER_SCHEMA, FLOW_FIELD_SCHEMA, GROWTH_SCHEMA, HDBSCAN_SCHEMA, HIERARCHY_SCHEMA, HIGHWAY_SCHEMA, HOUGH_SCHEMA, HUB_ARC_SCHEMA, KD_SCHEMA, KDEEB_SCHEMA, KEY_SCHEMA, LANES_SCHEMA, LEVEL_HIGHWAY_SCHEMA, LEVEL_ROOM_SCHEMA, LINK_COMMUNITY_SCHEMA, MEET_SCHEMA, MESH_SCHEMA, MINGLE_SCHEMA, NESTED_SCHEMA, OD_CELL_SCHEMA, P_HUB_SCHEMA, QUICKBUNDLES_SCHEMA, RADIUS_SCHEMA, RESISTANCE_SCHEMA, RIDGE_SCHEMA, ROAD_CLASS_SCHEMA, ROOM_SCHEMA, SCALE_SPACE_SCHEMA, SECTION_SCHEMA, SELECT_SCHEMA, SECTIONS_SCHEMA, SHARED_ALL_SCHEMA, SHARED_SCHEMA, SMOOTH_SCHEMA, SOFT_KEY_SCHEMA, SPECTRAL_SCHEMA, SPIRAL_SCHEMA, STUB_SCHEMA, TENSION_SCHEMA, TERRITORY_SCHEMA, TRACLUS_SCHEMA, TRUNKS_SCHEMA, WEISZFELD_SCHEMA, WSPD_SCHEMA, ZIPPER_SCHEMA, STEINER_SCHEMA, GAP_SCHEMA, STREET_SCHEMA, SEARCH_SCHEMA, INTERCHANGE_SCHEMA } from "./schemas.ts";
87
92
 
88
93
  /** The options of a router strategy: the options of its router, without the name and the limit of the benchmark. */
89
94
  export type RouterPreset<O> = Omit<O, "name" | "maxNodes">;
@@ -462,6 +467,11 @@ export const highwayStrategies: {
462
467
  readonly consensus: Strategy<"highway", ConsensusOptions>;
463
468
  readonly "p-hub": Strategy<"highway", PHubOptions>;
464
469
  readonly "scale-space": Strategy<"highway", ScaleSpaceOptions>;
470
+ readonly steiner: Strategy<"highway", SteinerOptions>;
471
+ readonly gaps: Strategy<"highway", GapOptions>;
472
+ readonly streets: Strategy<"highway", StreetOptions>;
473
+ readonly search: Strategy<"highway", SearchOptions>;
474
+ readonly interchanges: Strategy<"highway", InterchangeOptions>;
465
475
  readonly "corridors+breakeven": Strategy<"highway", CorridorOptions & BreakEvenOptions>;
466
476
  readonly "corridors+stretch": Strategy<"highway", CorridorOptions & StretchOptions>;
467
477
  readonly "corridors+ambiguity": Strategy<"highway", CorridorOptions & AmbiguityGuardOptions>;
@@ -892,6 +902,51 @@ export const highwayStrategies: {
892
902
  maxNodes: 10_000,
893
903
  run: (input: HighwayInput, o: Readonly<ScaleSpaceOptions>) => scaleSpacePlan(input, o),
894
904
  }),
905
+ steiner: defineStrategy({
906
+ step: "highway",
907
+ name: "steiner",
908
+ describe: "Obstacle-avoiding rectilinear Steiner trees (HWY-036 with EDA-015). Each group of edges gets one tree, and the stretches that edges share become highways.",
909
+ defaults: { ...STEINER_DEFAULTS } as SteinerOptions,
910
+ schema: STEINER_SCHEMA,
911
+ maxNodes: 10_000,
912
+ run: (input: HighwayInput, o: Readonly<SteinerOptions>) => steinerPlan(input, o),
913
+ }),
914
+ gaps: defineStrategy({
915
+ step: "highway",
916
+ name: "gaps",
917
+ describe: "Gap highways (HWY-057). The free middle lines of the gaps are streets, and a street that enough edges choose becomes a highway.",
918
+ defaults: { ...GAP_DEFAULTS } as GapOptions,
919
+ schema: GAP_SCHEMA,
920
+ maxNodes: 10_000,
921
+ run: (input: HighwayInput, o: Readonly<GapOptions>) => gapPlan(input, o),
922
+ }),
923
+ streets: defineStrategy({
924
+ step: "highway",
925
+ name: "streets",
926
+ describe: "Orthogonal streets by a greedy set cover (HWY-058). Each step takes the street that its new edges ride the most per unit of its length.",
927
+ defaults: { ...STREET_DEFAULTS } as StreetOptions,
928
+ schema: STREET_SCHEMA,
929
+ maxNodes: 10_000,
930
+ run: (input: HighwayInput, o: Readonly<StreetOptions>) => streetPlan(input, o),
931
+ }),
932
+ search: defineStrategy({
933
+ step: "highway",
934
+ name: "search",
935
+ describe: "A local search over the set of highways (HWY-059). The annealing adds, drops and moves highways, edges and points on a score of the bundle measures.",
936
+ defaults: { ...SEARCH_DEFAULTS } as SearchOptions,
937
+ schema: SEARCH_SCHEMA,
938
+ maxNodes: 10_000,
939
+ run: (input: HighwayInput, o: Readonly<SearchOptions>) => searchPlan(input, o),
940
+ }),
941
+ interchanges: defineStrategy({
942
+ step: "highway",
943
+ name: "interchanges",
944
+ describe: "A network of highways with interchanges (HWY-060). Each edge rides up to a number of highways, with a cost for each change.",
945
+ defaults: { ...INTERCHANGE_DEFAULTS } as InterchangeOptions,
946
+ schema: INTERCHANGE_SCHEMA,
947
+ maxNodes: 10_000,
948
+ run: (input: HighwayInput, o: Readonly<InterchangeOptions>) => interchangePlan(input, o),
949
+ }),
895
950
  "corridors+breakeven": gateStrategy(corridors, breakEvenGate),
896
951
  "corridors+stretch": gateStrategy(corridors, stretchGate),
897
952
  "corridors+ambiguity": gateStrategy(corridors, ambiguityGate),
@@ -39,6 +39,11 @@ import type { ResistanceOptions } from "../highways/resistance/index.ts";
39
39
  import type { RidgeOptions } from "../highways/ridges/index.ts";
40
40
  import type { RoadClassOptions } from "../highways/road-classes/index.ts";
41
41
  import type { ScaleSpaceOptions } from "../highways/scale-space/index.ts";
42
+ import type { GapOptions } from "../highways/gaps/index.ts";
43
+ import type { InterchangeOptions } from "../highways/interchanges/index.ts";
44
+ import type { SearchOptions } from "../highways/search/index.ts";
45
+ import type { SteinerOptions } from "../highways/steiner/index.ts";
46
+ import type { StreetOptions } from "../highways/streets/index.ts";
42
47
  import type { SelectOptions } from "../highways/select/index.ts";
43
48
  import type { SoftKeyOptions } from "../highways/soft-keys/index.ts";
44
49
  import type { SpectralOptions } from "../highways/spectral/index.ts";
@@ -925,3 +930,54 @@ export const PIPELINE_SCHEMA: OptionSchema<PipelineOptions> = {
925
930
  room: { type: "strategy", step: "room", describe: "The room strategy. With it, the gaps of the board open before the routes. Without it, the board stays." },
926
931
  roomOptions: { type: "object", describe: "The options of the room strategy." },
927
932
  };
933
+
934
+ /** The declarations of the options of the highway strategy `steiner` (HWY-036 with EDA-015). */
935
+ export const STEINER_SCHEMA: OptionSchema<SteinerOptions> = {
936
+ group: { type: "enum", values: ["source", "key"], default: "source", describe: "The groups of the trees: the edges from one source node, or the edges of one collection." },
937
+ method: { type: "enum", values: ["one-steiner", "spanning"], default: "one-steiner", describe: "The method of the tree: the iterated 1-Steiner method, or the spanning tree of the terminals." },
938
+ maxGroup: { type: "integer", min: 3, max: 32, step: 1, marks: [8, 12, 16], default: 12, describe: "A group with more terminals than this number gets the spanning tree alone." },
939
+ metric: { type: "enum", values: ["rectilinear", "octilinear"], default: "rectilinear", describe: "The metric of the tree: two directions or four directions." },
940
+ detour: { type: "number", min: 1, max: 3, step: 0.05, marks: [1.25, 1.5, 2], default: 1.5, describe: "An edge rides the tree only when its path in the tree is this many times its first route or less." },
941
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A stretch of a tree with fewer edges than this number is not a highway." },
942
+ };
943
+
944
+ /** The declarations of the options of the highway strategy `gaps` (HWY-057). */
945
+ export const GAP_SCHEMA: OptionSchema<GapOptions> = {
946
+ minSize: { type: "integer", min: 2, max: 16, step: 1, marks: [2, 3, 6], default: 3, describe: "A street with fewer edges than this number (the demand) is not a highway." },
947
+ discount: { type: "number", min: 0.1, max: 0.8, step: 0.05, marks: [0.3, 0.5, 0.7], default: 0.5, describe: "The cost of a length on a street against a length off the streets." },
948
+ detour: { type: "number", min: 1, max: 2, step: 0.05, marks: [1.2, 1.3, 1.5], default: 1.3, describe: "An edge rides a street only when its way along the street is this many times its first route or less." },
949
+ source: { type: "enum", values: ["room", "corners"], default: "room", describe: "The source of the streets: the gaps of the room step, or the lines through the corners." },
950
+ };
951
+
952
+ /** The declarations of the options of the highway strategy `streets` (HWY-058). */
953
+ export const STREET_SCHEMA: OptionSchema<StreetOptions> = {
954
+ detour: { type: "number", min: 1, max: 1.5, step: 0.05, marks: [1.1, 1.2, 1.3], default: 1.2, describe: "A street covers an edge when the way of the edge along it is this many times its first route or less." },
955
+ minGain: { type: "number", min: 1, max: 8, step: 0.25, marks: [1.5, 2, 4], default: 2, describe: "The cover stops when the best street gives less gain: the length that its edges ride over its length." },
956
+ maxStreets: { type: "integer", min: 4, max: 64, step: 4, marks: [16, 32], default: 32, describe: "The largest number of streets." },
957
+ minSize: { type: "integer", min: 2, max: 16, step: 1, default: 2, describe: "A street with fewer new edges than this number is not a highway." },
958
+ source: { type: "enum", values: ["room", "corners"], default: "corners", describe: "The source of the streets: the gaps of the room step, or the lines through the corners." },
959
+ };
960
+
961
+ /** The declarations of the options of the highway strategy `search` (HWY-059). */
962
+ export const SEARCH_SCHEMA: OptionSchema<SearchOptions> = {
963
+ from: { type: "enum", values: ["corridors", "quickbundles", "wspd", "road-classes", "flow-field", "od-cells", "shared-ways"], default: "corridors", describe: "The plan where the search starts." },
964
+ pool: { type: "list", default: ["quickbundles", "road-classes"], describe: "The generators of the highways that the move `add` takes." },
965
+ evaluations: { type: "integer", min: 0, max: 400, step: 4, marks: [0, 16, 64], default: 16, describe: "The number of plans that the search measures. The value 0 gives the start plan." },
966
+ temperature: { type: "number", min: 0, max: 0.2, step: 0.005, marks: [0, 0.02, 0.05], default: 0.02, describe: "The first temperature of the annealing, on the scale of the score." },
967
+ inkWeight: { type: "number", min: 0, max: 4, step: 0.25, marks: [1], default: 1, describe: "The weight of the ink that the routes save (B1)." },
968
+ stretchWeight: { type: "number", min: 0, max: 4, step: 0.25, marks: [0.5], default: 0.5, describe: "The weight of the 0.95 quantile of the stretch (B3)." },
969
+ ambiguityWeight: { type: "number", min: 0, max: 4, step: 0.25, marks: [0.5], default: 0.5, describe: "The weight of the ambiguity (B4)." },
970
+ angleWeight: { type: "number", min: 0, max: 4, step: 0.25, marks: [0.25], default: 0.25, describe: "The weight of the largest merge angle (B6), divided by 180 degrees." },
971
+ seed: { type: "integer", min: 0, max: 1000, step: 1, default: 1, describe: "The seed of the moves." },
972
+ };
973
+
974
+ /** The declarations of the options of the highway strategy `interchanges` (HWY-060). */
975
+ export const INTERCHANGE_SCHEMA: OptionSchema<InterchangeOptions> = {
976
+ from: { type: "enum", values: ["corridors", "shared-ways"], default: "corridors", describe: "The plan that gives the highways of the network." },
977
+ changeCost: { type: "number", min: 0, max: 8, step: 0.5, marks: [0, 2, 4], default: 2, describe: "The cost of a change between two highways, in units of the board." },
978
+ interchanges: { type: "integer", min: 1, max: 32, step: 1, marks: [4, 16], default: 16, describe: "The largest number of interchanges." },
979
+ perEdge: { type: "integer", min: 1, max: 3, step: 1, default: 2, describe: "The largest number of highways on the way of one edge." },
980
+ radius: { type: "number", min: 0.5, max: 8, step: 0.5, marks: [1, 2, 4], default: 2, describe: "Two highways get an interchange where they come this near, in units of the board." },
981
+ discount: { type: "number", min: 0.1, max: 1, step: 0.05, marks: [0.3, 0.5, 0.7], default: 0.5, describe: "The cost of a length on a highway against a length off the highways." },
982
+ detour: { type: "number", min: 1, max: 3, step: 0.05, marks: [1.25, 1.5, 2], default: 1.5, describe: "An edge rides the network only when its way is this many times its first route or less." },
983
+ };