packages feed

twee-2.0: src/Twee/Index/Lookup.hs

-- Term indexing (perfect-ish discrimination trees).
-- This module contains the type definitions and lookup function.
-- We put lookup in a separate module because it needs to be compiled
-- with inlining switched up to max, and compiling the rest of the module
-- like that is too slow.
{-# LANGUAGE BangPatterns, RecordWildCards #-}
{-# OPTIONS_GHC -funfolding-creation-threshold=10000 -funfolding-use-threshold=10000 #-}
module Twee.Index.Lookup where

import Twee.Base hiding (var, fun, empty, size, singleton, prefix, funs)
import qualified Twee.Term as Term
import Twee.Term.Core(TermList(..))
import Twee.Array

data Index f a =
  Index {
    size   :: {-# UNPACK #-} !Int, -- size of smallest term, not including prefix
    prefix :: {-# UNPACK #-} !(TermList f),
    here   :: [a],
    fun    :: {-# UNPACK #-} !(Array (Index f a)),
    var    :: {-# UNPACK #-} !(VarIndex f a) } |
  Nil
  deriving Show

instance Default (Index f a) where def = Nil

data VarIndex f a =
  VarIndex {
    var0 :: !(Index f a),
    var1 :: !(Index f a),
    hole :: !(Index f a) }
  deriving Show

{-# INLINE newVarIndex #-}
newVarIndex :: VarIndex f a
newVarIndex = VarIndex Nil Nil Nil

{-# INLINE lookupVarIndex #-}
lookupVarIndex :: Var -> VarIndex f a -> Index f a
lookupVarIndex (V 0) vidx = var0 vidx
lookupVarIndex (V 1) vidx = var1 vidx
lookupVarIndex _ vidx = hole vidx

{-# INLINE updateVarIndex #-}
updateVarIndex :: Var -> Index f a -> VarIndex f a -> VarIndex f a
updateVarIndex (V 0) idx vidx = vidx { var0 = idx }
updateVarIndex (V 1) idx vidx = vidx { var1 = idx }
updateVarIndex _ idx vidx = vidx { hole = idx }

varIndexElems :: VarIndex f a -> [Index f a]
varIndexElems vidx = [var0 vidx, var1 vidx, hole vidx]

varIndexToList :: VarIndex f a -> [(Int, Index f a)]
varIndexToList vidx = [(0, var0 vidx), (1, var1 vidx), (2, hole vidx)]

varIndexCapacity :: Int
varIndexCapacity = 2

data Subst2 f = Subst2 {-# UNPACK #-} !Int {-# UNPACK #-} !Int {-# UNPACK #-} !Int {-# UNPACK #-} !Int

emptySubst2 :: Subst2 f
emptySubst2 = Subst2 0 0 0 0

{-# INLINE extend2 #-}
extend2 :: Var -> TermList f -> Subst2 f -> Maybe (Subst2 f)
extend2 (V 0) t (Subst2 _ 0 x y) = Just (Subst2 (low t) (high t) x y)
extend2 (V 0) t (Subst2 x y _ _) | t /= TermList x y (array t) = Nothing
extend2 (V 1) u (Subst2 x y _ 0) = Just (Subst2 x y (low u) (high u))
extend2 (V 1) u (Subst2 _ _ x y) | u /= TermList x y (array u) = Nothing
extend2 _ _ sub = Just sub

data Stack f a =
  Frame {
    frame_subst :: {-# UNPACK #-} !(Subst2 f),
    frame_term  :: {-# UNPACK #-} !(TermList f),
    frame_index :: !(Index f a),
    frame_rest  :: !(Stack f a) }
  | Yield {
    yield_found :: [a],
    yield_rest  :: !(Stack f a) }
  | Stop

step !_ !_ _ _ | False = undefined
step _ _ Nil rest = rest
step _ t Index{size = size, prefix = prefix} rest
  | lenList t < size + lenList prefix = rest
step sub t Index{..} rest = pref sub t prefix here fun var rest

pref !_ !_ !_ _ !_ !_ _ | False = undefined
pref _ Empty Empty [] _ _ rest = rest
pref _ Empty Empty here _ _ rest = Yield here rest
pref _ Empty _ _ _ _ _ = undefined -- implies lenList t < size + lenList prefix above
pref sub (Cons t ts) (Cons (Var x) us) here fun var rest =
  case extend2 x (Term.singleton t) sub of
    Nothing  -> rest
    Just sub -> pref sub ts us here fun var rest
pref sub (ConsSym (App f _) ts) (ConsSym (App g _) us) here fun var rest
  | f == g = pref sub ts us here fun var rest
pref _ _ (Cons _ _) _ _ _ rest = rest
pref sub t@(Cons u us) Empty _ fun var rest =
  tryFun sub v vs fun (tryVar sub u us var rest)
  where
    UnsafeConsSym v vs = t

    {-# INLINE tryFun #-}
    tryFun sub (App f _) ts fun rest =
      case fun ! fun_id f of
        Nil -> rest
        idx -> Frame sub ts idx rest
    tryFun _ _ _ _ rest = rest

    {-# INLINE tryVar #-}
    tryVar sub t ts var rest =
      foldr op rest (varIndexToList var)
      where
        op (x, idx@Index{}) rest
          | Just sub <- extend2 (V x) (Term.singleton t) sub =
              Frame sub ts idx rest
        op _ rest = rest