@statelyai/layout 0.1.3 → 0.3.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.
Files changed (85) hide show
  1. package/NOTICE.md +43 -0
  2. package/README.md +153 -6
  3. package/dist/elkjs/index.cjs +9 -0
  4. package/dist/elkjs/index.d.cts +155 -0
  5. package/dist/elkjs/index.d.mts +51 -39
  6. package/dist/elkjs/index.mjs +3 -1484
  7. package/dist/elkjs/main.cjs +17 -0
  8. package/dist/elkjs/main.d.cts +10 -0
  9. package/dist/elkjs/main.d.mts +11 -0
  10. package/dist/elkjs/main.mjs +17 -0
  11. package/dist/elkjs/worker-api.cjs +3 -0
  12. package/dist/elkjs/worker-api.d.cts +3 -0
  13. package/dist/elkjs/worker-api.d.mts +3 -0
  14. package/dist/elkjs/worker-api.mjs +3 -0
  15. package/dist/elkjs/worker.cjs +86 -0
  16. package/dist/elkjs/worker.d.cts +17 -0
  17. package/dist/elkjs/worker.d.mts +17 -0
  18. package/dist/elkjs/worker.mjs +86 -0
  19. package/dist/elkjs-DaHMISnQ.mjs +1677 -0
  20. package/dist/elkjs-dMghiiWW.cjs +1706 -0
  21. package/dist/index-BEA_pzeT.d.cts +72 -0
  22. package/dist/{index-8xYkohbz.d.mts → index-D9dhxrRl.d.cts} +111 -5
  23. package/dist/index-DNTLRsDl.d.mts +72 -0
  24. package/dist/index-DNixtE3h.d.mts +1318 -0
  25. package/dist/index.cjs +215 -0
  26. package/dist/index.d.cts +78 -0
  27. package/dist/index.d.mts +4 -3
  28. package/dist/index.mjs +25 -25
  29. package/dist/layered/index.cjs +38 -0
  30. package/dist/layered/index.d.cts +3 -0
  31. package/dist/layered/index.d.mts +3 -2
  32. package/dist/layered/index.mjs +1 -1
  33. package/dist/layered-B2buJqMf.cjs +12009 -0
  34. package/dist/{layered-CoeH9LRO.mjs → layered-DGFTeQSl.mjs} +2323 -149
  35. package/dist/{spore-BtTSZbb6.mjs → layout-engine-Cs5tatA6.mjs} +159 -5
  36. package/dist/layout-engine-Dn1PiFwP.cjs +712 -0
  37. package/dist/public-types-9NCPoqbp.d.mts +109 -0
  38. package/dist/public-types-BcRZoJE3.d.cts +109 -0
  39. package/dist/routing/index.cjs +28 -0
  40. package/dist/routing/index.d.cts +3 -0
  41. package/dist/routing/index.d.mts +3 -0
  42. package/dist/routing/index.mjs +3 -0
  43. package/dist/routing-A2hrK9MP.mjs +2396 -0
  44. package/dist/routing-ujEP7Qh6.cjs +2606 -0
  45. package/dist/types-CT2akdK0.d.mts +133 -0
  46. package/dist/types-uxPlGRof.d.cts +133 -0
  47. package/dist/worker-client-BNjwT1AJ.mjs +92 -0
  48. package/dist/worker-client-BwGGRD5y.d.mts +19 -0
  49. package/dist/worker-client-D4oEvhAl.cjs +98 -0
  50. package/dist/worker-client-D4zNyPEI.d.cts +19 -0
  51. package/package.json +45 -10
  52. package/src/authoring/coordinates.ts +114 -0
  53. package/src/authoring/partial.ts +584 -0
  54. package/src/authoring/routing.ts +211 -0
  55. package/src/box.ts +22 -0
  56. package/src/constraints.ts +222 -0
  57. package/src/elkjs/index.ts +104 -39
  58. package/src/elkjs/main.ts +19 -0
  59. package/src/elkjs/public-types.ts +125 -0
  60. package/src/elkjs/routes.ts +147 -0
  61. package/src/elkjs/worker-api.ts +29 -0
  62. package/src/elkjs/worker-client.ts +138 -0
  63. package/src/elkjs/worker.ts +117 -0
  64. package/src/index.ts +19 -0
  65. package/src/internal/elkjs-compatibility.ts +17 -0
  66. package/src/internal/layout-engine.ts +126 -0
  67. package/src/layered/compound.ts +417 -0
  68. package/src/layered/index.ts +58 -105
  69. package/src/layered/types.ts +21 -0
  70. package/src/layout.ts +35 -28
  71. package/src/packing.ts +22 -0
  72. package/src/random.ts +75 -3
  73. package/src/routing/adapters.ts +111 -0
  74. package/src/routing/algorithms.ts +676 -0
  75. package/src/routing/coordination.ts +86 -0
  76. package/src/routing/engine.ts +473 -0
  77. package/src/routing/index.ts +68 -0
  78. package/src/routing/layout-cache.ts +65 -0
  79. package/src/routing/model.ts +218 -0
  80. package/src/routing/path.ts +324 -0
  81. package/src/routing/persistent.ts +117 -0
  82. package/src/routing/search.ts +276 -0
  83. package/src/routing/spatial.ts +78 -0
  84. package/src/routing/types.ts +146 -0
  85. package/src/types.ts +17 -2
@@ -1,19 +1,6 @@
1
- //#region src/errors.ts
2
- var LayoutError = class extends Error {
3
- constructor(message, code) {
4
- super(message);
5
- this.code = code;
6
- this.name = "LayoutError";
7
- }
8
- };
9
- var UnsupportedLayoutError = class extends LayoutError {
10
- constructor(message) {
11
- super(message, "UNSUPPORTED_LAYOUT");
12
- this.name = "UnsupportedLayoutError";
13
- }
14
- };
1
+ import { F as UnsupportedLayoutError, M as routeCrosses, N as routeOrthogonal, P as LayoutError, _ as routeToPolylines, b as recordRouteGeometry, c as orthogonalRouting, j as overlaps, v as nativeGeometry, y as worldGeometry } from "./routing-A2hrK9MP.mjs";
2
+ import { getNodeSize } from "@statelyai/graph/layout";
15
3
 
16
- //#endregion
17
4
  //#region src/java-random.ts
18
5
  /** Java's 48-bit `java.util.Random`, used by ELK for seeded tie-breaking. */
19
6
  var JavaRandom = class JavaRandom {
@@ -3818,6 +3805,2286 @@ function getPolylineMidpoint(points) {
3818
3805
  };
3819
3806
  }
3820
3807
 
