packages feed

moonlight-algebra-0.1.0.0: src-finite-lattice/Moonlight/FiniteLattice/Internal/Dense.hs

{-# LANGUAGE GHC2024 #-}

module Moonlight.FiniteLattice.Internal.Dense
  ( compileDensePlan,
  )
where

import Moonlight.FiniteLattice.Internal.Distributive
  ( ContextDistributiveRowsResult (..),
    distributivePlanFromRows,
  )
import Moonlight.FiniteLattice.Internal.Index
  ( ContextIndex (..),
    contextIndexValueForKey,
    decodeIndexKeys,
  )
import Moonlight.FiniteLattice.Internal.Key
  ( ContextKey (..),
    ContextKeySet,
    ContextKeyTable,
    contextKeySetToAscList,
    contextKeyTableGenerateM,
  )
import Moonlight.FiniteLattice.Internal.Layout
  ( checkedPairCellCount,
  )
import Moonlight.FiniteLattice.Internal.Plan
  ( ContextDenseRowsPlan (..),
    ContextDenseTablePlan (..),
    ContextMaskPlan (..),
    ContextPlan (..),
  )
import Moonlight.FiniteLattice.Internal.Relation
  ( ContextRowIndex,
    ContextRows,
    contextRowIndexFromRows,
    rowJoinCandidateKeys,
    rowJoinKeyMaybe,
    rowMeetCandidateKeys,
    rowMeetKeyMaybe,
  )
import Moonlight.FiniteLattice.Internal.Types
  ( ContextCompileLimits,
    ContextLatticeCompileError (..),
  )

compileDensePlan ::
  Ord c =>
  ContextCompileLimits ->
  ContextIndex c ->
  ContextKey ->
  ContextKey ->
  ContextRows ->
  ContextRows ->
  Either (ContextLatticeCompileError c) ContextPlan
compileDensePlan limits index topKey bottomKey upperRows lowerRows =
  case checkedPairCellCount limits (ciSize index) of
    Just pairCellCount -> do
      (joinTable, meetTable) <-
        compileDenseLatticeTables
          index
          pairCellCount
          upperRows
          lowerRows
          upperRowIndex
          lowerRowIndex
      pure
        ( DensePlan
            ContextDenseTablePlan
              { cdtpSize = ciSize index,
                cdtpUpperRows = upperRows,
                cdtpLowerRows = lowerRows,
                cdtpJoinTable = joinTable,
                cdtpMeetTable = meetTable
              }
        )
    Nothing ->
      case
        distributivePlanFromRows
          (ciSize index)
          topKey
          bottomKey
          upperRows
          lowerRows
          upperRowIndex
          lowerRowIndex
        of
        ContextRowJoinAbsent leftKey rightKey candidates ->
          Left
            ( ContextLatticeJoinDoesNotExist
                (contextIndexValueForKey index leftKey)
                (contextIndexValueForKey index rightKey)
                (decodeIndexKeys index candidates)
            )
        ContextRowMeetAbsent leftKey rightKey candidates ->
          Left
            ( ContextLatticeMeetDoesNotExist
                (contextIndexValueForKey index leftKey)
                (contextIndexValueForKey index rightKey)
                (decodeIndexKeys index candidates)
            )
        ContextDenseRowsValidated ->
          Right (denseRowsPlan upperRows lowerRows upperRowIndex lowerRowIndex)
        ContextDistributiveRowsPlan distributivePlan ->
          Right (MaskPlan (DistributivePlan distributivePlan))
  where
    upperRowIndex = contextRowIndexFromRows upperRows
    lowerRowIndex = contextRowIndexFromRows lowerRows

denseRowsPlan ::
  ContextRows ->
  ContextRows ->
  ContextRowIndex ->
  ContextRowIndex ->
  ContextPlan
denseRowsPlan upperRows lowerRows upperRowIndex lowerRowIndex =
  MaskPlan
    ( DenseRowsPlan
        ContextDenseRowsPlan
          { cdrpUpperRows = upperRows,
            cdrpLowerRows = lowerRows,
            cdrpUpperRowIndex = upperRowIndex,
            cdrpLowerRowIndex = lowerRowIndex
          }
    )

compileDenseLatticeTables ::
  Ord c =>
  ContextIndex c ->
  Int ->
  ContextRows ->
  ContextRows ->
  ContextRowIndex ->
  ContextRowIndex ->
  Either
    (ContextLatticeCompileError c)
    (ContextKeyTable, ContextKeyTable)
compileDenseLatticeTables index pairCellCount upperRows lowerRows upperRowIndex lowerRowIndex = do
  joinTable <-
    contextKeyTableGenerateM size pairCellCount $ \offset ->
      let (leftOrdinal, rightOrdinal) = offset `quotRem` size
       in leastUpperBoundKey
            index
            upperRows
            lowerRows
            upperRowIndex
            (ContextKey leftOrdinal)
            (ContextKey rightOrdinal)
  meetTable <-
    contextKeyTableGenerateM size pairCellCount $ \offset ->
      let (leftOrdinal, rightOrdinal) = offset `quotRem` size
       in greatestLowerBoundKey
            index
            upperRows
            lowerRows
            lowerRowIndex
            (ContextKey leftOrdinal)
            (ContextKey rightOrdinal)
  pure (joinTable, meetTable)
  where
    size = ciSize index

leastUpperBoundKey ::
  Ord c =>
  ContextIndex c ->
  ContextRows ->
  ContextRows ->
  ContextRowIndex ->
  ContextKey ->
  ContextKey ->
  Either (ContextLatticeCompileError c) ContextKey
leastUpperBoundKey index upperRows lowerRows upperRowIndex leftKey rightKey =
  case rowJoinKeyMaybe upperRows lowerRows upperRowIndex leftKey rightKey of
    Just joinKey -> Right joinKey
    Nothing ->
      selectUniqueJoinKey
        index
        leftKey
        rightKey
        (rowJoinCandidateKeys upperRows lowerRows leftKey rightKey)

greatestLowerBoundKey ::
  Ord c =>
  ContextIndex c ->
  ContextRows ->
  ContextRows ->
  ContextRowIndex ->
  ContextKey ->
  ContextKey ->
  Either (ContextLatticeCompileError c) ContextKey
greatestLowerBoundKey index upperRows lowerRows lowerRowIndex leftKey rightKey =
  case rowMeetKeyMaybe upperRows lowerRows lowerRowIndex leftKey rightKey of
    Just meetKey -> Right meetKey
    Nothing ->
      selectUniqueMeetKey
        index
        leftKey
        rightKey
        (rowMeetCandidateKeys upperRows lowerRows leftKey rightKey)

selectUniqueJoinKey ::
  Ord c =>
  ContextIndex c ->
  ContextKey ->
  ContextKey ->
  ContextKeySet ->
  Either (ContextLatticeCompileError c) ContextKey
selectUniqueJoinKey index leftKey rightKey candidates =
  case contextKeySetToAscList candidates of
    [keyOrdinal] -> Right (ContextKey keyOrdinal)
    _ ->
      Left
        ( ContextLatticeJoinDoesNotExist
            (contextIndexValueForKey index leftKey)
            (contextIndexValueForKey index rightKey)
            (decodeIndexKeys index candidates)
        )

selectUniqueMeetKey ::
  Ord c =>
  ContextIndex c ->
  ContextKey ->
  ContextKey ->
  ContextKeySet ->
  Either (ContextLatticeCompileError c) ContextKey
selectUniqueMeetKey index leftKey rightKey candidates =
  case contextKeySetToAscList candidates of
    [keyOrdinal] -> Right (ContextKey keyOrdinal)
    _ ->
      Left
        ( ContextLatticeMeetDoesNotExist
            (contextIndexValueForKey index leftKey)
            (contextIndexValueForKey index rightKey)
            (decodeIndexKeys index candidates)
        )