switch implementation of heap from being based on heap.sml (heap as described by one of Chris Okasaki's papers) to being based on bin-vec.sml (simple vector storing elements in sorted order); more performant this way for cache reasons

This commit is contained in:
2025-01-22 18:22:34 +00:00
parent c8c1818d24
commit 174a99a5a0
4 changed files with 90 additions and 208 deletions

View File

@@ -12,7 +12,7 @@ struct
, distSoFar: int
}
type state = ValSet.elem vector * DistHeap.t
type state = ValSet.elem vector * DistVec.elem vector
fun isBetween (p1, check, p2) = check >= p1 andalso check <= p2
@@ -122,11 +122,10 @@ struct
else
(* key not explored, so add to queue *)
let
val q =
DistHeap.insert
( {distance = dist, id = foldPlatID, comesFrom = fromPlatID}
, q
)
val insRecord =
{distance = dist, id = foldPlatID, comesFrom = fromPlatID}
val insPos = DistVec.findInsPos (insRecord, q)
val q = DistVec.insert (q, insRecord, insPos)
in
(eVals, q)
end
@@ -134,9 +133,10 @@ struct
else
(* key not explored, so add to queue *)
let
val q =
DistHeap.insert
({distance = dist, id = foldPlatID, comesFrom = fromPlatID}, q)
val insRecord =
{distance = dist, id = foldPlatID, comesFrom = fromPlatID}
val insPos = DistVec.findInsPos (insRecord, q)
val q = DistVec.insert (q, insRecord, insPos)
in
(eVals, q)
end
@@ -229,17 +229,21 @@ struct
end
fun filterMinDuplicates (q, eKeys) =
let
val {id = min, ...} = DistHeap.findMin q
val pos = IntSet.findInsPos (min, eKeys)
in
if IntSet.contains (min, eKeys) then
let val q = DistHeap.deleteMin q
in filterMinDuplicates (q, eKeys)
end
else
q
end
if DistVec.isEmpty q then
q
else
let
val {id = min, ...} = DistVec.findMin q
val pos = IntSet.findInsPos (min, eKeys)
in
if IntSet.contains (min, eKeys) then
let val q = DistVec.deleteMin q
in filterMinDuplicates (q, eKeys)
end
else
q
end
fun helpGetPathList (curID, eID, eKeys, eVals, acc) =
if curID = eID then
@@ -283,57 +287,51 @@ struct
if IntSet.contains (pID, eKeys) then
(* return path if we explored pid *)
getPathList (pID, eID, eKeys, eVals)
else (* continue dijkstra's algorithm *) if DistVec.isEmpty q then
(* return empty list to signify that there is no path *)
[]
else
(* continue dijkstra's algorithm *)
(* find reachable values from min in quad tree *)
let
val {distance = distSoFar, id = minID, comesFrom} = DistHeap.findMin q
val {distance = distSoFar, id = minID, comesFrom} = DistVec.findMin q
val plat = Platform.find (minID, platforms)
(* add explored *)
val insPos = IntSet.findInsPos (minID, eKeys)
val eKeys = IntSet.insert (eKeys, minID, insPos)
val eVals =
ValSet.insert
(eVals, {distance = distSoFar, from = comesFrom}, insPos)
val env =
{ platforms = platforms
, currentPlat = plat
, eKeys = eKeys
, distSoFar = distSoFar
}
val state = (eVals, q)
(* calculate area to fold over quad tree *)
val ww = Constants.worldWidth
val wh = Constants.worldHeight
val {x, y, width, ...} = plat
val y = y - Constants.jumpLimit
val height = wh - y
(* fold over quad tree, updating any distances
* we find the shortest path for *)
val (eVals, q) = addPlatforms (0, (eVals, q), env)
in
if minID = ~1 then
(* return empty list to signify that there is no path *)
[]
else
(* find reachable values from min in quad tree *)
let
val plat = Platform.find (minID, platforms)
(* add explored *)
val insPos = IntSet.findInsPos (minID, eKeys)
val eKeys = IntSet.insert (eKeys, minID, insPos)
val eVals =
ValSet.insert
(eVals, {distance = distSoFar, from = comesFrom}, insPos)
val env =
{ platforms = platforms
, currentPlat = plat
, eKeys = eKeys
, distSoFar = distSoFar
}
val state = (eVals, q)
(* calculate area to fold over quad tree *)
val ww = Constants.worldWidth
val wh = Constants.worldHeight
val {x, y, width, ...} = plat
val y = y - Constants.jumpLimit
val height = wh - y
(* fold over quad tree, updating any distances
* we find the shortest path for *)
val (eVals, q) = addPlatforms (0, (eVals, q), env)
in
loop (pID, eID, platforms, platformTree, q, eKeys, eVals)
end
loop (pID, eID, platforms, platformTree, q, eKeys, eVals)
end
end
fun start (pID, eID, platforms, platformTree) =
let
(* initialise data structures: the priority queue and the explored map *)
val q = DistHeap.empty
val q = DistHeap.insert ({distance = 0, id = eID, comesFrom = eID}, q)
val q = DistVec.fromList [{distance = 0, id = eID, comesFrom = eID}]
(* explored keys and values *)
val eKeys = IntSet.empty