3808
+ //#endregion
3809
+ //#region src/layered/compound.ts
3810
+ const paddingOf = (value) => ({
3811
+ top: typeof value === "number" ? value : value?.top ?? 12,
3812
+ right: typeof value === "number" ? value : value?.right ?? 12,
3813
+ bottom: typeof value === "number" ? value : value?.bottom ?? 12,
3814
+ left: typeof value === "number" ? value : value?.left ?? 12
3815
+ });
3816
+ /** Solve each scope's occupied envelope bottom-up; never repair returned sibling positions. */
3817
+ function layoutCompounds(graph, options, flat) {
3818
+ const nodes = graph.nodes.map((node) => {
3819
+ const size = options.measure?.(node);
3820
+ return {
3821
+ ...node,
3822
+ width: size?.width ?? node.width ?? 0,
3823
+ height: size?.height ?? node.height ?? 0
3824
+ };
3825
+ });
3826
+ const byId = new Map(nodes.map((node) => [node.id, node]));
3827
+ const ancestry = (id) => {
3828
+ const chain = [];
3829
+ let current = id;
3830
+ while (current != null) {
3831
+ if (chain.includes(current)) throw new Error(`Cyclic compound hierarchy at ${current}`);
3832
+ chain.push(current);
3833
+ current = byId.get(current)?.parentId ?? null;
3834
+ }
3835
+ return [...chain, null];
3836
+ };
3837
+ const branch = (id, scope) => {
3838
+ const chain = ancestry(id);
3839
+ return chain[chain.indexOf(scope) - 1];
3840
+ };
3841
+ const owner = (edge) => {
3842
+ const a = ancestry(edge.sourceId), b = ancestry(edge.targetId);
3843
+ if (edge.sourceId !== edge.targetId && b.includes(edge.sourceId)) return edge.sourceId;
3844
+ if (edge.sourceId !== edge.targetId && a.includes(edge.targetId)) return edge.targetId;
3845
+ return a.slice(1).find((id) => b.slice(1).includes(id)) ?? null;
3846
+ };
3847
+ const owned = /* @__PURE__ */ new Map();
3848
+ for (const edge of graph.edges) {
3849
+ const scope = owner(edge);
3850
+ owned.set(scope, [...owned.get(scope) ?? [], edge]);
3851
+ }
3852
+ const edges = new Map(graph.edges.map((e) => [e.id, {
3853
+ ...e,
3854
+ x: 0,
3855
+ y: 0,
3856
+ width: e.width ?? 0,
3857
+ height: e.height ?? 0
3858
+ }]));
3859
+ const localLabels = /* @__PURE__ */ new Map();
3860
+ const compoundGeometry = /* @__PURE__ */ new Map();
3861
+ const childScopes = [...new Set(nodes.flatMap((n) => n.parentId == null ? [] : [n.parentId]))].sort((a, b) => ancestry(b).length - ancestry(a).length);
3862
+ const solve = (scope) => {
3863
+ const children = nodes.filter((n) => (n.parentId ?? null) === scope);
3864
+ if (!children.length) return;
3865
+ const container = scope == null ? void 0 : byId.get(scope);
3866
+ const config = container && options.compound?.(container);
3867
+ const direction = config?.direction ?? options.direction ?? graph.direction ?? "right";
3868
+ const horizontal = direction === "left" || direction === "right";
3869
+ const padding = paddingOf(config?.padding ?? options.padding);
3870
+ const insets = { ...padding };
3871
+ const header = config?.header;
3872
+ const side = header?.side ?? "top";
3873
+ if (header) insets[side] += side === "top" || side === "bottom" ? header.height : header.width;
3874
+ const scopeEdges = owned.get(scope) ?? [];
3875
+ const boundary = /* @__PURE__ */ new Map();
3876
+ const projected = [];
3877
+ for (const edge of scopeEdges) if (edge.sourceId === scope || edge.targetId === scope) {
3878
+ const id = branch(edge.sourceId === scope ? edge.targetId : edge.sourceId, scope);
3879
+ boundary.set(id, [...boundary.get(id) ?? [], edge]);
3880
+ } else projected.push({
3881
+ ...edge,
3882
+ sourceId: branch(edge.sourceId, scope),
3883
+ targetId: branch(edge.targetId, scope),
3884
+ points: void 0
3885
+ });
3886
+ const gap = options.settings?.["spacing.labelNode"] ?? options.spacing?.node ?? 20;
3887
+ const labelGap = options.settings?.["spacing.labelLabel"] ?? 8;
3888
+ const sizes = new Map(children.map((n) => {
3889
+ const labels$1 = boundary.get(n.id) ?? [];
3890
+ const labelWidth = Math.max(0, ...labels$1.map((e) => e.width ?? 0));
3891
+ const labelHeight = labels$1.reduce((sum, e) => sum + (e.height ?? 0), 0) + Math.max(0, labels$1.length - 1) * labelGap;
3892
+ return [n.id, {
3893
+ width: labels$1.length && !horizontal ? n.width + gap + labelWidth : Math.max(n.width, labelWidth),
3894
+ height: labels$1.length && horizontal ? n.height + gap + labelHeight : Math.max(n.height, labelHeight)
3895
+ }];
3896
+ }));
3897
+ const labels = projected.filter((edge) => (edge.width ?? 0) > 0 && (edge.height ?? 0) > 0);
3898
+ const used = new Set([...graph.nodes, ...graph.edges].map((entity) => entity.id));
3899
+ const labelIds = /* @__PURE__ */ new Map();
3900
+ for (const edge of labels) {
3901
+ let id = `__layout_label_${edge.id}`;
3902
+ while ([
3903
+ id,
3904
+ `${id}_source`,
3905
+ `${id}_target`
3906
+ ].some((key) => used.has(key))) id += "_";
3907
+ for (const key of [
3908
+ id,
3909
+ `${id}_source`,
3910
+ `${id}_target`
3911
+ ]) used.add(key);
3912
+ labelIds.set(edge.id, id);
3913
+ sizes.set(id, {
3914
+ width: edge.width,
3915
+ height: edge.height
3916
+ });
3917
+ }
3918
+ const originalEdges = new Map(graph.edges.map((edge) => [edge.id, edge]));
3919
+ for (const edge of labels) {
3920
+ originalEdges.set(`${labelIds.get(edge.id)}_source`, edges.get(edge.id));
3921
+ originalEdges.set(`${labelIds.get(edge.id)}_target`, edges.get(edge.id));
3922
+ }
3923
+ const placementOrder = new Map(children.map((node, index) => [node.id, index]));
3924
+ for (const edge of labels) placementOrder.set(labelIds.get(edge.id), ((placementOrder.get(edge.sourceId) ?? 0) + (placementOrder.get(edge.targetId) ?? 0)) / 2 + (edge.sourceId === edge.targetId ? .25 : 0));
3925
+ const result$1 = flat({
3926
+ ...graph,
3927
+ nodes: [...children.map((n) => ({
3928
+ ...n,
3929
+ parentId: null
3930
+ })), ...labels.map((edge) => ({
3931
+ type: "node",
3932
+ id: labelIds.get(edge.id),
3933
+ data: void 0
3934
+ }))].sort((a, b) => placementOrder.get(a.id) - placementOrder.get(b.id)),
3935
+ edges: projected.flatMap((edge) => {
3936
+ const labelId = labelIds.get(edge.id);
3937
+ return labelId ? [{
3938
+ ...edge,
3939
+ id: `${labelId}_source`,
3940
+ targetId: labelId,
3941
+ targetPort: void 0,
3942
+ width: 0,
3943
+ height: 0
3944
+ }, {
3945
+ ...edge,
3946
+ id: `${labelId}_target`,
3947
+ sourceId: labelId,
3948
+ sourcePort: void 0,
3949
+ width: 0,
3950
+ height: 0
3951
+ }] : [edge];
3952
+ })
3953
+ }, {
3954
+ ...options,
3955
+ compound: void 0,
3956
+ direction,
3957
+ padding: insets,
3958
+ measure: (node) => sizes.get(node.id),
3959
+ nodeSettings: (node) => {
3960
+ const original = byId.get(node.id);
3961
+ return original ? options.nodeSettings?.(original) : void 0;
3962
+ },
3963
+ edgeSettings: (edge) => options.edgeSettings?.(originalEdges.get(edge.id) ?? edge)
3964
+ });
3965
+ for (const placed of result$1.nodes) {
3966
+ const node = byId.get(placed.id);
3967
+ if (node) Object.assign(node, {
3968
+ x: placed.x,
3969
+ y: placed.y,
3970
+ ports: placed.ports
3971
+ });
3972
+ }
3973
+ for (const edge of projected) {
3974
+ const labelId = labelIds.get(edge.id);
3975
+ if (labelId) {
3976
+ const label = result$1.nodes.find((n) => n.id === labelId);
3977
+ localLabels.set(edge.id, {
3978
+ scope,
3979
+ rect: {
3980
+ x: label.x,
3981
+ y: label.y,
3982
+ width: label.width,
3983
+ height: label.height
3984
+ }
3985
+ });
3986
+ }
3987
+ }
3988
+ for (const [id, labels$1] of boundary) {
3989
+ const node = byId.get(id);
3990
+ const totalHeight = labels$1.reduce((sum, e) => sum + (e.height ?? 0), 0) + Math.max(0, labels$1.length - 1) * labelGap;
3991
+ let cross = horizontal ? 0 : (Math.max(node.height, totalHeight) - totalHeight) / 2;
3992
+ for (const edge of labels$1) {
3993
+ const width = edge.width ?? 0, height = edge.height ?? 0;
3994
+ localLabels.set(edge.id, {
3995
+ scope,
3996
+ rect: {
3997
+ x: node.x + (horizontal ? (Math.max(node.width, width) - width) / 2 : node.width + gap),
3998
+ y: node.y + (horizontal ? node.height + gap : 0) + cross,
3999
+ width,
4000
+ height
4001
+ }
4002
+ });
4003
+ cross += height + labelGap;
4004
+ }
4005
+ }
4006
+ const boxes = [...children.map((n) => ({
4007
+ x: n.x,
4008
+ y: n.y,
4009
+ ...sizes.get(n.id)
4010
+ })), ...[...localLabels.values()].filter((l) => l.scope === scope).map((l) => l.rect)];
4011
+ let dx = Math.max(0, insets.left - Math.min(...boxes.map((b) => b.x)));
4012
+ let dy = Math.max(0, insets.top - Math.min(...boxes.map((b) => b.y)));
4013
+ if (header && (side === "top" || side === "bottom")) {
4014
+ const occupiedWidth = Math.max(...boxes.map((b) => b.x + b.width)) - Math.min(...boxes.map((b) => b.x)) + padding.left + padding.right;
4015
+ dx += Math.max(0, (header.width - occupiedWidth) / 2);
4016
+ }
4017
+ if (header && (side === "left" || side === "right")) {
4018
+ const occupiedHeight = Math.max(...boxes.map((b) => b.y + b.height)) - Math.min(...boxes.map((b) => b.y)) + padding.top + padding.bottom;
4019
+ dy += Math.max(0, (header.height - occupiedHeight) / 2);
4020
+ }
4021
+ const right = Math.max(...boxes.map((b) => b.x + dx + b.width));
4022
+ const bottom = Math.max(...boxes.map((b) => b.y + dy + b.height));
4023
+ for (const n of children) {
4024
+ n.x += dx;
4025
+ n.y += dy;
4026
+ }
4027
+ for (const l of localLabels.values()) if (l.scope === scope) {
4028
+ l.rect.x += dx;
4029
+ l.rect.y += dy;
4030
+ }
4031
+ if (container) {
4032
+ const width = Math.max(header?.width ?? 0, config?.minContentSize?.width ? config.minContentSize.width + insets.left + insets.right : 0, right + insets.right);
4033
+ const height = Math.max(header?.height ?? 0, config?.minContentSize?.height ? config.minContentSize.height + insets.top + insets.bottom : 0, bottom + insets.bottom);
4034
+ container.width = Math.max(container.width, width);
4035
+ container.height = Math.max(container.height, height);
4036
+ compoundGeometry.set(container.id, {
4037
+ bounds: {
4038
+ x: 0,
4039
+ y: 0,
4040
+ width: container.width,
4041
+ height: container.height
4042
+ },
4043
+ content: {
4044
+ x: insets.left,
4045
+ y: insets.top,
4046
+ width: container.width - insets.left - insets.right,
4047
+ height: container.height - insets.top - insets.bottom
4048
+ },
4049
+ ...header ? { header: {
4050
+ x: side === "right" ? container.width - header.width : 0,
4051
+ y: side === "bottom" ? container.height - header.height : 0,
4052
+ width: side === "top" || side === "bottom" ? container.width : header.width,
4053
+ height: side === "left" || side === "right" ? container.height : header.height
4054
+ } } : {}
4055
+ });
4056
+ }
4057
+ };
4058
+ for (const scope of childScopes) solve(scope);
4059
+ const roots = nodes.filter((n) => n.parentId == null);
4060
+ if (roots.length === 1 && compoundGeometry.has(roots[0].id) && !owned.get(null)?.length) Object.assign(roots[0], {
4061
+ x: 0,
4062
+ y: 0
4063
+ });
4064
+ else solve(null);
4065
+ const origin = (id) => {
4066
+ if (id == null) return {
4067
+ x: 0,
4068
+ y: 0
4069
+ };
4070
+ return ancestry(id).slice(0, -1).reduce((p, key) => ({
4071
+ x: p.x + byId.get(key).x,
4072
+ y: p.y + byId.get(key).y
4073
+ }), {
4074
+ x: 0,
4075
+ y: 0
4076
+ });
4077
+ };
4078
+ for (const [id, label] of localLabels) {
4079
+ const offset = origin(label.scope);
4080
+ Object.assign(edges.get(id), {
4081
+ ...label.rect,
4082
+ x: label.rect.x + offset.x,
4083
+ y: label.rect.y + offset.y
4084
+ });
4085
+ }
4086
+ const attachmentSettings = {};
4087
+ for (const edge of edges.values()) {
4088
+ const sourceGeometry = compoundGeometry.get(edge.sourceId), targetGeometry = compoundGeometry.get(edge.targetId);
4089
+ const intent = options.edgeAttachment?.(edge);
4090
+ attachmentSettings[edge.id] = {
4091
+ ...sourceGeometry && edge.sourceId !== edge.targetId && ancestry(edge.targetId).includes(edge.sourceId) ? { sourceAttachment: {
4092
+ bounds: intent?.source === "outer" ? {
4093
+ x: 0,
4094
+ y: 0,
4095
+ width: sourceGeometry.bounds.width,
4096
+ height: sourceGeometry.bounds.height
4097
+ } : sourceGeometry.content,
4098
+ facing: intent?.source === "outer" ? "outward" : "inward"
4099
+ } } : {},
4100
+ ...targetGeometry && intent?.target === "content" ? { targetAttachment: {
4101
+ bounds: targetGeometry.content,
4102
+ facing: "inward"
4103
+ } } : {}
4104
+ };
4105
+ }
4106
+ const worldNodes = nodes.map((n) => ({
4107
+ ...n,
4108
+ ...origin(n.id)
4109
+ }));
4110
+ const usedIds = new Set(nodes.map((n) => n.id));
4111
+ const headers = [...compoundGeometry].flatMap(([id, geometry]) => {
4112
+ if (!geometry.header) return [];
4113
+ const p = origin(id);
4114
+ let key = `__layout_header_${id}`;
4115
+ while (usedIds.has(key)) key += "_";
4116
+ usedIds.add(key);
4117
+ return [{
4118
+ type: "node",
4119
+ id: key,
4120
+ parentId: id,
4121
+ data: void 0,
4122
+ ...geometry.header,
4123
+ x: p.x + geometry.header.x,
4124
+ y: p.y + geometry.header.y
4125
+ }];
4126
+ });
4127
+ const snapshot = orthogonalRouting.route({
4128
+ ...graph,
4129
+ nodes: [...worldNodes, ...headers],
4130
+ edges: [...edges.values()]
4131
+ }, {
4132
+ coordinateSpace: "world",
4133
+ edges: attachmentSettings
4134
+ });
4135
+ for (const [id, route] of snapshot.routes) {
4136
+ const polylines = routeToPolylines(route);
4137
+ Object.assign(edges.get(id), {
4138
+ points: polylines.flatMap((p) => p.map((point) => ({ ...point }))),
4139
+ routing: "orthogonal"
4140
+ });
4141
+ }
4142
+ for (const [id, geometry] of compoundGeometry) geometry.bounds = {
4143
+ ...geometry.bounds,
4144
+ x: byId.get(id).x,
4145
+ y: byId.get(id).y
4146
+ };
4147
+ const result = {
4148
+ ...graph,
4149
+ edgeCoordinateSpace: "world",
4150
+ direction: options.direction ?? graph.direction ?? "right",
4151
+ nodes,
4152
+ edges: graph.edges.map((e) => edges.get(e.id)),
4153
+ compoundGeometry,
4154
+ compoundRoutes: snapshot.routes
4155
+ };
4156
+ recordRouteGeometry(result, snapshot.routes);
4157
+ return result;
4158
+ }
4159
+
4160
+ //#endregion
4161
+ //#region node_modules/.pnpm/@lume+kiwi@0.4.4/node_modules/@lume/kiwi/dist/maptype.js
4162
+ function createMap() {
4163
+ return new IndexedMap();
4164
+ }
4165
+ var IndexedMap = class IndexedMap {
4166
+ index = {};
4167
+ array = [];
4168
+ /**
4169
+ * Returns the number of items in the array.
4170
+ */
4171
+ size() {
4172
+ return this.array.length;
4173
+ }
4174
+ /**
4175
+ * Returns true if the array is empty.
4176
+ */
4177
+ empty() {
4178
+ return this.array.length === 0;
4179
+ }
4180
+ /**
4181
+ * Returns the item at the given array index.
4182
+ *
4183
+ * @param index The integer index of the desired item.
4184
+ */
4185
+ itemAt(index) {
4186
+ return this.array[index];
4187
+ }
4188
+ /**
4189
+ * Returns true if the key is in the array, false otherwise.
4190
+ *
4191
+ * @param key The key to locate in the array.
4192
+ */
4193
+ contains(key) {
4194
+ return this.index[key.id()] !== void 0;
4195
+ }
4196
+ /**
4197
+ * Returns the pair associated with the given key, or undefined.
4198
+ *
4199
+ * @param key The key to locate in the array.
4200
+ */
4201
+ find(key) {
4202
+ const i = this.index[key.id()];
4203
+ return i === void 0 ? void 0 : this.array[i];
4204
+ }
4205
+ /**
4206
+ * Returns the pair associated with the key if it exists.
4207
+ *
4208
+ * If the key does not exist, a new pair will be created and
4209
+ * inserted using the value created by the given factory.
4210
+ *
4211
+ * @param key The key to locate in the array.
4212
+ * @param factory The function which creates the default value.
4213
+ */
4214
+ setDefault(key, factory) {
4215
+ const i = this.index[key.id()];
4216
+ if (i === void 0) {
4217
+ const pair = new Pair(key, factory());
4218
+ this.index[key.id()] = this.array.length;
4219
+ this.array.push(pair);
4220
+ return pair;
4221
+ } else return this.array[i];
4222
+ }
4223
+ /**
4224
+ * Insert the pair into the array and return the pair.
4225
+ *
4226
+ * This will overwrite any existing entry in the array.
4227
+ *
4228
+ * @param key The key portion of the pair.
4229
+ * @param value The value portion of the pair.
4230
+ */
4231
+ insert(key, value) {
4232
+ const pair = new Pair(key, value);
4233
+ const i = this.index[key.id()];
4234
+ if (i === void 0) {
4235
+ this.index[key.id()] = this.array.length;
4236
+ this.array.push(pair);
4237
+ } else this.array[i] = pair;
4238
+ return pair;
4239
+ }
4240
+ /**
4241
+ * Removes and returns the pair for the given key, or undefined.
4242
+ *
4243
+ * @param key The key to remove from the map.
4244
+ */
4245
+ erase(key) {
4246
+ const i = this.index[key.id()];
4247
+ if (i === void 0) return;
4248
+ this.index[key.id()] = void 0;
4249
+ const pair = this.array[i];
4250
+ const last = this.array.pop();
4251
+ if (pair !== last) {
4252
+ this.array[i] = last;
4253
+ this.index[last.first.id()] = i;
4254
+ }
4255
+ return pair;
4256
+ }
4257
+ /**
4258
+ * Create a copy of this associative array.
4259
+ */
4260
+ copy() {
4261
+ const copy = new IndexedMap();
4262
+ for (let i = 0; i < this.array.length; i++) {
4263
+ const pair = this.array[i].copy();
4264
+ copy.array[i] = pair;
4265
+ copy.index[pair.first.id()] = i;
4266
+ }
4267
+ return copy;
4268
+ }
4269
+ };
4270
+ /**
4271
+ * A class which defines a generic pair object.
4272
+ * @private
4273
+ */
4274
+ var Pair = class Pair {
4275
+ first;
4276
+ second;
4277
+ /**
4278
+ * Construct a new Pair object.
4279
+ *
4280
+ * @param first The first item of the pair.
4281
+ * @param second The second item of the pair.
4282
+ */
4283
+ constructor(first, second) {
4284
+ this.first = first;
4285
+ this.second = second;
4286
+ }
4287
+ /**
4288
+ * Create a copy of the pair.
4289
+ */
4290
+ copy() {
4291
+ return new Pair(this.first, this.second);
4292
+ }
4293
+ };
4294
+
4295
+ //#endregion
4296
+ //#region node_modules/.pnpm/@lume+kiwi@0.4.4/node_modules/@lume/kiwi/dist/variable.js
4297
+ /**
4298
+ * The primary user constraint variable.
4299
+ *
4300
+ * @class
4301
+ * @param {String} [name=""] The name to associated with the variable.
4302
+ */
4303
+ var Variable = class {
4304
+ constructor(name = "") {
4305
+ this._name = name;
4306
+ }
4307
+ /**
4308
+ * Returns the unique id number of the variable.
4309
+ * @private
4310
+ */
4311
+ id() {
4312
+ return this._id;
4313
+ }
4314
+ /**
4315
+ * Returns the name of the variable.
4316
+ *
4317
+ * @return {String} name of the variable
4318
+ */
4319
+ name() {
4320
+ return this._name;
4321
+ }
4322
+ /**
4323
+ * Set the name of the variable.
4324
+ *
4325
+ * @param {String} name Name of the variable
4326
+ */
4327
+ setName(name) {
4328
+ this._name = name;
4329
+ }
4330
+ /**
4331
+ * Returns the user context object of the variable.
4332
+ * @private
4333
+ */
4334
+ context() {
4335
+ return this._context;
4336
+ }
4337
+ /**
4338
+ * Set the user context object of the variable.
4339
+ * @private
4340
+ */
4341
+ setContext(context) {
4342
+ this._context = context;
4343
+ }
4344
+ /**
4345
+ * Returns the value of the variable.
4346
+ *
4347
+ * @return {Number} Calculated value
4348
+ */
4349
+ value() {
4350
+ return this._value;
4351
+ }
4352
+ /**
4353
+ * Set the value of the variable.
4354
+ * @private
4355
+ */
4356
+ setValue(value) {
4357
+ this._value = value;
4358
+ }
4359
+ /**
4360
+ * Creates a new Expression by adding a number, variable or expression
4361
+ * to the variable.
4362
+ *
4363
+ * @param {Number|Variable|Expression} value Value to add.
4364
+ * @return {Expression} expression
4365
+ */
4366
+ plus(value) {
4367
+ return new Expression(this, value);
4368
+ }
4369
+ /**
4370
+ * Creates a new Expression by substracting a number, variable or expression
4371
+ * from the variable.
4372
+ *
4373
+ * @param {Number|Variable|Expression} value Value to substract.
4374
+ * @return {Expression} expression
4375
+ */
4376
+ minus(value) {
4377
+ return new Expression(this, typeof value === "number" ? -value : [-1, value]);
4378
+ }
4379
+ /**
4380
+ * Creates a new Expression by multiplying with a fixed number.
4381
+ *
4382
+ * @param {Number} coefficient Coefficient to multiply with.
4383
+ * @return {Expression} expression
4384
+ */
4385
+ multiply(coefficient) {
4386
+ return new Expression([coefficient, this]);
4387
+ }
4388
+ /**
4389
+ * Creates a new Expression by dividing with a fixed number.
4390
+ *
4391
+ * @param {Number} coefficient Coefficient to divide by.
4392
+ * @return {Expression} expression
4393
+ */
4394
+ divide(coefficient) {
4395
+ return new Expression([1 / coefficient, this]);
4396
+ }
4397
+ /**
4398
+ * Returns the JSON representation of the variable.
4399
+ * @private
4400
+ */
4401
+ toJSON() {
4402
+ return {
4403
+ name: this._name,
4404
+ value: this._value
4405
+ };
4406
+ }
4407
+ toString() {
4408
+ return this._context + "[" + this._name + ":" + this._value + "]";
4409
+ }
4410
+ _name;
4411
+ _value = 0;
4412
+ _context = null;
4413
+ _id = VarId++;
4414
+ };
4415
+ /**
4416
+ * The internal variable id counter.
4417
+ * @private
4418
+ */
4419
+ let VarId = 0;
4420
+
4421
+ //#endregion
4422
+ //#region node_modules/.pnpm/@lume+kiwi@0.4.4/node_modules/@lume/kiwi/dist/expression.js
4423
+ /**
4424
+ * An expression of variable terms and a constant.
4425
+ *
4426
+ * The constructor accepts an arbitrary number of parameters,
4427
+ * each of which must be one of the following types:
4428
+ * - number
4429
+ * - Variable
4430
+ * - Expression
4431
+ * - 2-tuple of [number, Variable|Expression]
4432
+ *
4433
+ * The parameters are summed. The tuples are multiplied.
4434
+ *
4435
+ * @class
4436
+ * @param {...(number|Variable|Expression|Array)} args
4437
+ */
4438
+ var Expression = class Expression {
4439
+ constructor() {
4440
+ let parsed = parseArgs(arguments);
4441
+ this._terms = parsed.terms;
4442
+ this._constant = parsed.constant;
4443
+ }
4444
+ /**
4445
+ * Returns the mapping of terms in the expression.
4446
+ *
4447
+ * This *must* be treated as const.
4448
+ * @private
4449
+ */
4450
+ terms() {
4451
+ return this._terms;
4452
+ }
4453
+ /**
4454
+ * Returns the constant of the expression.
4455
+ * @private
4456
+ */
4457
+ constant() {
4458
+ return this._constant;
4459
+ }
4460
+ /**
4461
+ * Returns the computed value of the expression.
4462
+ *
4463
+ * @private
4464
+ * @return {Number} computed value of the expression
4465
+ */
4466
+ value() {
4467
+ let result = this._constant;
4468
+ for (let i = 0, n = this._terms.size(); i < n; i++) {
4469
+ let pair = this._terms.itemAt(i);
4470
+ result += pair.first.value() * pair.second;
4471
+ }
4472
+ return result;
4473
+ }
4474
+ /**
4475
+ * Creates a new Expression by adding a number, variable or expression
4476
+ * to the expression.
4477
+ *
4478
+ * @param {Number|Variable|Expression} value Value to add.
4479
+ * @return {Expression} expression
4480
+ */
4481
+ plus(value) {
4482
+ return new Expression(this, value);
4483
+ }
4484
+ /**
4485
+ * Creates a new Expression by substracting a number, variable or expression
4486
+ * from the expression.
4487
+ *
4488
+ * @param {Number|Variable|Expression} value Value to substract.
4489
+ * @return {Expression} expression
4490
+ */
4491
+ minus(value) {
4492
+ return new Expression(this, typeof value === "number" ? -value : [-1, value]);
4493
+ }
4494
+ /**
4495
+ * Creates a new Expression by multiplying with a fixed number.
4496
+ *
4497
+ * @param {Number} coefficient Coefficient to multiply with.
4498
+ * @return {Expression} expression
4499
+ */
4500
+ multiply(coefficient) {
4501
+ return new Expression([coefficient, this]);
4502
+ }
4503
+ /**
4504
+ * Creates a new Expression by dividing with a fixed number.
4505
+ *
4506
+ * @param {Number} coefficient Coefficient to divide by.
4507
+ * @return {Expression} expression
4508
+ */
4509
+ divide(coefficient) {
4510
+ return new Expression([1 / coefficient, this]);
4511
+ }
4512
+ isConstant() {
4513
+ return this._terms.size() == 0;
4514
+ }
4515
+ toString() {
4516
+ let result = this._terms.array.map(function(pair) {
4517
+ return pair.second + "*" + pair.first.toString();
4518
+ }).join(" + ");
4519
+ if (!this.isConstant() && this._constant !== 0) result += " + ";
4520
+ result += this._constant;
4521
+ return result;
4522
+ }
4523
+ _terms;
4524
+ _constant;
4525
+ };
4526
+ /**
4527
+ * An internal argument parsing function.
4528
+ * @private
4529
+ */
4530
+ function parseArgs(args) {
4531
+ let constant = 0;
4532
+ let factory = () => 0;
4533
+ let terms = createMap();
4534
+ for (let i = 0, n = args.length; i < n; ++i) {
4535
+ let item = args[i];
4536
+ if (typeof item === "number") constant += item;
4537
+ else if (item instanceof Variable) terms.setDefault(item, factory).second += 1;
4538
+ else if (item instanceof Expression) {
4539
+ constant += item.constant();
4540
+ let terms2 = item.terms();
4541
+ for (let j = 0, k = terms2.size(); j < k; j++) {
4542
+ let termPair = terms2.itemAt(j);
4543
+ terms.setDefault(termPair.first, factory).second += termPair.second;
4544
+ }
4545
+ } else if (item instanceof Array) {
4546
+ if (item.length !== 2) throw new Error("array must have length 2");
4547
+ let value = item[0];
4548
+ let value2 = item[1];
4549
+ if (typeof value !== "number") throw new Error("array item 0 must be a number");
4550
+ if (value2 instanceof Variable) terms.setDefault(value2, factory).second += value;
4551
+ else if (value2 instanceof Expression) {
4552
+ constant += value2.constant() * value;
4553
+ let terms2 = value2.terms();
4554
+ for (let j = 0, k = terms2.size(); j < k; j++) {
4555
+ let termPair = terms2.itemAt(j);
4556
+ terms.setDefault(termPair.first, factory).second += termPair.second * value;
4557
+ }
4558
+ } else throw new Error("array item 1 must be a variable or expression");
4559
+ } else throw new Error("invalid Expression argument: " + item);
4560
+ }
4561
+ return {
4562
+ terms,
4563
+ constant
4564
+ };
4565
+ }
4566
+
4567
+ //#endregion
4568
+ //#region node_modules/.pnpm/@lume+kiwi@0.4.4/node_modules/@lume/kiwi/dist/strength.js
4569
+ /**
4570
+ * @class Strength
4571
+ */
4572
+ var Strength = class Strength {
4573
+ /**
4574
+ * Create a new symbolic strength.
4575
+ *
4576
+ * @param a strong
4577
+ * @param b medium
4578
+ * @param c weak
4579
+ * @param [w] weight
4580
+ * @return strength
4581
+ */
4582
+ static create(a, b, c$1, w = 1) {
4583
+ let result = 0;
4584
+ result += Math.max(0, Math.min(1e3, a * w)) * 1e6;
4585
+ result += Math.max(0, Math.min(1e3, b * w)) * 1e3;
4586
+ result += Math.max(0, Math.min(1e3, c$1 * w));
4587
+ return result;
4588
+ }
4589
+ /**
4590
+ * The 'required' symbolic strength.
4591
+ */
4592
+ static required = Strength.create(1e3, 1e3, 1e3);
4593
+ /**
4594
+ * The 'strong' symbolic strength.
4595
+ */
4596
+ static strong = Strength.create(1, 0, 0);
4597
+ /**
4598
+ * The 'medium' symbolic strength.
4599
+ */
4600
+ static medium = Strength.create(0, 1, 0);
4601
+ /**
4602
+ * The 'weak' symbolic strength.
4603
+ */
4604
+ static weak = Strength.create(0, 0, 1);
4605
+ /**
4606
+ * Clip a symbolic strength to the allowed min and max.
4607
+ * @private
4608
+ */
4609
+ static clip(value) {
4610
+ return Math.max(0, Math.min(Strength.required, value));
4611
+ }
4612
+ };
4613
+
4614
+ //#endregion
4615
+ //#region node_modules/.pnpm/@lume+kiwi@0.4.4/node_modules/@lume/kiwi/dist/constraint.js
4616
+ /**
4617
+ * An enum defining the linear constraint operators.
4618
+ *
4619
+ * |Value|Operator|Description|
4620
+ * |----|-----|-----|
4621
+ * |`Le`|<=|Less than equal|
4622
+ * |`Ge`|>=|Greater than equal|
4623
+ * |`Eq`|==|Equal|
4624
+ *
4625
+ * @enum {Number}
4626
+ */
4627
+ var Operator;
4628
+ (function(Operator$1) {
4629
+ Operator$1[Operator$1["Le"] = 0] = "Le";
4630
+ Operator$1[Operator$1["Ge"] = 1] = "Ge";
4631
+ Operator$1[Operator$1["Eq"] = 2] = "Eq";
4632
+ })(Operator || (Operator = {}));
4633
+ /**
4634
+ * A linear constraint equation.
4635
+ *
4636
+ * A constraint equation is composed of an expression, an operator,
4637
+ * and a strength. The RHS of the equation is implicitly zero.
4638
+ *
4639
+ * @class
4640
+ * @param {Expression} expression The constraint expression (LHS).
4641
+ * @param {Operator} operator The equation operator.
4642
+ * @param {Expression} [rhs] Right hand side of the expression.
4643
+ * @param {Number} [strength=Strength.required] The strength of the constraint.
4644
+ */
4645
+ var Constraint = class {
4646
+ constructor(expression, operator, rhs, strength = Strength.required) {
4647
+ this._operator = operator;
4648
+ this._strength = Strength.clip(strength);
4649
+ if (rhs === void 0 && expression instanceof Expression) this._expression = expression;
4650
+ else this._expression = expression.minus(rhs);
4651
+ }
4652
+ /**
4653
+ * Returns the unique id number of the constraint.
4654
+ * @private
4655
+ */
4656
+ id() {
4657
+ return this._id;
4658
+ }
4659
+ /**
4660
+ * Returns the expression of the constraint.
4661
+ *
4662
+ * @return {Expression} expression
4663
+ */
4664
+ expression() {
4665
+ return this._expression;
4666
+ }
4667
+ /**
4668
+ * Returns the relational operator of the constraint.
4669
+ *
4670
+ * @return {Operator} linear constraint operator
4671
+ */
4672
+ op() {
4673
+ return this._operator;
4674
+ }
4675
+ /**
4676
+ * Returns the strength of the constraint.
4677
+ *
4678
+ * @return {Number} strength
4679
+ */
4680
+ strength() {
4681
+ return this._strength;
4682
+ }
4683
+ toString() {
4684
+ return this._expression.toString() + " " + [
4685
+ "<=",
4686
+ ">=",
4687
+ "="
4688
+ ][this._operator] + " 0 (" + this._strength.toString() + ")";
4689
+ }
4690
+ _expression;
4691
+ _operator;
4692
+ _strength;
4693
+ _id = CnId++;
4694
+ };
4695
+ /**
4696
+ * The internal constraint id counter.
4697
+ * @private
4698
+ */
4699
+ let CnId = 0;
4700
+
4701
+ //#endregion
4702
+ //#region node_modules/.pnpm/@lume+kiwi@0.4.4/node_modules/@lume/kiwi/dist/solver.js
4703
+ /**
4704
+ * The constraint solver class.
4705
+ *
4706
+ * @class
4707
+ */
4708
+ var Solver = class {
4709
+ /**
4710
+ * @type {number} - The max number of solver iterations before an error
4711
+ * is thrown, in order to prevent infinite iteration. Default: `10,000`.
4712
+ */
4713
+ maxIterations = 1e3;
4714
+ /**
4715
+ * Construct a new Solver.
4716
+ */
4717
+ constructor() {}
4718
+ /**
4719
+ * Creates and add a constraint to the solver.
4720
+ *
4721
+ * @param {Expression|Variable} lhs Left hand side of the expression
4722
+ * @param {Operator} operator Operator
4723
+ * @param {Expression|Variable|Number} rhs Right hand side of the expression
4724
+ * @param {Number} [strength=Strength.required] Strength
4725
+ */
4726
+ createConstraint(lhs, operator, rhs, strength = Strength.required) {
4727
+ let cn = new Constraint(lhs, operator, rhs, strength);
4728
+ this.addConstraint(cn);
4729
+ return cn;
4730
+ }
4731
+ /**
4732
+ * Add a constraint to the solver.
4733
+ *
4734
+ * @param {Constraint} constraint Constraint to add to the solver
4735
+ */
4736
+ addConstraint(constraint) {
4737
+ if (this._cnMap.find(constraint) !== void 0) throw new Error("duplicate constraint");
4738
+ let data = this._createRow(constraint);
4739
+ let row = data.row;
4740
+ let tag = data.tag;
4741
+ let subject = this._chooseSubject(row, tag);
4742
+ if (subject.type() === SymbolType.Invalid && row.allDummies()) if (!nearZero(row.constant())) throw new Error("unsatisfiable constraint");
4743
+ else subject = tag.marker;
4744
+ if (subject.type() === SymbolType.Invalid) {
4745
+ if (!this._addWithArtificialVariable(row)) throw new Error("unsatisfiable constraint");
4746
+ } else {
4747
+ row.solveFor(subject);
4748
+ this._substitute(subject, row);
4749
+ this._rowMap.insert(subject, row);
4750
+ }
4751
+ this._cnMap.insert(constraint, tag);
4752
+ this._optimize(this._objective);
4753
+ }
4754
+ /**
4755
+ * Remove a constraint from the solver.
4756
+ *
4757
+ * @param {Constraint} constraint Constraint to remove from the solver
4758
+ */
4759
+ removeConstraint(constraint) {
4760
+ let cnPair = this._cnMap.erase(constraint);
4761
+ if (cnPair === void 0) throw new Error("unknown constraint");
4762
+ this._removeConstraintEffects(constraint, cnPair.second);
4763
+ let marker = cnPair.second.marker;
4764
+ let rowPair = this._rowMap.erase(marker);
4765
+ if (rowPair === void 0) {
4766
+ let leaving = this._getMarkerLeavingSymbol(marker);
4767
+ if (leaving.type() === SymbolType.Invalid) throw new Error("failed to find leaving row");
4768
+ rowPair = this._rowMap.erase(leaving);
4769
+ rowPair.second.solveForEx(leaving, marker);
4770
+ this._substitute(marker, rowPair.second);
4771
+ }
4772
+ this._optimize(this._objective);
4773
+ }
4774
+ /**
4775
+ * Test whether the solver contains the constraint.
4776
+ *
4777
+ * @param {Constraint} constraint Constraint to test for
4778
+ * @return {Bool} true or false
4779
+ */
4780
+ hasConstraint(constraint) {
4781
+ return this._cnMap.contains(constraint);
4782
+ }
4783
+ /**
4784
+ * Get an array of the current constraints.
4785
+ *
4786
+ * @return {Constraint[]}
4787
+ */
4788
+ getConstraints() {
4789
+ return this._cnMap.array.map(({ first }) => first);
4790
+ }
4791
+ /**
4792
+ * Add an edit variable to the solver.
4793
+ *
4794
+ * @param {Variable} variable Edit variable to add to the solver
4795
+ * @param {Number} strength Strength, should be less than `Strength.required`
4796
+ */
4797
+ addEditVariable(variable, strength) {
4798
+ if (this._editMap.find(variable) !== void 0) throw new Error("duplicate edit variable");
4799
+ strength = Strength.clip(strength);
4800
+ if (strength === Strength.required) throw new Error("bad required strength");
4801
+ let cn = new Constraint(new Expression(variable), Operator.Eq, void 0, strength);
4802
+ this.addConstraint(cn);
4803
+ let info = {
4804
+ tag: this._cnMap.find(cn).second,
4805
+ constraint: cn,
4806
+ constant: 0
4807
+ };
4808
+ this._editMap.insert(variable, info);
4809
+ }
4810
+ /**
4811
+ * Remove an edit variable from the solver.
4812
+ *
4813
+ * @param {Variable} variable Edit variable to remove from the solver
4814
+ */
4815
+ removeEditVariable(variable) {
4816
+ let editPair = this._editMap.erase(variable);
4817
+ if (editPair === void 0) throw new Error("unknown edit variable");
4818
+ this.removeConstraint(editPair.second.constraint);
4819
+ }
4820
+ /**
4821
+ * Test whether the solver contains the edit variable.
4822
+ *
4823
+ * @param {Variable} variable Edit variable to test for
4824
+ * @return {Bool} true or false
4825
+ */
4826
+ hasEditVariable(variable) {
4827
+ return this._editMap.contains(variable);
4828
+ }
4829
+ /**
4830
+ * Suggest the value of an edit variable.
4831
+ *
4832
+ * @param {Variable} variable Edit variable to suggest a value for
4833
+ * @param {Number} value Suggested value
4834
+ */
4835
+ suggestValue(variable, value) {
4836
+ let editPair = this._editMap.find(variable);
4837
+ if (editPair === void 0) throw new Error("unknown edit variable");
4838
+ let rows = this._rowMap;
4839
+ let info = editPair.second;
4840
+ let delta = value - info.constant;
4841
+ info.constant = value;
4842
+ let marker = info.tag.marker;
4843
+ let rowPair = rows.find(marker);
4844
+ if (rowPair !== void 0) {
4845
+ if (rowPair.second.add(-delta) < 0) this._infeasibleRows.push(marker);
4846
+ this._dualOptimize();
4847
+ return;
4848
+ }
4849
+ let other = info.tag.other;
4850
+ rowPair = rows.find(other);
4851
+ if (rowPair !== void 0) {
4852
+ if (rowPair.second.add(delta) < 0) this._infeasibleRows.push(other);
4853
+ this._dualOptimize();
4854
+ return;
4855
+ }
4856
+ for (let i = 0, n = rows.size(); i < n; ++i) {
4857
+ let rowPair$1 = rows.itemAt(i);
4858
+ let row = rowPair$1.second;
4859
+ let coeff = row.coefficientFor(marker);
4860
+ if (coeff !== 0 && row.add(delta * coeff) < 0 && rowPair$1.first.type() !== SymbolType.External) this._infeasibleRows.push(rowPair$1.first);
4861
+ }
4862
+ this._dualOptimize();
4863
+ }
4864
+ /**
4865
+ * Update the values of the variables.
4866
+ */
4867
+ updateVariables() {
4868
+ let vars = this._varMap;
4869
+ let rows = this._rowMap;
4870
+ for (let i = 0, n = vars.size(); i < n; ++i) {
4871
+ let pair = vars.itemAt(i);
4872
+ let rowPair = rows.find(pair.second);
4873
+ if (rowPair !== void 0) pair.first.setValue(rowPair.second.constant());
4874
+ else pair.first.setValue(0);
4875
+ }
4876
+ }
4877
+ /**
4878
+ * Get the symbol for the given variable.
4879
+ *
4880
+ * If a symbol does not exist for the variable, one will be created.
4881
+ * @private
4882
+ */
4883
+ _getVarSymbol(variable) {
4884
+ let factory = () => this._makeSymbol(SymbolType.External);
4885
+ return this._varMap.setDefault(variable, factory).second;
4886
+ }
4887
+ /**
4888
+ * Create a new Row object for the given constraint.
4889
+ *
4890
+ * The terms in the constraint will be converted to cells in the row.
4891
+ * Any term in the constraint with a coefficient of zero is ignored.
4892
+ * This method uses the `_getVarSymbol` method to get the symbol for
4893
+ * the variables added to the row. If the symbol for a given cell
4894
+ * variable is basic, the cell variable will be substituted with the
4895
+ * basic row.
4896
+ *
4897
+ * The necessary slack and error variables will be added to the row.
4898
+ * If the constant for the row is negative, the sign for the row
4899
+ * will be inverted so the constant becomes positive.
4900
+ *
4901
+ * Returns the created Row and the tag for tracking the constraint.
4902
+ * @private
4903
+ */
4904
+ _createRow(constraint) {
4905
+ let expr = constraint.expression();
4906
+ let row = new Row(expr.constant());
4907
+ let terms = expr.terms();
4908
+ for (let i = 0, n = terms.size(); i < n; ++i) {
4909
+ let termPair = terms.itemAt(i);
4910
+ if (!nearZero(termPair.second)) {
4911
+ let symbol = this._getVarSymbol(termPair.first);
4912
+ let basicPair = this._rowMap.find(symbol);
4913
+ if (basicPair !== void 0) row.insertRow(basicPair.second, termPair.second);
4914
+ else row.insertSymbol(symbol, termPair.second);
4915
+ }
4916
+ }
4917
+ let objective = this._objective;
4918
+ let strength = constraint.strength();
4919
+ let tag = {
4920
+ marker: INVALID_SYMBOL,
4921
+ other: INVALID_SYMBOL
4922
+ };
4923
+ switch (constraint.op()) {
4924
+ case Operator.Le:
4925
+ case Operator.Ge: {
4926
+ let coeff = constraint.op() === Operator.Le ? 1 : -1;
4927
+ let slack = this._makeSymbol(SymbolType.Slack);
4928
+ tag.marker = slack;
4929
+ row.insertSymbol(slack, coeff);
4930
+ if (strength < Strength.required) {
4931
+ let error = this._makeSymbol(SymbolType.Error);
4932
+ tag.other = error;
4933
+ row.insertSymbol(error, -coeff);
4934
+ objective.insertSymbol(error, strength);
4935
+ }
4936
+ break;
4937
+ }
4938
+ case Operator.Eq:
4939
+ if (strength < Strength.required) {
4940
+ let errplus = this._makeSymbol(SymbolType.Error);
4941
+ let errminus = this._makeSymbol(SymbolType.Error);
4942
+ tag.marker = errplus;
4943
+ tag.other = errminus;
4944
+ row.insertSymbol(errplus, -1);
4945
+ row.insertSymbol(errminus, 1);
4946
+ objective.insertSymbol(errplus, strength);
4947
+ objective.insertSymbol(errminus, strength);
4948
+ } else {
4949
+ let dummy = this._makeSymbol(SymbolType.Dummy);
4950
+ tag.marker = dummy;
4951
+ row.insertSymbol(dummy);
4952
+ }
4953
+ break;
4954
+ }
4955
+ if (row.constant() < 0) row.reverseSign();
4956
+ return {
4957
+ row,
4958
+ tag
4959
+ };
4960
+ }
4961
+ /**
4962
+ * Choose the subject for solving for the row.
4963
+ *
4964
+ * This method will choose the best subject for using as the solve
4965
+ * target for the row. An invalid symbol will be returned if there
4966
+ * is no valid target.
4967
+ *
4968
+ * The symbols are chosen according to the following precedence:
4969
+ *
4970
+ * 1) The first symbol representing an external variable.
4971
+ * 2) A negative slack or error tag variable.
4972
+ *
4973
+ * If a subject cannot be found, an invalid symbol will be returned.
4974
+ *
4975
+ * @private
4976
+ */
4977
+ _chooseSubject(row, tag) {
4978
+ let cells = row.cells();
4979
+ for (let i = 0, n = cells.size(); i < n; ++i) {
4980
+ let pair = cells.itemAt(i);
4981
+ if (pair.first.type() === SymbolType.External) return pair.first;
4982
+ }
4983
+ let type = tag.marker.type();
4984
+ if (type === SymbolType.Slack || type === SymbolType.Error) {
4985
+ if (row.coefficientFor(tag.marker) < 0) return tag.marker;
4986
+ }
4987
+ type = tag.other.type();
4988
+ if (type === SymbolType.Slack || type === SymbolType.Error) {
4989
+ if (row.coefficientFor(tag.other) < 0) return tag.other;
4990
+ }
4991
+ return INVALID_SYMBOL;
4992
+ }
4993
+ /**
4994
+ * Add the row to the tableau using an artificial variable.
4995
+ *
4996
+ * This will return false if the constraint cannot be satisfied.
4997
+ *
4998
+ * @private
4999
+ */
5000
+ _addWithArtificialVariable(row) {
5001
+ let art = this._makeSymbol(SymbolType.Slack);
5002
+ this._rowMap.insert(art, row.copy());
5003
+ this._artificial = row.copy();
5004
+ this._optimize(this._artificial);
5005
+ let success = nearZero(this._artificial.constant());
5006
+ this._artificial = null;
5007
+ let pair = this._rowMap.erase(art);
5008
+ if (pair !== void 0) {
5009
+ let basicRow = pair.second;
5010
+ if (basicRow.isConstant()) return success;
5011
+ let entering = this._anyPivotableSymbol(basicRow);
5012
+ if (entering.type() === SymbolType.Invalid) return false;
5013
+ basicRow.solveForEx(art, entering);
5014
+ this._substitute(entering, basicRow);
5015
+ this._rowMap.insert(entering, basicRow);
5016
+ }
5017
+ let rows = this._rowMap;
5018
+ for (let i = 0, n = rows.size(); i < n; ++i) rows.itemAt(i).second.removeSymbol(art);
5019
+ this._objective.removeSymbol(art);
5020
+ return success;
5021
+ }
5022
+ /**
5023
+ * Substitute the parametric symbol with the given row.
5024
+ *
5025
+ * This method will substitute all instances of the parametric symbol
5026
+ * in the tableau and the objective function with the given row.
5027
+ *
5028
+ * @private
5029
+ */
5030
+ _substitute(symbol, row) {
5031
+ let rows = this._rowMap;
5032
+ for (let i = 0, n = rows.size(); i < n; ++i) {
5033
+ let pair = rows.itemAt(i);
5034
+ pair.second.substitute(symbol, row);
5035
+ if (pair.second.constant() < 0 && pair.first.type() !== SymbolType.External) this._infeasibleRows.push(pair.first);
5036
+ }
5037
+ this._objective.substitute(symbol, row);
5038
+ if (this._artificial) this._artificial.substitute(symbol, row);
5039
+ }
5040
+ /**
5041
+ * Optimize the system for the given objective function.
5042
+ *
5043
+ * This method performs iterations of Phase 2 of the simplex method
5044
+ * until the objective function reaches a minimum.
5045
+ *
5046
+ * @private
5047
+ */
5048
+ _optimize(objective) {
5049
+ let iterations = 0;
5050
+ while (iterations < this.maxIterations) {
5051
+ let entering = this._getEnteringSymbol(objective);
5052
+ if (entering.type() === SymbolType.Invalid) return;
5053
+ let leaving = this._getLeavingSymbol(entering);
5054
+ if (leaving.type() === SymbolType.Invalid) throw new Error("the objective is unbounded");
5055
+ let row = this._rowMap.erase(leaving).second;
5056
+ row.solveForEx(leaving, entering);
5057
+ this._substitute(entering, row);
5058
+ this._rowMap.insert(entering, row);
5059
+ iterations++;
5060
+ }
5061
+ throw new Error("solver iterations exceeded");
5062
+ }
5063
+ /**
5064
+ * Optimize the system using the dual of the simplex method.
5065
+ *
5066
+ * The current state of the system should be such that the objective
5067
+ * function is optimal, but not feasible. This method will perform
5068
+ * an iteration of the dual simplex method to make the solution both
5069
+ * optimal and feasible.
5070
+ *
5071
+ * @private
5072
+ */
5073
+ _dualOptimize() {
5074
+ let rows = this._rowMap;
5075
+ let infeasible = this._infeasibleRows;
5076
+ while (infeasible.length !== 0) {
5077
+ let leaving = infeasible.pop();
5078
+ let pair = rows.find(leaving);
5079
+ if (pair !== void 0 && pair.second.constant() < 0) {
5080
+ let entering = this._getDualEnteringSymbol(pair.second);
5081
+ if (entering.type() === SymbolType.Invalid) throw new Error("dual optimize failed");
5082
+ let row = pair.second;
5083
+ rows.erase(leaving);
5084
+ row.solveForEx(leaving, entering);
5085
+ this._substitute(entering, row);
5086
+ rows.insert(entering, row);
5087
+ }
5088
+ }
5089
+ }
5090
+ /**
5091
+ * Compute the entering variable for a pivot operation.
5092
+ *
5093
+ * This method will return first symbol in the objective function which
5094
+ * is non-dummy and has a coefficient less than zero. If no symbol meets
5095
+ * the criteria, it means the objective function is at a minimum, and an
5096
+ * invalid symbol is returned.
5097
+ *
5098
+ * @private
5099
+ */
5100
+ _getEnteringSymbol(objective) {
5101
+ let cells = objective.cells();
5102
+ for (let i = 0, n = cells.size(); i < n; ++i) {
5103
+ let pair = cells.itemAt(i);
5104
+ let symbol = pair.first;
5105
+ if (pair.second < 0 && symbol.type() !== SymbolType.Dummy) return symbol;
5106
+ }
5107
+ return INVALID_SYMBOL;
5108
+ }
5109
+ /**
5110
+ * Compute the entering symbol for the dual optimize operation.
5111
+ *
5112
+ * This method will return the symbol in the row which has a positive
5113
+ * coefficient and yields the minimum ratio for its respective symbol
5114
+ * in the objective function. The provided row *must* be infeasible.
5115
+ * If no symbol is found which meats the criteria, an invalid symbol
5116
+ * is returned.
5117
+ *
5118
+ * @private
5119
+ */
5120
+ _getDualEnteringSymbol(row) {
5121
+ let ratio = Number.MAX_VALUE;
5122
+ let entering = INVALID_SYMBOL;
5123
+ let cells = row.cells();
5124
+ for (let i = 0, n = cells.size(); i < n; ++i) {
5125
+ let pair = cells.itemAt(i);
5126
+ let symbol = pair.first;
5127
+ let c$1 = pair.second;
5128
+ if (c$1 > 0 && symbol.type() !== SymbolType.Dummy) {
5129
+ let r = this._objective.coefficientFor(symbol) / c$1;
5130
+ if (r < ratio) {
5131
+ ratio = r;
5132
+ entering = symbol;
5133
+ }
5134
+ }
5135
+ }
5136
+ return entering;
5137
+ }
5138
+ /**
5139
+ * Compute the symbol for pivot exit row.
5140
+ *
5141
+ * This method will return the symbol for the exit row in the row
5142
+ * map. If no appropriate exit symbol is found, an invalid symbol
5143
+ * will be returned. This indicates that the objective function is
5144
+ * unbounded.
5145
+ *
5146
+ * @private
5147
+ */
5148
+ _getLeavingSymbol(entering) {
5149
+ let ratio = Number.MAX_VALUE;
5150
+ let found = INVALID_SYMBOL;
5151
+ let rows = this._rowMap;
5152
+ for (let i = 0, n = rows.size(); i < n; ++i) {
5153
+ let pair = rows.itemAt(i);
5154
+ let symbol = pair.first;
5155
+ if (symbol.type() !== SymbolType.External) {
5156
+ let row = pair.second;
5157
+ let temp = row.coefficientFor(entering);
5158
+ if (temp < 0) {
5159
+ let temp_ratio = -row.constant() / temp;
5160
+ if (temp_ratio < ratio) {
5161
+ ratio = temp_ratio;
5162
+ found = symbol;
5163
+ }
5164
+ }
5165
+ }
5166
+ }
5167
+ return found;
5168
+ }
5169
+ /**
5170
+ * Compute the leaving symbol for a marker variable.
5171
+ *
5172
+ * This method will return a symbol corresponding to a basic row
5173
+ * which holds the given marker variable. The row will be chosen
5174
+ * according to the following precedence:
5175
+ *
5176
+ * 1) The row with a restricted basic varible and a negative coefficient
5177
+ * for the marker with the smallest ratio of -constant / coefficient.
5178
+ *
5179
+ * 2) The row with a restricted basic variable and the smallest ratio
5180
+ * of constant / coefficient.
5181
+ *
5182
+ * 3) The last unrestricted row which contains the marker.
5183
+ *
5184
+ * If the marker does not exist in any row, an invalid symbol will be
5185
+ * returned. This indicates an internal solver error since the marker
5186
+ * *should* exist somewhere in the tableau.
5187
+ *
5188
+ * @private
5189
+ */
5190
+ _getMarkerLeavingSymbol(marker) {
5191
+ let dmax = Number.MAX_VALUE;
5192
+ let r1 = dmax;
5193
+ let r2 = dmax;
5194
+ let invalid = INVALID_SYMBOL;
5195
+ let first = invalid;
5196
+ let second = invalid;
5197
+ let third = invalid;
5198
+ let rows = this._rowMap;
5199
+ for (let i = 0, n = rows.size(); i < n; ++i) {
5200
+ let pair = rows.itemAt(i);
5201
+ let row = pair.second;
5202
+ let c$1 = row.coefficientFor(marker);
5203
+ if (c$1 === 0) continue;
5204
+ let symbol = pair.first;
5205
+ if (symbol.type() === SymbolType.External) third = symbol;
5206
+ else if (c$1 < 0) {
5207
+ let r = -row.constant() / c$1;
5208
+ if (r < r1) {
5209
+ r1 = r;
5210
+ first = symbol;
5211
+ }
5212
+ } else {
5213
+ let r = row.constant() / c$1;
5214
+ if (r < r2) {
5215
+ r2 = r;
5216
+ second = symbol;
5217
+ }
5218
+ }
5219
+ }
5220
+ if (first !== invalid) return first;
5221
+ if (second !== invalid) return second;
5222
+ return third;
5223
+ }
5224
+ /**
5225
+ * Remove the effects of a constraint on the objective function.
5226
+ *
5227
+ * @private
5228
+ */
5229
+ _removeConstraintEffects(cn, tag) {
5230
+ if (tag.marker.type() === SymbolType.Error) this._removeMarkerEffects(tag.marker, cn.strength());
5231
+ if (tag.other.type() === SymbolType.Error) this._removeMarkerEffects(tag.other, cn.strength());
5232
+ }
5233
+ /**
5234
+ * Remove the effects of an error marker on the objective function.
5235
+ *
5236
+ * @private
5237
+ */
5238
+ _removeMarkerEffects(marker, strength) {
5239
+ let pair = this._rowMap.find(marker);
5240
+ if (pair !== void 0) this._objective.insertRow(pair.second, -strength);
5241
+ else this._objective.insertSymbol(marker, -strength);
5242
+ }
5243
+ /**
5244
+ * Get the first Slack or Error symbol in the row.
5245
+ *
5246
+ * If no such symbol is present, an invalid symbol will be returned.
5247
+ *
5248
+ * @private
5249
+ */
5250
+ _anyPivotableSymbol(row) {
5251
+ let cells = row.cells();
5252
+ for (let i = 0, n = cells.size(); i < n; ++i) {
5253
+ let pair = cells.itemAt(i);
5254
+ let type = pair.first.type();
5255
+ if (type === SymbolType.Slack || type === SymbolType.Error) return pair.first;
5256
+ }
5257
+ return INVALID_SYMBOL;
5258
+ }
5259
+ /**
5260
+ * Returns a new Symbol of the given type.
5261
+ *
5262
+ * @private
5263
+ */
5264
+ _makeSymbol(type) {
5265
+ return new Symbol(type, this._idTick++);
5266
+ }
5267
+ _cnMap = createCnMap();
5268
+ _rowMap = createRowMap();
5269
+ _varMap = createVarMap();
5270
+ _editMap = createEditMap();
5271
+ _infeasibleRows = [];
5272
+ _objective = new Row();
5273
+ _artificial = null;
5274
+ _idTick = 0;
5275
+ };
5276
+ /**
5277
+ * Test whether a value is approximately zero.
5278
+ * @private
5279
+ */
5280
+ function nearZero(value) {
5281
+ let eps = 1e-8;
5282
+ return value < 0 ? -value < eps : value < eps;
5283
+ }
5284
+ /**
5285
+ * An internal function for creating a constraint map.
5286
+ * @private
5287
+ */
5288
+ function createCnMap() {
5289
+ return createMap();
5290
+ }
5291
+ /**
5292
+ * An internal function for creating a row map.
5293
+ * @private
5294
+ */
5295
+ function createRowMap() {
5296
+ return createMap();
5297
+ }
5298
+ /**
5299
+ * An internal function for creating a variable map.
5300
+ * @private
5301
+ */
5302
+ function createVarMap() {
5303
+ return createMap();
5304
+ }
5305
+ /**
5306
+ * An internal function for creating an edit map.
5307
+ * @private
5308
+ */
5309
+ function createEditMap() {
5310
+ return createMap();
5311
+ }
5312
+ /**
5313
+ * An enum defining the available symbol types.
5314
+ * @private
5315
+ */
5316
+ var SymbolType;
5317
+ (function(SymbolType$1) {
5318
+ SymbolType$1[SymbolType$1["Invalid"] = 0] = "Invalid";
5319
+ SymbolType$1[SymbolType$1["External"] = 1] = "External";
5320
+ SymbolType$1[SymbolType$1["Slack"] = 2] = "Slack";
5321
+ SymbolType$1[SymbolType$1["Error"] = 3] = "Error";
5322
+ SymbolType$1[SymbolType$1["Dummy"] = 4] = "Dummy";
5323
+ })(SymbolType || (SymbolType = {}));
5324
+ /**
5325
+ * An internal class representing a symbol in the solver.
5326
+ * @private
5327
+ */
5328
+ var Symbol = class {
5329
+ /**
5330
+ * Construct a new Symbol
5331
+ *
5332
+ * @param [type] The type of the symbol.
5333
+ * @param [id] The unique id number of the symbol.
5334
+ */
5335
+ constructor(type, id) {
5336
+ this._id = id;
5337
+ this._type = type;
5338
+ }
5339
+ /**
5340
+ * Returns the unique id number of the symbol.
5341
+ */
5342
+ id() {
5343
+ return this._id;
5344
+ }
5345
+ /**
5346
+ * Returns the type of the symbol.
5347
+ */
5348
+ type() {
5349
+ return this._type;
5350
+ }
5351
+ _id;
5352
+ _type;
5353
+ };
5354
+ /**
5355
+ * A static invalid symbol
5356
+ * @private
5357
+ */
5358
+ let INVALID_SYMBOL = new Symbol(SymbolType.Invalid, -1);
5359
+ /**
5360
+ * An internal row class used by the solver.
5361
+ * @private
5362
+ */
5363
+ var Row = class Row {
5364
+ /**
5365
+ * Construct a new Row.
5366
+ */
5367
+ constructor(constant = 0) {
5368
+ this._constant = constant;
5369
+ }
5370
+ /**
5371
+ * Returns the mapping of symbols to coefficients.
5372
+ */
5373
+ cells() {
5374
+ return this._cellMap;
5375
+ }
5376
+ /**
5377
+ * Returns the constant for the row.
5378
+ */
5379
+ constant() {
5380
+ return this._constant;
5381
+ }
5382
+ /**
5383
+ * Returns true if the row is a constant value.
5384
+ */
5385
+ isConstant() {
5386
+ return this._cellMap.empty();
5387
+ }
5388
+ /**
5389
+ * Returns true if the Row has all dummy symbols.
5390
+ */
5391
+ allDummies() {
5392
+ let cells = this._cellMap;
5393
+ for (let i = 0, n = cells.size(); i < n; ++i) if (cells.itemAt(i).first.type() !== SymbolType.Dummy) return false;
5394
+ return true;
5395
+ }
5396
+ /**
5397
+ * Create a copy of the row.
5398
+ */
5399
+ copy() {
5400
+ let theCopy = new Row(this._constant);
5401
+ theCopy._cellMap = this._cellMap.copy();
5402
+ return theCopy;
5403
+ }
5404
+ /**
5405
+ * Add a constant value to the row constant.
5406
+ *
5407
+ * Returns the new value of the constant.
5408
+ */
5409
+ add(value) {
5410
+ return this._constant += value;
5411
+ }
5412
+ /**
5413
+ * Insert the symbol into the row with the given coefficient.
5414
+ *
5415
+ * If the symbol already exists in the row, the coefficient
5416
+ * will be added to the existing coefficient. If the resulting
5417
+ * coefficient is zero, the symbol will be removed from the row.
5418
+ */
5419
+ insertSymbol(symbol, coefficient = 1) {
5420
+ let pair = this._cellMap.setDefault(symbol, () => 0);
5421
+ if (nearZero(pair.second += coefficient)) this._cellMap.erase(symbol);
5422
+ }
5423
+ /**
5424
+ * Insert a row into this row with a given coefficient.
5425
+ *
5426
+ * The constant and the cells of the other row will be
5427
+ * multiplied by the coefficient and added to this row. Any
5428
+ * cell with a resulting coefficient of zero will be removed
5429
+ * from the row.
5430
+ */
5431
+ insertRow(other, coefficient = 1) {
5432
+ this._constant += other._constant * coefficient;
5433
+ let cells = other._cellMap;
5434
+ for (let i = 0, n = cells.size(); i < n; ++i) {
5435
+ let pair = cells.itemAt(i);
5436
+ this.insertSymbol(pair.first, pair.second * coefficient);
5437
+ }
5438
+ }
5439
+ /**
5440
+ * Remove a symbol from the row.
5441
+ */
5442
+ removeSymbol(symbol) {
5443
+ this._cellMap.erase(symbol);
5444
+ }
5445
+ /**
5446
+ * Reverse the sign of the constant and cells in the row.
5447
+ */
5448
+ reverseSign() {
5449
+ this._constant = -this._constant;
5450
+ let cells = this._cellMap;
5451
+ for (let i = 0, n = cells.size(); i < n; ++i) {
5452
+ let pair = cells.itemAt(i);
5453
+ pair.second = -pair.second;
5454
+ }
5455
+ }
5456
+ /**
5457
+ * Solve the row for the given symbol.
5458
+ *
5459
+ * This method assumes the row is of the form
5460
+ * a * x + b * y + c = 0 and (assuming solve for x) will modify
5461
+ * the row to represent the right hand side of
5462
+ * x = -b/a * y - c / a. The target symbol will be removed from
5463
+ * the row, and the constant and other cells will be multiplied
5464
+ * by the negative inverse of the target coefficient.
5465
+ *
5466
+ * The given symbol *must* exist in the row.
5467
+ */
5468
+ solveFor(symbol) {
5469
+ let cells = this._cellMap;
5470
+ let coeff = -1 / cells.erase(symbol).second;
5471
+ this._constant *= coeff;
5472
+ for (let i = 0, n = cells.size(); i < n; ++i) cells.itemAt(i).second *= coeff;
5473
+ }
5474
+ /**
5475
+ * Solve the row for the given symbols.
5476
+ *
5477
+ * This method assumes the row is of the form
5478
+ * x = b * y + c and will solve the row such that
5479
+ * y = x / b - c / b. The rhs symbol will be removed from the
5480
+ * row, the lhs added, and the result divided by the negative
5481
+ * inverse of the rhs coefficient.
5482
+ *
5483
+ * The lhs symbol *must not* exist in the row, and the rhs
5484
+ * symbol must* exist in the row.
5485
+ */
5486
+ solveForEx(lhs, rhs) {
5487
+ this.insertSymbol(lhs, -1);
5488
+ this.solveFor(rhs);
5489
+ }
5490
+ /**
5491
+ * Returns the coefficient for the given symbol.
5492
+ */
5493
+ coefficientFor(symbol) {
5494
+ let pair = this._cellMap.find(symbol);
5495
+ return pair !== void 0 ? pair.second : 0;
5496
+ }
5497
+ /**
5498
+ * Substitute a symbol with the data from another row.
5499
+ *
5500
+ * Given a row of the form a * x + b and a substitution of the
5501
+ * form x = 3 * y + c the row will be updated to reflect the
5502
+ * expression 3 * a * y + a * c + b.
5503
+ *
5504
+ * If the symbol does not exist in the row, this is a no-op.
5505
+ */
5506
+ substitute(symbol, row) {
5507
+ let pair = this._cellMap.erase(symbol);
5508
+ if (pair !== void 0) this.insertRow(row, pair.second);
5509
+ }
5510
+ _cellMap = createMap();
5511
+ _constant;
5512
+ };
5513
+
5514
+ //#endregion
5515
+ //#region src/constraints.ts
5516
+ /** Serializable constraint constructors; graph geometry stays in @statelyai/graph. */
5517
+ const c = {
5518
+ align: (value) => ({
5519
+ ...value,
5520
+ kind: "align"
5521
+ }),
5522
+ distribute: (value) => ({
5523
+ ...value,
5524
+ kind: "distribute"
5525
+ }),
5526
+ pin: (value) => ({
5527
+ ...value,
5528
+ kind: "pin"
5529
+ }),
5530
+ linear: (value) => ({
5531
+ ...value,
5532
+ kind: "linear"
5533
+ }),
5534
+ waypoint: (value) => ({
5535
+ ...value,
5536
+ kind: "waypoint"
5537
+ })
5538
+ };
5539
+ function constraintFailure(constraint, message) {
5540
+ throw new LayoutError(`${constraint.id}: ${message}`, "UNSATISFIED_CONSTRAINT");
5541
+ }
5542
+ /** Solve positions only. Fixed geometry is represented by constants, never edit variables. */
5543
+ function solveGeometryConstraints(graph, constraints, movableNodes, movableLabels, diagnostics) {
5544
+ const solver = new Solver();
5545
+ const variables = /* @__PURE__ */ new Map();
5546
+ const nodes = new Map(graph.nodes.map((n) => [n.id, n]));
5547
+ const edges = new Map(graph.edges.map((e) => [e.id, e]));
5548
+ function geometry(ref) {
5549
+ const node = "nodeId" in ref;
5550
+ const id = node ? ref.nodeId : ref.edgeId;
5551
+ const rect = node ? nodes.get(id) : edges.get(id);
5552
+ if (!rect) throw new LayoutError(`Unknown constraint entity: ${id}`, "INVALID_CONSTRAINT");
5553
+ const key = JSON.stringify([node ? "node" : "label", id]);
5554
+ if ((node ? movableNodes : movableLabels).has(id) && !variables.has(key)) {
5555
+ const pair = {
5556
+ x: new Variable(`${key}.x`),
5557
+ y: new Variable(`${key}.y`)
5558
+ };
5559
+ variables.set(key, pair);
5560
+ solver.addConstraint(new Constraint(pair.x, Operator.Eq, rect.x, Strength.weak / 10));
5561
+ solver.addConstraint(new Constraint(pair.y, Operator.Eq, rect.y, Strength.weak / 10));
5562
+ }
5563
+ return {
5564
+ rect,
5565
+ variables: variables.get(key)
5566
+ };
5567
+ }
5568
+ function expression(ref, attribute) {
5569
+ const { rect, variables: pair } = geometry(ref);
5570
+ const axis = attribute === "y" || attribute === "centerY" || attribute === "bottom" ? "y" : "x";
5571
+ const extent$1 = axis === "x" ? rect.width : rect.height;
5572
+ const offset = attribute.startsWith("center") ? extent$1 / 2 : attribute === "right" || attribute === "bottom" ? extent$1 : 0;
5573
+ return new Expression(pair?.[axis] ?? rect[axis], offset);
5574
+ }
5575
+ const checks = [];
5576
+ const ids = /* @__PURE__ */ new Set();
5577
+ for (const constraint of constraints) {
5578
+ if (ids.has(constraint.id)) throw new LayoutError(`Duplicate constraint ID: ${constraint.id}`, "INVALID_CONSTRAINT");
5579
+ ids.add(constraint.id);
5580
+ if (constraint.kind === "waypoint") continue;
5581
+ const strength = Strength[constraint.strength ?? "required"];
5582
+ const add = (lhs, operator = Operator.Eq, rhs = 0) => {
5583
+ const difference = lhs.minus(rhs);
5584
+ if (!Number.isFinite(difference.constant()) || !difference.terms().array.every((item) => Number.isFinite(item.second))) throw new LayoutError(`${constraint.id}: non-finite expression`, "INVALID_CONSTRAINT");
5585
+ try {
5586
+ solver.addConstraint(new Constraint(difference, operator, 0, strength));
5587
+ } catch {
5588
+ constraintFailure(constraint, "conflicts with fixed geometry or another required constraint");
5589
+ }
5590
+ checks.push({
5591
+ constraint,
5592
+ expression: difference,
5593
+ operator
5594
+ });
5595
+ };
5596
+ if (constraint.kind === "linear") {
5597
+ let value = new Expression();
5598
+ for (const term of constraint.terms) value = value.plus(expression(term.entity, term.attribute).multiply(term.coefficient));
5599
+ add(value, {
5600
+ eq: Operator.Eq,
5601
+ le: Operator.Le,
5602
+ ge: Operator.Ge
5603
+ }[constraint.relation], constraint.value);
5604
+ } else if (constraint.kind === "pin") {
5605
+ geometry(constraint.entity);
5606
+ if (constraint.x !== void 0) add(expression(constraint.entity, "x"), Operator.Eq, constraint.x);
5607
+ if (constraint.y !== void 0) add(expression(constraint.entity, "y"), Operator.Eq, constraint.y);
5608
+ } else {
5609
+ const refs = constraint.entities;
5610
+ for (const ref of refs) geometry(ref);
5611
+ const axis = constraint.axis;
5612
+ const end = axis === "x" ? "right" : "bottom";
5613
+ const center = axis === "x" ? "centerX" : "centerY";
5614
+ if (constraint.kind === "align") {
5615
+ const attr = constraint.anchor === "start" ? axis : constraint.anchor === "end" ? end : center;
5616
+ for (const ref of refs.slice(1)) add(expression(ref, attr), Operator.Eq, expression(refs[0], attr));
5617
+ } else {
5618
+ const gaps = refs.slice(1).map((ref, i) => constraint.spacing === "centers" ? expression(ref, center).minus(expression(refs[i], center)) : expression(ref, axis).minus(expression(refs[i], end)));
5619
+ for (const gap of gaps) {
5620
+ add(gap, Operator.Ge, 0);
5621
+ add(gap, Operator.Eq, constraint.gap ?? gaps[0]);
5622
+ }
5623
+ }
5624
+ }
5625
+ }
5626
+ solver.updateVariables();
5627
+ const warned = /* @__PURE__ */ new Set();
5628
+ for (const check of checks) {
5629
+ const residual = check.expression.value();
5630
+ if ((check.operator === Operator.Eq ? Math.abs(residual) > 1e-6 : check.operator === Operator.Le ? residual > 1e-6 : residual < -1e-6) && !warned.has(check.constraint.id)) {
5631
+ warned.add(check.constraint.id);
5632
+ diagnostics.push({
5633
+ severity: "warning",
5634
+ code: "CONSTRAINT_VIOLATION",
5635
+ message: `Constraint ${check.constraint.id} could not be satisfied`,
5636
+ constraintIds: [check.constraint.id]
5637
+ });
5638
+ }
5639
+ }
5640
+ const coordinate = (variable) => {
5641
+ const value = variable.value();
5642
+ if (!Number.isFinite(value)) throw new LayoutError("Constraint solution contains non-finite geometry", "INVALID_CONSTRAINT");
5643
+ return value === 0 ? 0 : value;
5644
+ };
5645
+ return {
5646
+ ...graph,
5647
+ nodes: graph.nodes.map((node) => {
5648
+ const pair = variables.get(JSON.stringify(["node", node.id]));
5649
+ return pair ? {
5650
+ ...node,
5651
+ x: coordinate(pair.x),
5652
+ y: coordinate(pair.y)
5653
+ } : node;
5654
+ }),
5655
+ edges: graph.edges.map((edge) => {
5656
+ const pair = variables.get(JSON.stringify(["label", edge.id]));
5657
+ return pair ? {
5658
+ ...edge,
5659
+ x: coordinate(pair.x),
5660
+ y: coordinate(pair.y)
5661
+ } : edge;
5662
+ })
5663
+ };
5664
+ }
5665
+
5666
+ //#endregion
5667
+ //#region src/authoring/partial.ts
5668
+ const geometryKeys = [
5669
+ "x",
5670
+ "y",
5671
+ "width",
5672
+ "height"
5673
+ ];
5674
+ function finite(value) {
5675
+ return typeof value === "number" && Number.isFinite(value);
5676
+ }
5677
+ function samePosition(a, b) {
5678
+ return a.x === b.x && a.y === b.y;
5679
+ }
5680
+ function onRoute(point, points) {
5681
+ return points?.some((b, i) => {
5682
+ if (!i) return false;
5683
+ const a = points[i - 1];
5684
+ const cross = (point.x - a.x) * (b.y - a.y) - (point.y - a.y) * (b.x - a.x);
5685
+ return Math.abs(cross) < 1e-6 && point.x >= Math.min(a.x, b.x) - 1e-6 && point.x <= Math.max(a.x, b.x) + 1e-6 && point.y >= Math.min(a.y, b.y) - 1e-6 && point.y <= Math.max(a.y, b.y) + 1e-6;
5686
+ }) ?? false;
5687
+ }
5688
+ function labelReferences(constraints) {
5689
+ const ids = /* @__PURE__ */ new Set();
5690
+ const add = (ref) => {
5691
+ if ("edgeId" in ref) ids.add(ref.edgeId);
5692
+ };
5693
+ for (const c$1 of constraints) if (c$1.kind === "align" || c$1.kind === "distribute") c$1.entities.forEach(add);
5694
+ else if (c$1.kind === "pin") add(c$1.entity);
5695
+ else if (c$1.kind === "linear") c$1.terms.forEach((term) => add(term.entity));
5696
+ return ids;
5697
+ }
5698
+ /** Authoring path: plan only selected nodes; route against the complete fixed scene. */
5699
+ function runPartialLayout(input, options, context, arrange, phase = "selection") {
5700
+ const scope = context.scope;
5701
+ if (scope.mode !== "partial" && scope.mode !== "route-only") throw new Error("Expected authoring scope");
5702
+ const selectedNodes = new Set(scope.mode === "partial" ? scope.nodeIds ?? [] : []);
5703
+ const selectedEdges = new Set(scope.mode === "route-only" ? scope.edgeIds ?? input.edges.map((e) => e.id) : scope.edgeIds ?? []);
5704
+ const geometry = scope.mode === "partial" ? scope.edgeGeometry ?? "both" : "routes";
5705
+ const routing = scope.mode === "partial" ? scope.routing ?? "affected" : "selected";
5706
+ const constraints = context.constraints ?? [];
5707
+ const constrainedLabels = labelReferences(constraints);
5708
+ for (const [ids, entities] of [[selectedNodes, input.nodes], [selectedEdges, input.edges]]) {
5709
+ const known = new Set(entities.map((e) => e.id));
5710
+ for (const id of ids) if (!known.has(id)) throw new LayoutError(`Unknown selected entity: ${id}`, "INVALID_SELECTION");
5711
+ }
5712
+ const containers = new Set(input.nodes.flatMap((n) => n.parentId == null ? [] : [n.parentId]));
5713
+ if ([...selectedNodes].some((id) => containers.has(id))) throw new UnsupportedLayoutError("Authoring layout cannot move containers; select leaf nodes or use full layout without geometry constraints");
5714
+ const previousNodes = new Map(scope.previous?.nodes.map((n) => [n.id, n]));
5715
+ const previousEdges = new Map(scope.previous?.edges.map((e) => [e.id, e]));
5716
+ const missing = (id) => {
5717
+ throw new LayoutError(`Fixed entity ${id} requires finite geometry in graph or previous`, "MISSING_GEOMETRY");
5718
+ };
5719
+ let nodes = input.nodes.map((node) => {
5720
+ const previous = previousNodes.get(node.id);
5721
+ const size = getNodeSize(node, options);
5722
+ const rect = { ...node };
5723
+ for (const key of geometryKeys) {
5724
+ const value = node[key] ?? previous?.[key];
5725
+ if (value !== void 0 && (!finite(value) || (key === "width" || key === "height") && value < 0)) missing(node.id);
5726
+ rect[key] = value ?? (selectedNodes.has(node.id) ? key === "width" || key === "height" ? size[key] : 0 : missing(node.id));
5727
+ if (!finite(rect[key]) || (key === "width" || key === "height") && rect[key] < 0) missing(node.id);
5728
+ }
5729
+ return rect;
5730
+ });
5731
+ let edges = input.edges.map((edge) => {
5732
+ const previous = previousEdges.get(edge.id);
5733
+ const absentLabel = !edge.label && (edge.width ?? previous?.width ?? 0) === 0 && (edge.height ?? previous?.height ?? 0) === 0;
5734
+ const rect = {
5735
+ ...edge,
5736
+ ...edge.points === void 0 && previous?.points !== void 0 ? { points: previous.points } : {},
5737
+ ...edge.routing === void 0 && previous?.routing !== void 0 ? { routing: previous.routing } : {}
5738
+ };
5739
+ for (const key of geometryKeys) {
5740
+ const value = edge[key] ?? previous?.[key];
5741
+ if (value !== void 0 && (!finite(value) || (key === "width" || key === "height") && value < 0)) missing(edge.id);
5742
+ rect[key] = value ?? (selectedEdges.has(edge.id) && geometry !== "routes" && (key === "x" || key === "y") || absentLabel ? 0 : missing(edge.id));
5743
+ }
5744
+ return rect;
5745
+ });
5746
+ const authored = {
5747
+ ...input,
5748
+ direction: options.direction ?? input.direction ?? scope.previous?.direction ?? "down",
5749
+ nodes,
5750
+ edges
5751
+ };
5752
+ const baseline = worldGeometry(authored);
5753
+ nodes = baseline.nodes;
5754
+ edges = baseline.edges;
5755
+ let graph = baseline;
5756
+ const byId = new Map(nodes.map((n) => [n.id, n]));
5757
+ const ancestorSets = /* @__PURE__ */ new Map();
5758
+ const ancestors = (id) => {
5759
+ const cached = ancestorSets.get(id);
5760
+ if (cached) return cached;
5761
+ const result = /* @__PURE__ */ new Set();
5762
+ let parent = byId.get(id)?.parentId;
5763
+ while (parent != null && !result.has(parent)) {
5764
+ result.add(parent);
5765
+ parent = byId.get(parent)?.parentId;
5766
+ }
5767
+ ancestorSets.set(id, result);
5768
+ return result;
5769
+ };
5770
+ for (const node of nodes) ancestors(node.id);
5771
+ const direction = options.direction ?? input.direction ?? scope.previous?.direction ?? "down";
5772
+ const gap = options.spacing?.node ?? 20;
5773
+ if (!finite(gap) || gap < 0) throw new LayoutError("Spacing must be finite and non-negative", "INVALID_OPTIONS");
5774
+ context.throwIfAborted();
5775
+ if (selectedNodes.size && phase === "selection") {
5776
+ const groups = /* @__PURE__ */ new Map();
5777
+ for (const node of nodes) if (selectedNodes.has(node.id)) {
5778
+ const group = groups.get(node.parentId ?? null) ?? [];
5779
+ group.push(node);
5780
+ groups.set(node.parentId ?? null, group);
5781
+ }
5782
+ const placed = new Map(nodes.map((n) => [n.id, n]));
5783
+ for (const group of groups.values()) {
5784
+ const ids = new Set(group.map((n) => n.id));
5785
+ const local = arrange({
5786
+ ...input,
5787
+ initialNodeId: void 0,
5788
+ nodes: group.map((n) => ({
5789
+ ...n,
5790
+ parentId: void 0,
5791
+ initialNodeId: void 0
5792
+ })),
5793
+ edges: edges.filter((e) => ids.has(e.sourceId) && ids.has(e.targetId))
5794
+ }, {
5795
+ ...options,
5796
+ padding: 0
5797
+ });
5798
+ const anchorX = Math.min(...group.map((n) => n.x));
5799
+ const anchorY = Math.min(...group.map((n) => n.y));
5800
+ const localX = Math.min(...local.nodes.map((n) => n.x));
5801
+ const localY = Math.min(...local.nodes.map((n) => n.y));
5802
+ const proposed = group.map((n) => {
5803
+ const p = local.nodes.find((item) => item.id === n.id);
5804
+ return {
5805
+ ...n,
5806
+ x: p.x - localX + anchorX,
5807
+ y: p.y - localY + anchorY
5808
+ };
5809
+ });
5810
+ const obstacles = [...placed.values()].filter((n) => !ids.has(n.id));
5811
+ const fixedLabels = edges.filter((e) => geometry === "routes" || !selectedEdges.has(e.id));
5812
+ const candidates = [{
5813
+ x: 0,
5814
+ y: 0
5815
+ }];
5816
+ candidateGeneration: for (const obstacle of [...obstacles, ...fixedLabels]) for (const node of proposed) {
5817
+ context.throwIfAborted();
5818
+ if (candidates.length + 4 > 2e3) break candidateGeneration;
5819
+ candidates.push({
5820
+ x: obstacle.x + obstacle.width + gap - node.x,
5821
+ y: 0
5822
+ }, {
5823
+ x: obstacle.x - gap - node.x - node.width,
5824
+ y: 0
5825
+ }, {
5826
+ x: 0,
5827
+ y: obstacle.y + obstacle.height + gap - node.y
5828
+ }, {
5829
+ x: 0,
5830
+ y: obstacle.y - gap - node.y - node.height
5831
+ });
5832
+ }
5833
+ candidates.sort((a, b) => Math.abs(a.x) + Math.abs(a.y) - Math.abs(b.x) - Math.abs(b.y));
5834
+ let comparisons = 0;
5835
+ const budget = () => {
5836
+ if (++comparisons % 128 === 0) context.throwIfAborted();
5837
+ return comparisons <= 1e5;
5838
+ };
5839
+ const fits = (offset$1) => {
5840
+ context.throwIfAborted();
5841
+ return proposed.every((n) => {
5842
+ if (!budget()) return false;
5843
+ const translated = {
5844
+ ...n,
5845
+ x: n.x + offset$1.x,
5846
+ y: n.y + offset$1.y
5847
+ };
5848
+ const parent = n.parentId == null ? void 0 : placed.get(n.parentId);
5849
+ if (parent && (translated.x < parent.x || translated.y < parent.y || translated.x + translated.width > parent.x + parent.width || translated.y + translated.height > parent.y + parent.height)) return false;
5850
+ return fixedLabels.every((label) => budget() && !overlaps(translated, label, gap)) && obstacles.every((o) => budget() && (ancestors(n.id).has(o.id) || ancestors(o.id).has(n.id) || !overlaps(translated, o, gap)));
5851
+ });
5852
+ };
5853
+ const offset = candidates.find((candidate) => comparisons <= 1e5 && fits(candidate));
5854
+ if (offset) for (const n of proposed) placed.set(n.id, {
5855
+ ...n,
5856
+ x: n.x + offset.x,
5857
+ y: n.y + offset.y
5858
+ });
5859
+ else context.diagnostics.push({
5860
+ severity: "warning",
5861
+ code: "PLACEMENT_BLOCKED",
5862
+ message: "No placement found within the search budget without moving fixed geometry; preserved selected positions",
5863
+ entityIds: [...ids],
5864
+ geometry: "node"
5865
+ });
5866
+ }
5867
+ graph = {
5868
+ ...graph,
5869
+ nodes: nodes.map((n) => placed.get(n.id))
5870
+ };
5871
+ }
5872
+ graph = solveGeometryConstraints(graph, constraints, selectedNodes, geometry === "routes" ? /* @__PURE__ */ new Set() : selectedEdges, context.diagnostics);
5873
+ const moved = graph.nodes.filter((n) => !samePosition(n, byId.get(n.id)));
5874
+ const movedIds = new Set(moved.map((n) => n.id));
5875
+ const resultNodes = new Map(graph.nodes.map((n) => [n.id, n]));
5876
+ const automatic = /* @__PURE__ */ new Set();
5877
+ const affected = (edge) => movedIds.has(edge.sourceId) || movedIds.has(edge.targetId) || moved.some((n) => !ancestors(edge.sourceId).has(n.id) && !ancestors(edge.targetId).has(n.id) && (routeCrosses(edge.points, n) || overlaps(edge, n) || edge.routing === "splines" && edge.points?.length && overlaps(n, {
5878
+ x: Math.min(...edge.points.map((p) => p.x)),
5879
+ y: Math.min(...edge.points.map((p) => p.y)),
5880
+ width: Math.max(...edge.points.map((p) => p.x)) - Math.min(...edge.points.map((p) => p.x)),
5881
+ height: Math.max(...edge.points.map((p) => p.y)) - Math.min(...edge.points.map((p) => p.y))
5882
+ })));
5883
+ const edgeById = new Map(graph.edges.map((e) => [e.id, e]));
5884
+ for (const constraint of constraints) if (constraint.kind === "waypoint") {
5885
+ if (!finite(constraint.point.x) || !finite(constraint.point.y) || !edgeById.has(constraint.edgeId)) throw new LayoutError(`${constraint.id}: invalid waypoint`, "INVALID_CONSTRAINT");
5886
+ }
5887
+ graph = {
5888
+ ...graph,
5889
+ edges: graph.edges.map((edge) => {
5890
+ context.throwIfAborted();
5891
+ const needsRepair = affected(edge);
5892
+ const allowed = selectedEdges.has(edge.id) || routing === "affected" && needsRepair;
5893
+ const waypoints = constraints.filter((c$1) => c$1.kind === "waypoint" && c$1.edgeId === edge.id);
5894
+ const routeAllowed = phase === "constraints" ? needsRepair || waypoints.some((c$1) => c$1.kind === "waypoint" && (edge.routing === "splines" || !onRoute(c$1.point, edge.points))) : allowed && geometry !== "labels";
5895
+ const labelAllowed = allowed && geometry !== "routes" && !constrainedLabels.has(edge.id);
5896
+ const source = resultNodes.get(edge.sourceId);
5897
+ const target = resultNodes.get(edge.targetId);
5898
+ let next = edge;
5899
+ let routeFailed = false;
5900
+ if (needsRepair && !routeAllowed) context.diagnostics.push({
5901
+ severity: "warning",
5902
+ code: "ROUTE_REPAIR_REQUIRED",
5903
+ message: `Edge ${edge.id} needs routing outside the permitted geometry`,
5904
+ entityIds: [edge.id],
5905
+ geometry: "routes"
5906
+ });
5907
+ if (routeAllowed) {
5908
+ if (options.settings?.edgeRouting === "SPLINES" || options.strategies?.routeEdges) throw new UnsupportedLayoutError("Partial layout supports its built-in orthogonal router only");
5909
+ const ancestorIds = new Set([...ancestors(source.id), ...ancestors(target.id)]);
5910
+ const nodeObstacles = graph.nodes.filter((n) => !ancestorIds.has(n.id)).map((n) => n.id === source.id || n.id === target.id ? n : {
5911
+ ...n,
5912
+ x: n.x - 1,
5913
+ y: n.y - 1,
5914
+ width: n.width + 2,
5915
+ height: n.height + 2
5916
+ });
5917
+ const labelObstacles = [...edgeById.values()].filter((e) => e.id !== edge.id && e.width > 0 && e.height > 0);
5918
+ const required = waypoints.filter((c$1) => (c$1.strength ?? "required") === "required");
5919
+ const accepted = new Set(required.map((c$1) => c$1.id));
5920
+ const route = () => routeOrthogonal(edge, source, target, direction, [...nodeObstacles, ...labelObstacles], waypoints.filter((c$1) => c$1.kind === "waypoint" && accepted.has(c$1.id)).map((c$1) => c$1.kind === "waypoint" ? c$1.point : {
5921
+ x: 0,
5922
+ y: 0
5923
+ }), () => context.throwIfAborted());
5924
+ let points = route();
5925
+ const priorities = {
5926
+ strong: 3,
5927
+ medium: 2,
5928
+ weak: 1,
5929
+ required: 4
5930
+ };
5931
+ for (const preference of waypoints.filter((c$1) => !accepted.has(c$1.id)).sort((a, b) => priorities[b.strength ?? "required"] - priorities[a.strength ?? "required"])) {
5932
+ accepted.add(preference.id);
5933
+ const candidate = route();
5934
+ if (candidate) points = candidate;
5935
+ else accepted.delete(preference.id);
5936
+ }
5937
+ if (points) next = {
5938
+ ...next,
5939
+ points,
5940
+ routing: "orthogonal"
5941
+ };
5942
+ else {
5943
+ routeFailed = true;
5944
+ context.diagnostics.push({
5945
+ severity: "warning",
5946
+ code: "ROUTE_BLOCKED",
5947
+ message: `No route found for ${edge.id} within the search budget; preserved the route`,
5948
+ entityIds: [edge.id],
5949
+ geometry: "routes"
5950
+ });
5951
+ }
5952
+ }
5953
+ for (const constraint of waypoints) if (constraint.kind === "waypoint" && (routeFailed || next.routing === "splines" || !onRoute(constraint.point, next.points))) {
5954
+ if ((constraint.strength ?? "required") === "required") constraintFailure(constraint, "route cannot pass through the waypoint within the permitted geometry");
5955
+ context.diagnostics.push({
5956
+ severity: "warning",
5957
+ code: "CONSTRAINT_VIOLATION",
5958
+ message: `Waypoint ${constraint.id} could not be satisfied`,
5959
+ entityIds: [edge.id],
5960
+ constraintIds: [constraint.id],
5961
+ geometry: "routes"
5962
+ });
5963
+ }
5964
+ if (labelAllowed && (next.points?.length ?? 0) >= 2) {
5965
+ const midpoint = getPolylineMidpoint(next.points ?? []);
5966
+ const candidates = [
5967
+ {
5968
+ x: midpoint.x - next.width / 2,
5969
+ y: midpoint.y - next.height / 2
5970
+ },
5971
+ {
5972
+ x: midpoint.x - next.width / 2,
5973
+ y: midpoint.y - next.height - gap
5974
+ },
5975
+ {
5976
+ x: midpoint.x - next.width / 2,
5977
+ y: midpoint.y + gap
5978
+ },
5979
+ {
5980
+ x: midpoint.x + gap,
5981
+ y: midpoint.y - next.height / 2
5982
+ },
5983
+ {
5984
+ x: midpoint.x - next.width - gap,
5985
+ y: midpoint.y - next.height / 2
5986
+ }
5987
+ ];
5988
+ const parentIds = new Set([...ancestors(source.id), ...ancestors(target.id)]);
5989
+ for (const obstacle of [...graph.nodes, ...edgeById.values()]) candidates.push({
5990
+ x: midpoint.x - next.width / 2,
5991
+ y: obstacle.y - next.height - gap
5992
+ }, {
5993
+ x: midpoint.x - next.width / 2,
5994
+ y: obstacle.y + obstacle.height + gap
5995
+ }, {
5996
+ x: obstacle.x - next.width - gap,
5997
+ y: midpoint.y - next.height / 2
5998
+ }, {
5999
+ x: obstacle.x + obstacle.width + gap,
6000
+ y: midpoint.y - next.height / 2
6001
+ });
6002
+ candidates.sort((a, b) => Math.hypot(a.x + next.width / 2 - midpoint.x, a.y + next.height / 2 - midpoint.y) - Math.hypot(b.x + next.width / 2 - midpoint.x, b.y + next.height / 2 - midpoint.y));
6003
+ const chosen = candidates.find((p) => {
6004
+ const rect = {
6005
+ ...next,
6006
+ ...p
6007
+ };
6008
+ return !graph.nodes.some((n) => !parentIds.has(n.id) && overlaps(rect, n)) && ![...edgeById.values()].some((e) => e.id !== edge.id && overlaps(rect, e));
6009
+ });
6010
+ if (chosen) next = {
6011
+ ...next,
6012
+ ...chosen
6013
+ };
6014
+ else context.diagnostics.push({
6015
+ severity: "warning",
6016
+ code: "LABEL_PLACEMENT_BLOCKED",
6017
+ message: `No clear label position found for ${edge.id}; preserved label position`,
6018
+ entityIds: [edge.id],
6019
+ geometry: "labels"
6020
+ });
6021
+ }
6022
+ if (geometry === "labels" && allowed && !samePosition(next, baseline.edges.find((e) => e.id === edge.id))) context.diagnostics.push({
6023
+ severity: "info",
6024
+ code: "ROUTE_PRESERVED",
6025
+ message: `Route for ${edge.id} was preserved; label attachment may need repair`,
6026
+ entityIds: [edge.id],
6027
+ geometry: "routes"
6028
+ });
6029
+ edgeById.set(edge.id, next);
6030
+ if (!selectedEdges.has(edge.id) && (next.x !== edge.x || next.y !== edge.y || next.routing !== edge.routing || JSON.stringify(next.points) !== JSON.stringify(edge.points))) automatic.add(edge.id);
6031
+ return next;
6032
+ })
6033
+ };
6034
+ if (automatic.size) context.diagnostics.push({
6035
+ severity: "info",
6036
+ code: "AFFECTED_EDGES_UPDATED",
6037
+ message: "Repaired geometry affected by moved nodes",
6038
+ entityIds: [...automatic]
6039
+ });
6040
+ for (const node of graph.nodes) if (selectedNodes.has(node.id) || node.parentId != null && movedIds.has(node.parentId)) {
6041
+ const parent = node.parentId == null ? void 0 : resultNodes.get(node.parentId);
6042
+ if (parent && (node.x < parent.x || node.y < parent.y || node.x + node.width > parent.x + parent.width || node.y + node.height > parent.y + parent.height)) context.diagnostics.push({
6043
+ severity: "warning",
6044
+ code: "CONTAINMENT_VIOLATION",
6045
+ message: `Node ${node.id} extends outside its fixed parent`,
6046
+ entityIds: [node.id, parent.id],
6047
+ geometry: "node"
6048
+ });
6049
+ if (graph.nodes.some((other) => other.id !== node.id && !ancestors(node.id).has(other.id) && !ancestors(other.id).has(node.id) && overlaps(node, other))) context.diagnostics.push({
6050
+ severity: "warning",
6051
+ code: "NODE_OVERLAP",
6052
+ message: `Node ${node.id} overlaps another node`,
6053
+ entityIds: [node.id],
6054
+ geometry: "node"
6055
+ });
6056
+ }
6057
+ for (const edge of graph.edges) {
6058
+ const before = baseline.edges.find((e) => e.id === edge.id);
6059
+ if (!samePosition(edge, before)) {
6060
+ const containerIds = new Set([...ancestors(edge.sourceId), ...ancestors(edge.targetId)]);
6061
+ const collisions = [...graph.nodes.filter((n) => !containerIds.has(n.id) && overlaps(edge, n)), ...graph.edges.filter((other) => other.id !== edge.id && overlaps(edge, other))];
6062
+ if (collisions.length) context.diagnostics.push({
6063
+ severity: "warning",
6064
+ code: "LABEL_OVERLAP",
6065
+ message: `Label ${edge.id} overlaps fixed or constrained geometry`,
6066
+ entityIds: [edge.id, ...collisions.map((e) => e.id)],
6067
+ geometry: "labels"
6068
+ });
6069
+ for (const other of graph.edges) if (other.id !== edge.id && routeCrosses(other.points, edge) && !routeCrosses(other.points, before)) context.diagnostics.push({
6070
+ severity: "warning",
6071
+ code: "ROUTE_REPAIR_REQUIRED",
6072
+ message: `Route ${other.id} crosses the moved label ${edge.id}`,
6073
+ entityIds: [other.id, edge.id],
6074
+ geometry: "routes"
6075
+ });
6076
+ }
6077
+ if (geometry === "routes" && routeCrosses(before.points, before) && !routeCrosses(edge.points, edge)) context.diagnostics.push({
6078
+ severity: "warning",
6079
+ code: "LABEL_REPAIR_REQUIRED",
6080
+ message: `Label ${edge.id} is no longer attached to its route`,
6081
+ entityIds: [edge.id],
6082
+ geometry: "labels"
6083
+ });
6084
+ }
6085
+ return nativeGeometry(graph, authored);
6086
+ }
6087
+
3821
6088
  //#endregion
