@mark1russell7/highways 0.5.0 → 0.5.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.
- package/README.md +43 -2
- package/build/index.d.ts +1472 -63
- package/build/index.d.ts.map +1 -1
- package/build/index.js +10007 -3406
- package/build/index.js.map +1 -1
- package/package.json +11 -2
- package/src/bench/exact/index.ts +72 -11
- package/src/bench/exact/optima-exact-v1-bounds.json +14409 -0
- package/src/bench/exact/optima-exact-v1.json +4809 -0
- package/src/bench/exact/solve.ts +129 -0
- package/src/bench/screen/activation.ts +3 -0
- package/src/bench/screen/bounds.ts +140 -0
- package/src/bench/screen/compare.ts +26 -0
- package/src/bench/screen/exact-set.ts +100 -0
- package/src/bench/screen/exercise.ts +290 -0
- package/src/bench/screen/forms.ts +14 -0
- package/src/bench/screen/gap.ts +316 -0
- package/src/bench/screen/hash.ts +7 -76
- package/src/bench/screen/index.ts +6 -0
- package/src/bench/screen/measures.ts +71 -1
- package/src/bench/screen/portfolio-pick.ts +20 -0
- package/src/bench/screen/screen.ts +50 -2
- package/src/bench/screen/set.ts +3 -2
- package/src/highways/areas/index.ts +160 -0
- package/src/highways/confluent/index.ts +154 -0
- package/src/highways/confluent/k23.test-util.ts +8 -0
- package/src/highways/consensus/index.ts +129 -0
- package/src/highways/crossbars/index.ts +184 -0
- package/src/highways/cubu/index.ts +26 -0
- package/src/highways/divided/index.ts +111 -0
- package/src/highways/fdeb/index.ts +193 -0
- package/src/highways/frechet/index.ts +232 -0
- package/src/highways/hierarchy/index.ts +140 -0
- package/src/highways/index.ts +64 -0
- package/src/highways/kdeeb/index.ts +355 -0
- package/src/highways/link-communities/index.ts +189 -0
- package/src/highways/mesh/index.ts +209 -0
- package/src/highways/mlseb/index.ts +204 -0
- package/src/highways/p-hub/index.ts +248 -0
- package/src/highways/power/index.ts +117 -0
- package/src/highways/resistance/index.ts +159 -0
- package/src/highways/sbeb/index.ts +303 -0
- package/src/highways/scale-space/index.ts +135 -0
- package/src/highways/spectral/index.ts +391 -0
- package/src/highways/territories/index.ts +150 -0
- package/src/highways/trace.ts +153 -0
- package/src/index.ts +1 -0
- package/src/portfolio/bands.ts +33 -0
- package/src/portfolio/fit.ts +29 -0
- package/src/portfolio/index.ts +6 -0
- package/src/portfolio/key.ts +98 -0
- package/src/portfolio/members.ts +171 -0
- package/src/portfolio/router.ts +133 -0
- package/src/portfolio/sets.ts +28 -0
- package/src/strategies/builtins.ts +222 -1
- package/src/strategies/schemas.ts +280 -1
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"directory": "packages/core"
|
|
10
10
|
},
|
|
11
11
|
"homepage": "https://mark1russell7.github.io/highways/",
|
|
12
|
-
"version": "0.5.
|
|
12
|
+
"version": "0.5.1",
|
|
13
13
|
"type": "module",
|
|
14
14
|
"main": "./build/index.js",
|
|
15
15
|
"types": "./build/index.d.ts",
|
|
@@ -28,9 +28,11 @@
|
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@mark1russell7/layout-contract": "^0.2.6"
|
|
33
|
+
},
|
|
31
34
|
"devDependencies": {
|
|
32
35
|
"@mark1russell7/cue": "github:mark1russell7/cue",
|
|
33
|
-
"@mark1russell7/layout-contract": "github:mark1russell7/layout-contract#69933a61b0270c5915b82ab563d24908ade708af&path:/packages/layout-contract",
|
|
34
36
|
"@types/node": "^26.6.4",
|
|
35
37
|
"highs": "^1.15.4",
|
|
36
38
|
"typescript": "^7.0.2",
|
|
@@ -45,6 +47,13 @@
|
|
|
45
47
|
"profile": "node scripts/profile.ts",
|
|
46
48
|
"levels": "node scripts/levels.ts",
|
|
47
49
|
"screen": "node scripts/screen.ts",
|
|
50
|
+
"exact": "node scripts/exact.ts",
|
|
51
|
+
"oracle": "node scripts/oracle.ts",
|
|
52
|
+
"portfolio": "node scripts/portfolio.ts",
|
|
53
|
+
"portfolio:time": "node scripts/portfolio-time.ts",
|
|
54
|
+
"portfolio:sets": "node scripts/portfolio-sets.ts",
|
|
55
|
+
"portfolio:api": "node scripts/portfolio-api-report.ts",
|
|
56
|
+
"bounds": "node scripts/bounds.ts",
|
|
48
57
|
"screen:inputs": "node scripts/screen-inputs.ts",
|
|
49
58
|
"test:watch": "vitest",
|
|
50
59
|
"typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.test.json"
|
package/src/bench/exact/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { dist, type Point } from "../../geom.ts";
|
|
1
|
+
import { dist, polylineLength, type Point } from "../../geom.ts";
|
|
2
2
|
import { edgePlugs, sharedStretches, type KeyedWay } from "../../highways/stretches.ts";
|
|
3
3
|
import type { HighwayPlan } from "../../highways/model.ts";
|
|
4
|
-
import type { Graph } from "../../model.ts";
|
|
4
|
+
import type { Edge, Graph, Route } from "../../model.ts";
|
|
5
5
|
import { byCollection } from "../../routers/trunks.ts";
|
|
6
6
|
import { WayFinder, type WayOptions } from "../../ways.ts";
|
|
7
7
|
|
|
@@ -28,6 +28,8 @@ export interface ExactModel {
|
|
|
28
28
|
readonly rows: number;
|
|
29
29
|
/** The number of edges in the model. An edge without a way in the stretch limit is not in the model. */
|
|
30
30
|
readonly edges: number;
|
|
31
|
+
/** The length of the arc or the link of each binary variable, by its name. A name `x…` is an arc of an edge, and a name `y…` is a link of a key. */
|
|
32
|
+
readonly lengths: ReadonlyMap<string, number>;
|
|
31
33
|
/** This function gives the plan of a solution. `value` gives the value of a variable by its name. */
|
|
32
34
|
decode(value: (name: string) => number): HighwayPlan;
|
|
33
35
|
}
|
|
@@ -54,13 +56,19 @@ function distances(adj: readonly (readonly { to: number; len: number }[])[], sta
|
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
/**
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
*/
|
|
63
|
-
|
|
59
|
+
/** The network of the exact model: the corner graph, plus the point out of each plug of each edge. */
|
|
60
|
+
interface ExactNetwork {
|
|
61
|
+
readonly points: readonly Point[];
|
|
62
|
+
readonly links: readonly { readonly u: number; readonly v: number; readonly len: number }[];
|
|
63
|
+
readonly adj: readonly (readonly { to: number; len: number }[])[];
|
|
64
|
+
/** The two end points of each edge: the points out of its plugs. */
|
|
65
|
+
readonly ends: readonly { readonly edge: Edge; readonly a: number; readonly b: number }[];
|
|
66
|
+
/** The distance from a plug to the point out of it. */
|
|
67
|
+
readonly margin: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** This function makes the network of the exact model for the edges of a graph. */
|
|
71
|
+
function exactNetwork(graph: Graph, o: Readonly<WayOptions>): ExactNetwork {
|
|
64
72
|
const finder = new WayFinder(graph.nodes, { ...(o.margin === undefined ? {} : { margin: o.margin }), ...(o.k === undefined ? {} : { k: o.k }) });
|
|
65
73
|
const corners = finder.corners;
|
|
66
74
|
const k = o.k ?? 8;
|
|
@@ -79,7 +87,7 @@ export function exactModel(graph: Graph, o: Readonly<ExactOptions>): ExactModel
|
|
|
79
87
|
};
|
|
80
88
|
corners.points.forEach((p, i) => ids.set(`${p.x},${p.y}`, i));
|
|
81
89
|
const plugs = edgePlugs(graph);
|
|
82
|
-
const ends = plugs.map(({ edge, ps, pt }) => ({ edge
|
|
90
|
+
const ends = plugs.map(({ edge, ps, pt }) => ({ edge, a: nodeOf(finder.out(ps)), b: nodeOf(finder.out(pt)) }));
|
|
83
91
|
|
|
84
92
|
// The links: each corner to its k nearest visible corners, as in the corner graph, and each end point to its 2k nearest visible corners.
|
|
85
93
|
const linkIds = new Map<string, number>();
|
|
@@ -99,12 +107,25 @@ export function exactModel(graph: Graph, o: Readonly<ExactOptions>): ExactModel
|
|
|
99
107
|
adj[l.u]!.push({ to: l.v, len: l.len });
|
|
100
108
|
adj[l.v]!.push({ to: l.u, len: l.len });
|
|
101
109
|
}
|
|
110
|
+
return { points, links, adj, ends, margin: finder.margin };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* This function gives the model of fixed-charge network design (Magnanti and Wong 1984) for the edges of a graph (HWY-040).
|
|
115
|
+
* The network is the corner graph, plus the point out of each plug. Each link costs its length once for each key that uses it.
|
|
116
|
+
* Each edge goes one way between the points out of its two plugs. The way is `stretch` times its shortest way or shorter.
|
|
117
|
+
* The optimum has the least ink for the stretch limit. The ways of the solution give highways with `sharedStretches`.
|
|
118
|
+
*/
|
|
119
|
+
export function exactModel(graph: Graph, o: Readonly<ExactOptions>): ExactModel {
|
|
120
|
+
const { points, links, adj, ends: outs } = exactNetwork(graph, o);
|
|
121
|
+
const ends = outs.map((e) => ({ edge: e.edge.id, key: o.rule === "all" ? "*" : (byCollection(e.edge) ?? `\u0000${e.edge.id}`), a: e.a, b: e.b }));
|
|
102
122
|
|
|
103
123
|
// The arcs of each edge: the arcs on some way within the stretch limit.
|
|
104
124
|
const eps = o.epsilon ?? 0.001;
|
|
105
125
|
const objective: string[] = [];
|
|
106
126
|
const rows: string[] = [];
|
|
107
127
|
const binaries: string[] = [];
|
|
128
|
+
const lengths = new Map<string, number>();
|
|
108
129
|
const keys = [...new Set(ends.map((e) => e.key))];
|
|
109
130
|
const used = new Map<string, Set<number>>();
|
|
110
131
|
const arcsOf: { e: number; arcs: Arc[] }[] = [];
|
|
@@ -134,6 +155,7 @@ export function exactModel(graph: Graph, o: Readonly<ExactOptions>): ExactModel
|
|
|
134
155
|
for (const a of arcs) {
|
|
135
156
|
const x = `x${ei}_${a.link}_${a.from < a.to ? 0 : 1}`;
|
|
136
157
|
binaries.push(x);
|
|
158
|
+
lengths.set(x, a.len);
|
|
137
159
|
objective.push(`${(eps * a.len).toFixed(6)} ${x}`);
|
|
138
160
|
term(a.from, `+ ${x}`);
|
|
139
161
|
term(a.to, `- ${x}`);
|
|
@@ -156,6 +178,7 @@ export function exactModel(graph: Graph, o: Readonly<ExactOptions>): ExactModel
|
|
|
156
178
|
for (const li of used.get(key) ?? []) {
|
|
157
179
|
const y = `y${ki}_${li}`;
|
|
158
180
|
binaries.push(y);
|
|
181
|
+
lengths.set(y, links[li]!.len);
|
|
159
182
|
objective.push(`${links[li]!.len.toFixed(6)} ${y}`);
|
|
160
183
|
}
|
|
161
184
|
});
|
|
@@ -193,5 +216,43 @@ export function exactModel(graph: Graph, o: Readonly<ExactOptions>): ExactModel
|
|
|
193
216
|
}
|
|
194
217
|
return sharedStretches(ways, { minSize: 2 });
|
|
195
218
|
};
|
|
196
|
-
return { lp, columns: binaries.length, rows: rows.length, edges: arcsOf.length, decode };
|
|
219
|
+
return { lp, columns: binaries.length, rows: rows.length, edges: arcsOf.length, lengths, decode };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* This function gives the stretch of each route as the exact model counts it, by the edge id.
|
|
224
|
+
* The stretch of a route is its length without its two plug ends, divided by the shortest way in the network of the model.
|
|
225
|
+
* The function builds the network one time. The result function then measures each list of routes of the graph, so a portfolio pays for the network once.
|
|
226
|
+
* An edge without a route or without a way in the network has no value.
|
|
227
|
+
*/
|
|
228
|
+
export function exactStretches(graph: Graph, o: Readonly<WayOptions> = {}): (routes: readonly Route[]) => Map<string, number> {
|
|
229
|
+
const { adj, ends, margin } = exactNetwork(graph, o);
|
|
230
|
+
const best = new Map<number, Float64Array>();
|
|
231
|
+
const from = (a: number): Float64Array => {
|
|
232
|
+
if (!best.has(a)) best.set(a, distances(adj, a));
|
|
233
|
+
return best.get(a)!;
|
|
234
|
+
};
|
|
235
|
+
return (routes) => {
|
|
236
|
+
const byEdge = new Map(routes.map((r) => [r.edge, r]));
|
|
237
|
+
const out = new Map<string, number>();
|
|
238
|
+
for (const e of ends) {
|
|
239
|
+
const r = byEdge.get(e.edge.id);
|
|
240
|
+
if (!r || r.points.length < 2 || e.a === e.b) continue;
|
|
241
|
+
const b = from(e.a)[e.b]!;
|
|
242
|
+
if (!Number.isFinite(b) || b <= 1) continue;
|
|
243
|
+
out.set(e.edge.id, (polylineLength(r.points) - 2 * margin) / b);
|
|
244
|
+
}
|
|
245
|
+
return out;
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* This function gives the largest stretch of routes as the exact model counts it (`exactStretches`).
|
|
251
|
+
* The cap of the model is a limit on this value.
|
|
252
|
+
* An edge without a route or without a way in the network does not count. Without such an edge, the value is 1.
|
|
253
|
+
*/
|
|
254
|
+
export function exactStretch(graph: Graph, routes: readonly Route[], o: Readonly<WayOptions> = {}): number {
|
|
255
|
+
let max = 1;
|
|
256
|
+
for (const v of exactStretches(graph, o)(routes).values()) max = Math.max(max, v);
|
|
257
|
+
return max;
|
|
197
258
|
}
|