moonlight-triangulation-0.1.0.0: src-build/Moonlight/Triangulation/Internal/Join/Plan.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
-- | The sole physical planner for binary and n-ary joins. It derives exact
-- local compatibility facts, selects one schedule, and leaves execution to a
-- consumer; sequential and concurrent interpreters share the same tournament
-- tree rather than inventing pairing policies of their own.
module Moonlight.Triangulation.Internal.Join.Plan
( PairPlan (..)
, planPair
, TournamentPlan (..)
, planTournament
) where
import Data.List.NonEmpty (NonEmpty (..))
import Moonlight.Triangulation.Dcel (numVertices)
import Moonlight.Triangulation.Internal.Join.Seam (SeamPlan, planSeam)
import Moonlight.Triangulation.Internal.Join.SiteSet
( SiteSet
, siteSetFromTriangulation
, siteSetRelation
, siteSetUnionWith
)
import Moonlight.Triangulation.Internal.Representation (Triangulation)
import Moonlight.Triangulation.JoinSemilattice (JoinSemilattice (joinAnnotations))
import Moonlight.Triangulation.Internal.Types
( ConstraintMode (Unconstrained)
, SiteRelation (..)
)
data PairPlan annotation
= ReturnLeftOperand
| ReturnRightOperand
| InsertLeftIntoRight !(SiteSet annotation)
| InsertRightIntoLeft !(SiteSet annotation)
| MergeSeparated !SeamPlan
| RebuildCanonicalUnion !(SiteSet annotation)
-- | Stage cheap facts before exact set classification. Empty and structurally
-- identical operands return verbatim; skewed pairs preserve the larger value
-- through local insertion before seam planning is considered.
planPair
:: JoinSemilattice annotation
=> Triangulation 'Unconstrained annotation () () ()
-> Triangulation 'Unconstrained annotation () () ()
-> PairPlan annotation
planPair left right
| leftCount == 0 = ReturnRightOperand
| rightCount == 0 = ReturnLeftOperand
| left == right = ReturnLeftOperand
| insertionIsCheaper leftCount rightCount = InsertLeftIntoRight leftSites
| insertionIsCheaper rightCount leftCount = InsertRightIntoLeft rightSites
| Just seamPlan <- planSeam left right = MergeSeparated seamPlan
| otherwise =
case siteSetRelation leftSites rightSites of
EqualSites -> InsertLeftIntoRight leftSites
LeftProperSubset -> InsertLeftIntoRight leftSites
RightProperSubset -> InsertRightIntoLeft rightSites
DisjointSites -> rebuildUnion
PartialOverlap _ -> rebuildUnion
where
!leftCount = numVertices left
!rightCount = numVertices right
leftSites = siteSetFromTriangulation left
rightSites = siteSetFromTriangulation right
rebuildUnion =
RebuildCanonicalUnion
(siteSetUnionWith joinAnnotations leftSites rightSites)
-- A transaction reuses an existing topology only when the added side is small
-- enough that its expected local cavities beat one bulk sweep. This is an
-- internal cost estimate, deliberately not a caller-controlled threshold.
insertionIsCheaper :: Int -> Int -> Bool
insertionIsCheaper addition base = addition <= 64 || addition <= base `quot` 8
{-# INLINE insertionIsCheaper #-}
-- | A deterministic dependency graph. Leaves retain meshes as values; no site
-- flattening occurs, so singleton and repeated-value shortcut semantics remain
-- those of the binary operation. Duplicate operands need no planning pass:
-- every adjacent pair reaches the binary operation, whose structural-equality
-- shortcut already returns the operand verbatim, so a dedup here would buy a
-- quadratic scan of whole meshes to skip work the executor skips anyway.
data TournamentPlan mesh
= TournamentLeaf !mesh
| TournamentNode !(TournamentPlan mesh) !(TournamentPlan mesh)
planTournament :: NonEmpty mesh -> TournamentPlan mesh
planTournament = buildBalanced . fmap TournamentLeaf
where
buildBalanced :: NonEmpty (TournamentPlan value) -> TournamentPlan value
buildBalanced (single :| []) = single
buildBalanced plans = buildBalanced (pairRound plans)
pairRound :: NonEmpty (TournamentPlan value) -> NonEmpty (TournamentPlan value)
pairRound (left :| right : rest) =
TournamentNode left right :| pairTail rest
pairRound (single :| []) = single :| []
pairTail :: [TournamentPlan value] -> [TournamentPlan value]
pairTail (left : right : rest) = TournamentNode left right : pairTail rest
pairTail rest = rest