3822
6089
  //#region src/layered/separate-exterior-labels.ts
3823
6090
  /** Assigns collision-free cross-axis lanes to inline labels and their route tracks. */
@@ -3829,7 +6096,7 @@ function separateExteriorLabels({ edges, nodeRects, direction, spacing, settings
3829
6096
  const flowEnd = (rect) => horizontalFlow ? rect.x + rect.width : rect.y + rect.height;
3830
6097
  const crossStart = (rect) => horizontalFlow ? rect.y : rect.x;
3831
6098
  const crossEnd = (rect) => horizontalFlow ? rect.y + rect.height : rect.x + rect.width;
3832
- const overlaps = (left, right) => flowStart(left) < flowEnd(right) && flowEnd(left) > flowStart(right) && crossStart(left) < crossEnd(right) && crossEnd(left) > crossStart(right);
6099
+ const overlaps$1 = (left, right) => flowStart(left) < flowEnd(right) && flowEnd(left) > flowStart(right) && crossStart(left) < crossEnd(right) && crossEnd(left) > crossStart(right);
3833
6100
  const labelRectByEdgeId = new Map(edges.filter((edge) => edge.width > 0 && edge.height > 0).map((edge) => [String(edge.id), {
3834
6101
  x: edge.x,
3835
6102
  y: edge.y,
@@ -3914,14 +6181,14 @@ function separateExteriorLabels({ edges, nodeRects, direction, spacing, settings
3914
6181
  x: labelRect.x + delta
3915
6182
  };
3916
6183
  const candidateTrackCross = exteriorTrack.cross + delta;
3917
- return obstacles.every((obstacle) => !overlaps(candidateLabel, obstacle)) && nodeRects.every((nodeRect) => !lineIntersects(nodeRect, candidateTrackCross, exteriorTrack.flowStart) && !lineIntersects(nodeRect, candidateTrackCross, exteriorTrack.flowEnd));
6184
+ return obstacles.every((obstacle) => !overlaps$1(candidateLabel, obstacle)) && nodeRects.every((nodeRect) => !lineIntersects(nodeRect, candidateTrackCross, exteriorTrack.flowStart) && !lineIntersects(nodeRect, candidateTrackCross, exteriorTrack.flowEnd));
3918
6185
  });
3919
6186
  if (candidate === void 0) continue;
3920
6187
  totalDelta = candidate - labelCrossStart;
3921
6188
  if (horizontalFlow) labelRect.y += totalDelta;
3922
6189
  else labelRect.x += totalDelta;
3923
6190
  } else while (true) {
3924
- const blockers = obstacles.filter((rect) => overlaps(labelRect, rect));
6191
+ const blockers = obstacles.filter((rect) => overlaps$1(labelRect, rect));
3925
6192
  if (blockers.length === 0) break;
3926
6193
  const delta = (lowSide ? Math.min(...blockers.map(crossStart)) - spacing - (horizontalFlow ? edge.height : edge.width) : Math.max(...blockers.map(crossEnd)) + spacing) - crossStart(labelRect);
3927
6194
  totalDelta += delta;
@@ -7843,7 +10110,7 @@ function adjustUnzippedSinkRoutes(graph, routes, direction, edgeNodeSpacing, edg
7843
10110
  }
7844
10111
  return result;
7845
10112
  }
7846
- function getNodeSize(node, options) {
10113
+ function getNodeSize$1(node, options) {
7847
10114
  const measured = options.measure?.(node);
7848
10115
  if (measured) return measured;
7849
10116
  return {
@@ -7884,7 +10151,7 @@ function runWrappedPathPipeline(graph, options) {
7884
10151
  currentId = targets[0];
7885
10152
  }
7886
10153
  if (orderedIds.length !== graph.nodes.length) return void 0;
7887
- const sizes = new Map(graph.nodes.map((node) => [node.id, getNodeSize(node, options)]));
10154
+ const sizes = new Map(graph.nodes.map((node) => [node.id, getNodeSize$1(node, options)]));
7888
10155
  const maximumWidth = Math.max(...[...sizes.values()].map((size) => size.width));
7889
10156
  const maximumHeight = Math.max(...[...sizes.values()].map((size) => size.height));
7890
10157
  if ([...sizes.values()].some((size) => size.width !== maximumWidth || size.height !== maximumHeight)) return;
@@ -8060,7 +10327,7 @@ function runWrappedMultiEdgePipeline(graph, options) {
8060
10327
  }
8061
10328
  if (nodeIdByRank.size !== maximumRank + 1) return void 0;
8062
10329
  const orderedIds = Array.from({ length: maximumRank + 1 }, (_, index) => nodeIdByRank.get(index));
8063
- const sizes = new Map(graph.nodes.map((node) => [node.id, getNodeSize(node, options)]));
10330
+ const sizes = new Map(graph.nodes.map((node) => [node.id, getNodeSize$1(node, options)]));
8064
10331
  const layerSpacing = options.spacing?.layer ?? options.settings?.["spacing.baseValue"] ?? 20;
8065
10332
  const nodeSpacing = options.spacing?.node ?? options.settings?.["spacing.baseValue"] ?? 20;
8066
10333
  const widths = orderedIds.map((id) => sizes.get(id).width + layerSpacing);
@@ -8285,8 +10552,8 @@ function runCommentBoxPipeline(graph, options, context) {
8285
10552
  const horizontal = direction === "left" || direction === "right";
8286
10553
  const commentNodeSpacing = Number(options.settings?.["spacing.commentNode"] ?? 10);
8287
10554
  const commentCommentSpacing = Number(options.settings?.["spacing.commentComment"] ?? 10);
8288
- const targetSize = getNodeSize(target, options);
8289
- const commentSizes = comments.map((comment) => getNodeSize(comment, options));
10555
+ const targetSize = getNodeSize$1(target, options);
10556
+ const commentSizes = comments.map((comment) => getNodeSize$1(comment, options));
8290
10557
  const beforeIndexes = comments.flatMap((_, index) => index % 2 === 0 ? [index] : []);
8291
10558
  const afterIndexes = comments.flatMap((_, index) => index % 2 === 1 ? [index] : []);
8292
10559
  const rowFlowSize = (indexes) => indexes.reduce((sum, index) => sum + (horizontal ? commentSizes[index].width : commentSizes[index].height), 0) + Math.max(0, indexes.length - 1) * commentCommentSpacing;
@@ -8312,7 +10579,7 @@ function runCommentBoxPipeline(graph, options, context) {
8312
10579
  edges: graph.edges.filter((edge) => !commentIds.has(edge.sourceId) && !commentIds.has(edge.targetId))
8313
10580
  }, {
8314
10581
  ...options,
8315
- measure: (node) => node.id === targetId ? groupSize : options.measure?.(node) ?? getNodeSize(node, options)
10582
+ measure: (node) => node.id === targetId ? groupSize : options.measure?.(node) ?? getNodeSize$1(node, options)
8316
10583
  }, context);
8317
10584
  const groupRect = base.nodes.find((node) => node.id === targetId);
8318
10585
  if (!groupRect) return void 0;
@@ -8567,126 +10834,16 @@ function runSeparatedComponents(graph, options, context) {
8567
10834
  };
8568
10835
  }
8569
10836
  function runCompoundPipeline(graph, options, context) {
8570
- const nodes = graph.nodes.map((node) => ({ ...node }));
8571
- const nodeById = new Map(nodes.map((node) => [node.id, node]));
8572
- const depth = (node) => {
8573
- let value = 0;
8574
- let parentId = node.parentId;
8575
- const seen = /* @__PURE__ */ new Set();
8576
- while (parentId != null && !seen.has(parentId)) {
8577
- seen.add(parentId);
8578
- value++;
8579
- parentId = nodeById.get(parentId)?.parentId;
8580
- }
8581
- return value;
8582
- };
8583
- const parentIds = [...new Set(nodes.flatMap((node) => node.parentId == null ? [] : [node.parentId]))].sort((left, right) => depth(nodeById.get(right)) - depth(nodeById.get(left)));
8584
- const edgeById = new Map(graph.edges.map((edge) => [edge.id, { ...edge }]));
8585
- const padding = typeof options.padding === "number" ? options.padding : 12;
8586
- const layoutSiblings = (parentId) => {
8587
- const siblings = nodes.filter((node) => (node.parentId ?? null) === parentId);
8588
- if (siblings.length === 0) return;
8589
- const siblingIds = new Set(siblings.map((node) => node.id));
8590
- const siblingEdges = graph.edges.filter((edge) => siblingIds.has(edge.sourceId) && siblingIds.has(edge.targetId));
8591
- const flatNodes = siblings.map((node) => ({
8592
- ...node,
8593
- parentId: null
8594
- }));
8595
- const result = runLayeredPipeline({
8596
- ...graph,
8597
- nodes: flatNodes,
8598
- edges: siblingEdges
8599
- }, options, context);
8600
- for (const laidOut of result.nodes) {
8601
- const node = nodeById.get(laidOut.id);
8602
- if (!node) continue;
8603
- Object.assign(node, laidOut, { parentId });
8604
- }
8605
- for (const edge of result.edges) edgeById.set(edge.id, edge);
8606
- };
8607
- for (const parentId of parentIds) {
8608
- layoutSiblings(parentId);
8609
- const parent = nodeById.get(parentId);
8610
- if (!parent) continue;
8611
- const children = nodes.filter((node) => node.parentId === parentId);
8612
- const right = Math.max(0, ...children.map((node) => (node.x ?? 0) + (node.width ?? 0)));
8613
- const bottom = Math.max(0, ...children.map((node) => (node.y ?? 0) + (node.height ?? 0)));
8614
- parent.width = Math.max(parent.width ?? 0, right + padding);
8615
- parent.height = Math.max(parent.height ?? 0, bottom + padding);
8616
- }
8617
- const roots = nodes.filter((node) => node.parentId == null);
8618
- if (roots.length === 1 && parentIds.includes(roots[0].id)) Object.assign(roots[0], {
8619
- x: 0,
8620
- y: 0
10837
+ const result = layoutCompounds(graph, options, (scope, local) => runLayeredPipeline(scope, local, context));
10838
+ for (const route of result.compoundRoutes.values()) for (const diagnostic of route.diagnostics) context?.diagnostics.push({
10839
+ severity: "warning",
10840
+ code: diagnostic.code,
10841
+ message: diagnostic.message,
10842
+ entityIds: [route.edgeId],
10843
+ phase: "compound-routing",
10844
+ geometry: "routes"
8621
10845
  });
8622
- else layoutSiblings(null);
8623
- const absoluteRect = (id) => {
8624
- const node = nodeById.get(id);
8625
- if (!node) return {
8626
- x: 0,
8627
- y: 0,
8628
- width: 0,
8629
- height: 0
8630
- };
8631
- let x = node.x ?? 0;
8632
- let y = node.y ?? 0;
8633
- let parentId = node.parentId;
8634
- const seen = /* @__PURE__ */ new Set();
8635
- while (parentId != null && !seen.has(parentId)) {
8636
- seen.add(parentId);
8637
- const parent = nodeById.get(parentId);
8638
- if (!parent) break;
8639
- x += parent.x ?? 0;
8640
- y += parent.y ?? 0;
8641
- parentId = parent.parentId;
8642
- }
8643
- return {
8644
- x,
8645
- y,
8646
- width: node.width ?? 0,
8647
- height: node.height ?? 0
8648
- };
8649
- };
8650
- for (const edge of graph.edges) {
8651
- if (edgeById.get(edge.id)?.points !== void 0) continue;
8652
- const source = absoluteRect(edge.sourceId);
8653
- const target = absoluteRect(edge.targetId);
8654
- const start = {
8655
- x: source.x + source.width,
8656
- y: source.y + source.height / 2
8657
- };
8658
- const end = {
8659
- x: target.x,
8660
- y: target.y + target.height / 2
8661
- };
8662
- const track = (start.x + end.x) / 2;
8663
- const points = [
8664
- start,
8665
- {
8666
- x: track,
8667
- y: start.y
8668
- },
8669
- {
8670
- x: track,
8671
- y: end.y
8672
- },
8673
- end
8674
- ];
8675
- edgeById.set(edge.id, {
8676
- ...edge,
8677
- points,
8678
- x: track,
8679
- y: (start.y + end.y) / 2,
8680
- width: edge.width ?? 0,
8681
- height: edge.height ?? 0,
8682
- routing: "orthogonal"
8683
- });
8684
- }
8685
- return {
8686
- ...graph,
8687
- nodes,
8688
- edges: graph.edges.map((edge) => edgeById.get(edge.id) ?? edge)
8689
- };
10846
+ return result;
8690
10847
  }
8691
10848
  function runLayeredPipeline(graph, options, context) {
8692
10849
  if (options.settings?.noLayout) return {
@@ -8750,7 +10907,7 @@ function runLayeredPipeline(graph, options, context) {
8750
10907
  }
8751
10908
  const input = {
8752
10909
  graph,
8753
- sizes: new Map(graph.nodes.map((node) => [node.id, getNodeSize(node, options)])),
10910
+ sizes: new Map(graph.nodes.map((node) => [node.id, getNodeSize$1(node, options)])),
8754
10911
  direction,
8755
10912
  spacing: {
8756
10913
  node: options.spacing?.node ?? options.settings?.["spacing.baseValue"] ?? 20,
@@ -9575,22 +11732,39 @@ function runLayeredPipeline(graph, options, context) {
9575
11732
  * custom phase strategies, and all layered edge-routing styles.
9576
11733
  */
9577
11734
  function getLayeredLayout(graph, options = {}) {
9578
- return runLayeredPipeline(graph, options);
11735
+ const result = runLayeredPipeline(graph, options);
11736
+ return {
11737
+ ...result,
11738
+ compoundGeometry: result.compoundGeometry ?? /* @__PURE__ */ new Map(),
11739
+ compoundRoutes: result.compoundRoutes ?? /* @__PURE__ */ new Map()
11740
+ };
9579
11741
  }
9580
11742
  const layeredAlgorithm = {
9581
11743
  id: "layered",
9582
11744
  capabilities: {
9583
11745
  full: true,
9584
11746
  incremental: false,
9585
- partial: false,
9586
- routeOnly: false,
11747
+ partial: true,
11748
+ routeOnly: true,
11749
+ constraints: true,
9587
11750
  hierarchy: true,
9588
11751
  ports: true
9589
11752
  },
9590
11753
  layout(graph, options, context) {
9591
- return runLayeredPipeline(graph, options ?? {}, context);
11754
+ if (context.scope.mode === "partial" || context.scope.mode === "route-only") return context.measurePhase("partial-layout", () => runPartialLayout(graph, options ?? {}, context, getLayeredLayout));
11755
+ if (context.constraints?.length && graph.nodes.some((node) => node.parentId != null)) throw new UnsupportedLayoutError("Full layout with geometry constraints does not support containers; use partial leaf constraints or full layout without geometry constraints");
11756
+ const result = runLayeredPipeline(graph, options ?? {}, context);
11757
+ if (!context.constraints?.length) return result;
11758
+ return context.measurePhase("constraints", () => runPartialLayout(result, options ?? {}, {
11759
+ ...context,
11760
+ scope: {
11761
+ mode: "partial",
11762
+ nodeIds: result.nodes.map((n) => n.id),
11763
+ edgeIds: [...labelReferences(context.constraints ?? [])]
11764
+ }
11765
+ }, getLayeredLayout, "constraints"));
9592
11766
  }
9593
11767
  };
9594
11768
 
9595
11769
  //#endregion
9596
- export { minimizeCrossingsWithBarycenter as A, LayoutError as B, breakCyclesGreedilyByModelOrder as C, breakCyclesWithModelOrderDepthFirstSearch as D, breakCyclesWithModelOrderBreadthFirstSearch as E, placePorts as F, routeEdgesOrthogonally as I, routeEdgesWithPolylines as L, minimizeCrossingsWithModelOrder as M, placeNodesInLayers as N, getPolylineMidpoint as O, placeNodesInteractively as P, routeEdgesWithSplines as R, breakCyclesGreedily as S, breakCyclesWithDepthFirstSearch as T, UnsupportedLayoutError as V, assignLayersInteractively as _, elkLayeredEnumValues as a, breakCyclesByStronglyConnectedConnectivity as b, placeNodesWithLinearSegments as c, assignLayersWithMinWidth as d, assignLayersWithNetworkSimplex as f, assignLayersByLongestPathToSink as g, assignLayersByLongestPath as h, toElkLayeredOptions as i, minimizeCrossingsWithMedian as j, minimizeCrossingsInteractively as k, placeNodesWithBrandesKoepf as l, assignLayersByDepthFirstModelOrder as m, layeredAlgorithm as n, elkLayeredOptionDefinitions as o, assignLayersByBreadthFirstModelOrder as p, fromElkLayeredOptionId as r, placeNodesWithNetworkSimplex as s, getLayeredLayout as t, assignLayersWithStretchWidth as u, assignLayersWithCoffmanGraham as v, breakCyclesInteractively as w, breakCyclesByStronglyConnectedNodeType as x, breakCyclesByModelOrder as y, JavaRandom as z };
11770
+ export { minimizeCrossingsInteractively as A, JavaRandom as B, breakCyclesGreedily as C, breakCyclesWithModelOrderBreadthFirstSearch as D, breakCyclesWithDepthFirstSearch as E, placeNodesInteractively as F, placePorts as I, routeEdgesOrthogonally as L, minimizeCrossingsWithMedian as M, minimizeCrossingsWithModelOrder as N, breakCyclesWithModelOrderDepthFirstSearch as O, placeNodesInLayers as P, routeEdgesWithPolylines as R, breakCyclesByStronglyConnectedNodeType as S, breakCyclesInteractively as T, assignLayersByLongestPathToSink as _, elkLayeredEnumValues as a, breakCyclesByModelOrder as b, placeNodesWithLinearSegments as c, assignLayersWithMinWidth as d, assignLayersWithNetworkSimplex as f, assignLayersByLongestPath as g, assignLayersByDepthFirstModelOrder as h, toElkLayeredOptions as i, minimizeCrossingsWithBarycenter as j, getPolylineMidpoint as k, placeNodesWithBrandesKoepf as l, assignLayersByBreadthFirstModelOrder as m, layeredAlgorithm as n, elkLayeredOptionDefinitions as o, c as p, fromElkLayeredOptionId as r, placeNodesWithNetworkSimplex as s, getLayeredLayout as t, assignLayersWithStretchWidth as u, assignLayersInteractively as v, breakCyclesGreedilyByModelOrder as w, breakCyclesByStronglyConnectedConnectivity as x, assignLayersWithCoffmanGraham as y, routeEdgesWithSplines as z };