@@ -2,7 +2,7 @@ import { BaseSolver } from "@tscircuit/solver-utils"
22import type { GraphicsObject } from "graphics-debug"
33import { convertToSerializedHyperGraph } from "./compat/convertToSerializedHyperGraph"
44import { computeRegionCost } from "./computeRegionCost"
5- import { countNewIntersections } from "./countNewIntersections"
5+ import { countNewIntersectionsWithValues } from "./countNewIntersections"
66import { MinHeap } from "./MinHeap"
77import { shuffle } from "./shuffle"
88import type {
@@ -204,9 +204,22 @@ export const getTinyHyperGraphSolverOptions = (
204204const compareCandidatesByF = ( left : Candidate , right : Candidate ) =>
205205 left . f - right . f
206206
207+ interface SegmentGeometryScratch {
208+ lesserAngle : number
209+ greaterAngle : number
210+ layerMask : number
211+ entryExitLayerChanges : number
212+ }
213+
207214export class TinyHyperGraphSolver extends BaseSolver {
208215 state : TinyHyperGraphWorkingState
209- problemSetup : TinyHyperGraphProblemSetup
216+ private _problemSetup ?: TinyHyperGraphProblemSetup
217+ private segmentGeometryScratch : SegmentGeometryScratch = {
218+ lesserAngle : 0 ,
219+ greaterAngle : 0 ,
220+ layerMask : 0 ,
221+ entryExitLayerChanges : 0 ,
222+ }
210223
211224 DISTANCE_TO_COST = 0.05 // 50mm = 1 cost unit (1 cost unit ~ 100% chance of failure)
212225
@@ -247,7 +260,14 @@ export class TinyHyperGraphSolver extends BaseSolver {
247260 ripCount : 0 ,
248261 regionCongestionCost : new Float64Array ( topology . regionCount ) . fill ( 0 ) ,
249262 }
250- this . problemSetup = this . computeProblemSetup ( )
263+ }
264+
265+ get problemSetup ( ) : TinyHyperGraphProblemSetup {
266+ if ( ! this . _problemSetup ) {
267+ this . _problemSetup = this . computeProblemSetup ( )
268+ }
269+
270+ return this . _problemSetup
251271 }
252272
253273 computeProblemSetup ( ) : TinyHyperGraphProblemSetup {
@@ -288,6 +308,10 @@ export class TinyHyperGraphSolver extends BaseSolver {
288308 }
289309 }
290310
311+ override _setup ( ) {
312+ void this . problemSetup
313+ }
314+
291315 override _step ( ) {
292316 const { problem, topology, state } = this
293317
@@ -480,41 +504,33 @@ export class TinyHyperGraphSolver extends BaseSolver {
480504 )
481505 }
482506
483- getPortAngleInRegion ( portId : PortId , regionId : RegionId ) : number {
484- const { topology } = this
485- const [ firstRegionId , secondRegionId ] =
486- topology . incidentPortRegion [ portId ] ?? [ ]
487-
488- if ( firstRegionId === regionId ) {
489- return topology . portAngleForRegion1 [ portId ]
490- }
491-
492- if ( secondRegionId === regionId ) {
493- return (
494- topology . portAngleForRegion2 ?. [ portId ] ??
495- topology . portAngleForRegion1 [ portId ]
496- )
497- }
498-
499- return topology . portAngleForRegion1 [ portId ]
500- }
501-
502- buildDynamicAnglePair (
507+ populateSegmentGeometryScratch (
503508 regionId : RegionId ,
504509 port1Id : PortId ,
505510 port2Id : PortId ,
506- ) : DynamicAnglePair {
507- const { topology, state } = this
508- const angle1 = this . getPortAngleInRegion ( port1Id , regionId )
509- const angle2 = this . getPortAngleInRegion ( port2Id , regionId )
511+ ) : SegmentGeometryScratch {
512+ const { topology } = this
513+ const scratch = this . segmentGeometryScratch
514+ const port1IncidentRegions = topology . incidentPortRegion [ port1Id ]
515+ const port2IncidentRegions = topology . incidentPortRegion [ port2Id ]
516+ const angle1 =
517+ port1IncidentRegions [ 0 ] === regionId || port1IncidentRegions [ 1 ] !== regionId
518+ ? topology . portAngleForRegion1 [ port1Id ]
519+ : topology . portAngleForRegion2 ?. [ port1Id ] ??
520+ topology . portAngleForRegion1 [ port1Id ]
521+ const angle2 =
522+ port2IncidentRegions [ 0 ] === regionId || port2IncidentRegions [ 1 ] !== regionId
523+ ? topology . portAngleForRegion1 [ port2Id ]
524+ : topology . portAngleForRegion2 ?. [ port2Id ] ??
525+ topology . portAngleForRegion1 [ port2Id ]
510526 const z1 = topology . portZ [ port1Id ]
511527 const z2 = topology . portZ [ port2Id ]
528+ scratch . lesserAngle = angle1 < angle2 ? angle1 : angle2
529+ scratch . greaterAngle = angle1 < angle2 ? angle2 : angle1
530+ scratch . layerMask = ( 1 << z1 ) | ( 1 << z2 )
531+ scratch . entryExitLayerChanges = z1 !== z2 ? 1 : 0
512532
513- if ( angle1 < angle2 ) {
514- return [ state . currentRouteNetId ! , angle1 , z1 , angle2 , z2 ]
515- }
516-
517- return [ state . currentRouteNetId ! , angle2 , z2 , angle1 , z1 ]
533+ return scratch
518534 }
519535
520536 appendSegmentToRegionCache (
@@ -524,30 +540,40 @@ export class TinyHyperGraphSolver extends BaseSolver {
524540 ) {
525541 const { topology, state } = this
526542 const regionCache = state . regionIntersectionCaches [ regionId ]
527- const newPair = this . buildDynamicAnglePair ( regionId , port1Id , port2Id )
543+ const segmentGeometry = this . populateSegmentGeometryScratch (
544+ regionId ,
545+ port1Id ,
546+ port2Id ,
547+ )
528548 const [
529549 newSameLayerIntersections ,
530550 newCrossLayerIntersections ,
531551 newEntryExitLayerChanges ,
532- ] = countNewIntersections ( regionCache , newPair )
533- const [ netId , lesserAngle , z1 , greaterAngle , z2 ] = newPair
552+ ] = countNewIntersectionsWithValues (
553+ regionCache ,
554+ state . currentRouteNetId ! ,
555+ segmentGeometry . lesserAngle ,
556+ segmentGeometry . greaterAngle ,
557+ segmentGeometry . layerMask ,
558+ segmentGeometry . entryExitLayerChanges ,
559+ )
534560 const nextLength = regionCache . netIds . length + 1
535561
536562 const netIds = new Int32Array ( nextLength )
537563 netIds . set ( regionCache . netIds )
538- netIds [ nextLength - 1 ] = netId
564+ netIds [ nextLength - 1 ] = state . currentRouteNetId !
539565
540566 const lesserAngles = new Int32Array ( nextLength )
541567 lesserAngles . set ( regionCache . lesserAngles )
542- lesserAngles [ nextLength - 1 ] = lesserAngle
568+ lesserAngles [ nextLength - 1 ] = segmentGeometry . lesserAngle
543569
544570 const greaterAngles = new Int32Array ( nextLength )
545571 greaterAngles . set ( regionCache . greaterAngles )
546- greaterAngles [ nextLength - 1 ] = greaterAngle
572+ greaterAngles [ nextLength - 1 ] = segmentGeometry . greaterAngle
547573
548574 const layerMasks = new Int32Array ( nextLength )
549575 layerMasks . set ( regionCache . layerMasks )
550- layerMasks [ nextLength - 1 ] = ( 1 << z1 ) | ( 1 << z2 )
576+ layerMasks [ nextLength - 1 ] = segmentGeometry . layerMask
551577
552578 const existingSameLayerIntersections =
553579 regionCache . existingSameLayerIntersections + newSameLayerIntersections
@@ -742,8 +768,7 @@ export class TinyHyperGraphSolver extends BaseSolver {
742768 const nextRegionId = currentCandidate . nextRegionId
743769
744770 const regionCache = state . regionIntersectionCaches [ nextRegionId ]
745-
746- const newPair = this . buildDynamicAnglePair (
771+ const segmentGeometry = this . populateSegmentGeometryScratch (
747772 nextRegionId ,
748773 currentCandidate . portId ,
749774 neighborPortId ,
@@ -753,7 +778,14 @@ export class TinyHyperGraphSolver extends BaseSolver {
753778 newSameLayerIntersections ,
754779 newCrossLayerIntersections ,
755780 newEntryExitLayerChanges ,
756- ] = countNewIntersections ( regionCache , newPair )
781+ ] = countNewIntersectionsWithValues (
782+ regionCache ,
783+ state . currentRouteNetId ! ,
784+ segmentGeometry . lesserAngle ,
785+ segmentGeometry . greaterAngle ,
786+ segmentGeometry . layerMask ,
787+ segmentGeometry . entryExitLayerChanges ,
788+ )
757789
758790 const newRegionCost =
759791 computeRegionCost (
0 commit comments