HappyTree 0.2018.1.5 → 0.2018.1.7
raw patch · 5 files changed
+248/−143 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Lib: Leaf :: (NP I a -> b) -> DecisionTree
- Lib: RevAppendSym0KindInference :: RevAppendSym0
- Lib: RevAppendSym1KindInference :: RevAppendSym1
- Lib: SplitOnOrd :: (NS (SplitOrderOn DecisionTree b) (TakeElem a)) -> DecisionTree
- Lib: SplitOnStructure :: (NS (SplitStructureOn DecisionTree b) (TakeElem a)) -> DecisionTree
- Lib: SplitOrderOn :: (Dict (SplitOrd (Fst a)), (Fst a), dt (Fst a : Snd a) b, dt (Snd a) b, dt (Fst a : Snd a) b) -> SplitOrderOn dt b a
- Lib: SplitStructureOn :: (Dict (SplitStructure (Fst a)), NP (SplitStructureOnAux dt b (Snd a)) (SplitCode (Fst a))) -> SplitStructureOn dt b a
- Lib: SplitStructureOnAux :: dt (r :++ a) b -> SplitStructureOnAux dt b r a
- Lib: TakeElemAuxSym0KindInference :: TakeElemAuxSym0
- Lib: TakeElemAuxSym1KindInference :: TakeElemAuxSym1
- Lib: TakeElemSym0KindInference :: TakeElemSym0
- Lib: TakeElemTypeAux :: (Fst a, NP I (Snd a)) -> TakeElemTypeAux a
- Lib: [runSplitOrderOn] :: SplitOrderOn dt b a -> (Dict (SplitOrd (Fst a)), (Fst a), dt (Fst a : Snd a) b, dt (Snd a) b, dt (Fst a : Snd a) b)
- Lib: [runSplitStructureOnAux] :: SplitStructureOnAux dt b r a -> dt (r :++ a) b
- Lib: [runSplitStructureOn] :: SplitStructureOn dt b a -> (Dict (SplitStructure (Fst a)), NP (SplitStructureOnAux dt b (Snd a)) (SplitCode (Fst a)))
- Lib: [runTakeElemTypeAux] :: TakeElemTypeAux a -> (Fst a, NP I (Snd a))
- Lib: class Ord a => SplitOrd a
- Lib: class (SplitCode a ~ Code a, Generic a) => SplitStructure a where {
- Lib: data DecisionTree (a :: [*]) (b :: *)
- Lib: data RevAppendSym0 (l_ahtn :: TyFun [a6989586621679076944] (TyFun [a6989586621679076944] [a6989586621679076944] -> Type))
- Lib: data RevAppendSym1 (l_ahtl :: [a6989586621679076944]) (l_ahtk :: TyFun [a6989586621679076944] [a6989586621679076944])
- Lib: data TakeElemAuxSym0 (l_ahtA :: TyFun [a6989586621679076943] (TyFun [a6989586621679076943] [(a6989586621679076943, [a6989586621679076943])] -> Type))
- Lib: data TakeElemAuxSym1 (l_ahty :: [a6989586621679076943]) (l_ahtx :: TyFun [a6989586621679076943] [(a6989586621679076943, [a6989586621679076943])])
- Lib: data TakeElemSym0 (l_ahtL :: TyFun [a6989586621679076942] [(a6989586621679076942, [a6989586621679076942])])
- Lib: dictSList :: SList a -> Dict (SListI a)
- Lib: eval :: DecisionTree a b -> NP I a -> b
- Lib: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Lib.RevAppendSym0
- Lib: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Lib.RevAppendSym1
- Lib: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Lib.TakeElemAuxSym0
- Lib: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Lib.TakeElemAuxSym1
- Lib: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Lib.TakeElemSym0
- Lib: newtype SplitOrderOn dt b a
- Lib: newtype SplitStructureOn dt b a
- Lib: newtype SplitStructureOnAux dt b r a
- Lib: newtype TakeElemTypeAux a
- Lib: npToSList :: NP f a -> SList a
- Lib: revAppend :: [a_aht6] -> [a_aht6] -> [a_aht6]
- Lib: revAppendDT :: NP f a -> NP f b -> NP f (RevAppend a b)
- Lib: sListCons :: Proxy a -> SList b -> SList (a : b)
- Lib: sRevAppend :: forall (t_ahtP :: [a_aht6]) (t_ahtQ :: [a_aht6]). Sing t_ahtP -> Sing t_ahtQ -> Sing (Apply (Apply RevAppendSym0 t_ahtP) t_ahtQ :: [a_aht6])
- Lib: sTakeElem :: forall (t_ahtT :: [a_aht4]). Sing t_ahtT -> Sing (Apply TakeElemSym0 t_ahtT :: [(a_aht4, [a_aht4])])
- Lib: sTakeElemAux :: forall (t_ahtR :: [a_aht5]) (t_ahtS :: [a_aht5]). Sing t_ahtR -> Sing t_ahtS -> Sing (Apply (Apply TakeElemAuxSym0 t_ahtR) t_ahtS :: [(a_aht5, [a_aht5])])
- Lib: someFunc :: IO ()
- Lib: sopAppend :: NP f a -> NP f b -> NP f (a :++ b)
- Lib: splitStructureFrom :: SplitStructure a => a -> SOP I (SplitCode a)
- Lib: splitStructureTo :: SplitStructure a => SOP I (SplitCode a) -> a
- Lib: takeElem :: [a_aht4] -> [(a_aht4, [a_aht4])]
- Lib: takeElemAux :: [a_aht5] -> [a_aht5] -> [(a_aht5, [a_aht5])]
- Lib: takeElemAuxDT :: NP I a -> NP I b -> TakeElemAuxType a b
- Lib: takeElemAuxDTSing :: SList a -> SList b -> SList (TakeElemAux a b)
- Lib: takeElemAuxDTSingAux :: SList (a : as) -> Proxy a
- Lib: takeElemDT :: NP I a -> TakeElemType a
- Lib: type RevAppendSym2 (t_ahti :: [a6989586621679076944]) (t_ahtj :: [a6989586621679076944]) = RevAppend t_ahti t_ahtj
- Lib: type SplitCode a = Code a;
- Lib: type TakeElemAuxSym2 (t_ahtv :: [a6989586621679076943]) (t_ahtw :: [a6989586621679076943]) = TakeElemAux t_ahtv t_ahtw
- Lib: type TakeElemSym1 (t_ahtK :: [a6989586621679076942]) = TakeElem t_ahtK
- Lib: type family SplitCode a :: [[*]];
- Lib: unSListCons :: forall (a :: [k]). SList (_ : a) -> SList a
- Lib: }
+ Data.HappyTree: BuildAuxAux :: [(a, Fst b, NP I (Snd b))] -> BuildAuxAux a b
+ Data.HappyTree: Deciding :: Double -> Score
+ Data.HappyTree: Destructing :: Score
+ Data.HappyTree: Index :: NS (IndexAux x) l -> Index
+ Data.HappyTree: IndexAux :: IndexAux
+ Data.HappyTree: Leaf :: (NP I a -> b) -> DecisionTree
+ Data.HappyTree: RevAppendSym0KindInference :: RevAppendSym0
+ Data.HappyTree: RevAppendSym1KindInference :: RevAppendSym1
+ Data.HappyTree: SelElemAuxSym0KindInference :: SelElemAuxSym0
+ Data.HappyTree: SelElemAuxSym1KindInference :: SelElemAuxSym1
+ Data.HappyTree: SelElemSym0KindInference :: SelElemSym0
+ Data.HappyTree: SelElemTypeAux :: (Fst a) -> (NP I (Snd a)) -> SelElemTypeAux a
+ Data.HappyTree: SelElemTypeAuxIndex :: (Index env (Fst a)) -> (NP (Index env) (Snd a)) -> SelElemTypeAuxIndex env a
+ Data.HappyTree: Split :: (NS (SplitOn b) (SelElem a)) -> DecisionTree
+ Data.HappyTree: SplitFun :: (forall b. [(a, b)] -> [SplitFunAux env a b]) -> SplitFun a
+ Data.HappyTree: SplitFunAux :: (a -> SOP I c) -> (NP (SplitFunAuxAux b) c) -> SplitFunAux env a b
+ Data.HappyTree: SplitFunAuxAux :: [(NP I d, b)] -> SplitFunAuxAux b d
+ Data.HappyTree: SplitOn :: (Fst x -> SOP I c) -> (NP (SplitOnAux (Snd x) b) c) -> SplitOn
+ Data.HappyTree: SplitOnAux :: DecisionTree (c :++ a) b -> SplitOnAux a b c
+ Data.HappyTree: WithScore :: (Score, (SplitOn b x)) -> WithScore b x
+ Data.HappyTree: [runBuildAuxAux] :: BuildAuxAux a b -> [(a, Fst b, NP I (Snd b))]
+ Data.HappyTree: [runIndex] :: Index -> NS (IndexAux x) l
+ Data.HappyTree: [runSplitFunAuxAux] :: SplitFunAuxAux b d -> [(NP I d, b)]
+ Data.HappyTree: [runSplitOnAux] :: SplitOnAux a b c -> DecisionTree (c :++ a) b
+ Data.HappyTree: [runWithScore] :: WithScore b x -> (Score, (SplitOn b x))
+ Data.HappyTree: build :: (All (GetIndex env) a, SListI env, Ord b) => SplitFuns env env -> [(NP I a, b)] -> b -> DecisionTree a b
+ Data.HappyTree: buildAux :: (SListI env, Ord b) => NP (Index env) a -> SplitFuns env env -> [(NP I a, b)] -> b -> DecisionTree a b
+ Data.HappyTree: buildTree :: (SListI env, Ord b) => SplitFuns env env -> NP (Index env) (Snd a1) -> b -> SplitFunAux env (Fst a1) (b, NP I (Snd a1)) -> (Score, SplitOn b a1)
+ Data.HappyTree: class GetIndex l x
+ Data.HappyTree: data DecisionTree (a :: [*]) (b :: *)
+ Data.HappyTree: data IndexAux (l :: k) (r :: k)
+ Data.HappyTree: data RevAppendSym0 (l_ahn3 :: TyFun [a6989586621679075662] (TyFun [a6989586621679075662] [a6989586621679075662] -> Type))
+ Data.HappyTree: data RevAppendSym1 (l_ahn1 :: [a6989586621679075662]) (l_ahn0 :: TyFun [a6989586621679075662] [a6989586621679075662])
+ Data.HappyTree: data Score
+ Data.HappyTree: data SelElemAuxSym0 (l_ahng :: TyFun [a6989586621679075661] (TyFun [a6989586621679075661] [(a6989586621679075661, [a6989586621679075661])] -> Type))
+ Data.HappyTree: data SelElemAuxSym1 (l_ahne :: [a6989586621679075661]) (l_ahnd :: TyFun [a6989586621679075661] [(a6989586621679075661, [a6989586621679075661])])
+ Data.HappyTree: data SelElemSym0 (l_ahnr :: TyFun [a6989586621679075660] [(a6989586621679075660, [a6989586621679075660])])
+ Data.HappyTree: data SelElemTypeAux a
+ Data.HappyTree: data SelElemTypeAuxIndex env a
+ Data.HappyTree: data SplitFun (env :: [*]) a
+ Data.HappyTree: data SplitFunAux env a b
+ Data.HappyTree: data SplitOn (b :: *) (x :: (*, [*]))
+ Data.HappyTree: dictSList :: SList a -> Dict (SListI a)
+ Data.HappyTree: entropy :: Ord a => [a] -> Double
+ Data.HappyTree: eval :: DecisionTree a b -> NP I a -> b
+ Data.HappyTree: fromIndex :: SListI l => NP f l -> Index l x -> f x
+ Data.HappyTree: fromSFA :: SplitFunAux (env :: [*]) a b -> Proxy (All (GetIndex env))
+ Data.HappyTree: getIndex :: GetIndex l x => Proxy l -> Proxy x -> Index l x
+ Data.HappyTree: getIndex2 :: All (GetIndex l) r => SList r -> NP (Index l) r
+ Data.HappyTree: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Data.HappyTree.RevAppendSym0
+ Data.HappyTree: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Data.HappyTree.RevAppendSym1
+ Data.HappyTree: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Data.HappyTree.SelElemAuxSym0
+ Data.HappyTree: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Data.HappyTree.SelElemAuxSym1
+ Data.HappyTree: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Data.HappyTree.SelElemSym0
+ Data.HappyTree: instance GHC.Base.Monoid (Data.HappyTree.SplitFun env a)
+ Data.HappyTree: instance GHC.Classes.Eq Data.HappyTree.Score
+ Data.HappyTree: instance GHC.Classes.Ord Data.HappyTree.Score
+ Data.HappyTree: instance forall k (l :: k) (r :: [k]). Data.HappyTree.GetIndex (l : r) l
+ Data.HappyTree: instance forall k (r :: [k]) (x :: k) (l :: k). Data.HappyTree.GetIndex r x => Data.HappyTree.GetIndex (l : r) x
+ Data.HappyTree: mode :: Ord a => [a] -> a
+ Data.HappyTree: nMinOn :: Ord b => (forall x. f x -> b) -> NP f a -> Maybe (NS f a)
+ Data.HappyTree: nMinOnAux :: Ord b => (forall x. f x -> b) -> NP f a -> Maybe (b, NS f a)
+ Data.HappyTree: newtype BuildAuxAux a b
+ Data.HappyTree: newtype Index (l :: [k]) (x :: k)
+ Data.HappyTree: newtype SplitFunAuxAux b d
+ Data.HappyTree: newtype SplitOnAux a b c
+ Data.HappyTree: newtype WithScore b x
+ Data.HappyTree: npAppend :: NP f a -> NP f b -> NP f (a :++ b)
+ Data.HappyTree: npRevAppend :: NP f a -> NP f b -> NP f (RevAppend a b)
+ Data.HappyTree: npSelElem :: NP I a -> SelElemAuxType '[] a
+ Data.HappyTree: npSelElemAux :: NP I a -> NP I b -> SelElemAuxType a b
+ Data.HappyTree: npToSList :: NP f a -> SList a
+ Data.HappyTree: revAppend :: [a_ah8q] -> [a_ah8q] -> [a_ah8q]
+ Data.HappyTree: runSplitFun :: () => SplitFun env a -> [(a, b)] -> [SplitFunAux env a b]
+ Data.HappyTree: sListCons :: Proxy a -> SList b -> SList (a : b)
+ Data.HappyTree: sRevAppend :: forall (t_ahnv :: [a_ah8q]) (t_ahnw :: [a_ah8q]). Sing t_ahnv -> Sing t_ahnw -> Sing (Apply (Apply RevAppendSym0 t_ahnv) t_ahnw :: [a_ah8q])
+ Data.HappyTree: sSelElem :: forall (t_ahnz :: [a_ah8o]). Sing t_ahnz -> Sing (Apply SelElemSym0 t_ahnz :: [(a_ah8o, [a_ah8o])])
+ Data.HappyTree: sSelElemAux :: forall (t_ahnx :: [a_ah8p]) (t_ahny :: [a_ah8p]). Sing t_ahnx -> Sing t_ahny -> Sing (Apply (Apply SelElemAuxSym0 t_ahnx) t_ahny :: [(a_ah8p, [a_ah8p])])
+ Data.HappyTree: selElem :: [a_ah8o] -> [(a_ah8o, [a_ah8o])]
+ Data.HappyTree: selElemAux :: [a_ah8p] -> [a_ah8p] -> [(a_ah8p, [a_ah8p])]
+ Data.HappyTree: selElemTypeAuxIndex :: NP (Index env) a -> NP (Index env) b -> NP (SelElemTypeAuxIndex env) (SelElemAux a b)
+ Data.HappyTree: splitFunAuxP :: (SListI2 c, All2 (GetIndex env) c) => Proxy c -> (a -> SOP I c) -> NP (SplitFunAuxAux b) c -> SplitFunAux env a b
+ Data.HappyTree: splitOrd :: (Ord a, GetIndex env a) => SplitFun env a
+ Data.HappyTree: splitStatic :: (SListI2 c, All2 (GetIndex env) c) => (a -> SOP I c) -> SplitFun env a
+ Data.HappyTree: splitStaticAux :: SplitFun env a -> Proxy (GetIndex env)
+ Data.HappyTree: splitStructure :: (Generic a, SListI2 (Code a), All2 (GetIndex env) (Code a)) => SplitFun env a
+ Data.HappyTree: takeElem :: [a] -> [([a], a, [a])]
+ Data.HappyTree: takeElemAux :: [a] -> [a] -> [([a], a, [a])]
+ Data.HappyTree: type RevAppendSym2 (t_ahmY :: [a6989586621679075662]) (t_ahmZ :: [a6989586621679075662]) = RevAppend t_ahmY t_ahmZ
+ Data.HappyTree: type SelElemAuxSym2 (t_ahnb :: [a6989586621679075661]) (t_ahnc :: [a6989586621679075661]) = SelElemAux t_ahnb t_ahnc
+ Data.HappyTree: type SelElemAuxType a b = NP SelElemTypeAux (SelElemAux a b)
+ Data.HappyTree: type SelElemSym1 (t_ahnq :: [a6989586621679075660]) = SelElem t_ahnq
+ Data.HappyTree: type SelElemType a = SelElemAuxType '[] a
+ Data.HappyTree: type SplitFuns cur env = NP (SplitFun env) cur
Files
- HappyTree.cabal +3/−18
- README.md +16/−0
- app/Main.hs +0/−6
- src/Data/HappyTree.hs +229/−0
- src/Lib.hs +0/−119
HappyTree.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: ca077430f4b90fc7a4a71fa0738c6711a609f4b20ff2f746b4e91c7aa4cc897c+-- hash: 8a83dd3398398752373163bc2904bfb643a36edcaa02323e902e5632931dfed3 name: HappyTree-version: 0.2018.1.5+version: 0.2018.1.7 description: Please see the README on Github at <https://github.com/MarisaKirisame/HappyTree#readme> homepage: https://github.com/MarisaKirisame/HappyTree#readme bug-reports: https://github.com/MarisaKirisame/HappyTree/issues@@ -35,22 +35,7 @@ , generics-sop ==0.3.1.0 , singletons ==2.3.1 exposed-modules:- Lib- other-modules:- Paths_HappyTree- default-language: Haskell2010--executable HappyTree-exe- main-is: Main.hs- hs-source-dirs:- app- ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wno-partial-type-signatures- build-depends:- HappyTree- , base >=4.7 && <5- , constraints ==0.9.1- , generics-sop ==0.3.1.0- , singletons ==2.3.1+ Data.HappyTree other-modules: Paths_HappyTree default-language: Haskell2010
README.md view
@@ -1,1 +1,17 @@ # HappyTree++Happy Tree is a end-to-end decision tree library in Haskell.++That mean, it's main selling point is, while most decision tree library support splitting on Discrete Category/Continuous Variable (Read: essentially Int and Double), Happy Tree let you split on any type, as long as you specify how to split on it.++Want to decide on List or AST? No Problem!++Want to use your custom quantile search like thingy to speed up splitting on continuous variable? Piece of Cake!++Want to use different split strategy at the same time, splitting on the finest choice? You Name It: It form a monoid.++## Known Problem++Can only split on finitely many type now. Cannot split on++data Perfect a = Here a | More (Perfect (a, a)).
− app/Main.hs
@@ -1,6 +0,0 @@-module Main where--import Lib--main :: IO ()-main = someFunc
+ src/Data/HappyTree.hs view
@@ -0,0 +1,229 @@+{-# LANGUAGE + DataKinds,+ TypeFamilies,+ TemplateHaskell,+ PolyKinds,+ ExistentialQuantification,+ ScopedTypeVariables,+ UndecidableInstances,+ TypeOperators,+ UndecidableSuperClasses,+ GADTs,+ PartialTypeSignatures,+ RankNTypes,+ FlexibleInstances,+ MultiParamTypeClasses,+ FlexibleContexts+#-}++module Data.HappyTree where++import Data.Singletons.Prelude+import Data.Singletons.TH+import qualified Generics.SOP as SOP+import Data.Constraint+import Data.List+import Data.Ord+import Data.Maybe++$(singletons [d|+ revAppend :: [a] -> [a] -> [a]+ revAppend [] x = x+ revAppend (x:xs) n = revAppend xs (x:n) + selElemAux :: [a] -> [a] -> [(a, [a])]+ selElemAux l [] = []+ selElemAux l (r:rs) = (r, revAppend l rs) : selElemAux (r:l) rs + selElem :: [a] -> [(a, [a])]+ selElem = selElemAux []+ |])++takeElemAux :: [a] -> [a] -> [([a], a, [a])]+takeElemAux l [] = []+takeElemAux l (r:rs) = (reverse l, r, rs) : takeElemAux (r:l) rs++takeElem :: [a] -> [([a], a, [a])]+takeElem = takeElemAux []++data SelElemTypeAux a = SelElemTypeAux (Fst a) (SOP.NP SOP.I (Snd a))+type SelElemAuxType a b = SOP.NP SelElemTypeAux (SelElemAux a b)+type SelElemType a = SelElemAuxType '[] a++npRevAppend :: SOP.NP f a -> SOP.NP f b -> SOP.NP f (RevAppend a b)+npRevAppend SOP.Nil x = x+npRevAppend (x SOP.:* y) z = npRevAppend y (x SOP.:* z)++npSelElemAux :: SOP.NP SOP.I a -> SOP.NP SOP.I b -> SelElemAuxType a b+npSelElemAux _ SOP.Nil = SOP.Nil+npSelElemAux x (SOP.I y SOP.:* z) = SelElemTypeAux y (npRevAppend x z) SOP.:* npSelElemAux (SOP.I y SOP.:* x) z+npSelElem :: SOP.NP SOP.I a -> SelElemAuxType '[] a+npSelElem = npSelElemAux SOP.Nil++dictSList :: SOP.SList a -> Dict (SOP.SListI a)+dictSList SOP.SNil = Dict+dictSList SOP.SCons = Dict++sListCons :: Proxy a -> SOP.SList b -> SOP.SList (a:b)+sListCons _ x = dictSList x `withDict` SOP.SCons++npAppend :: SOP.NP f a -> SOP.NP f b -> SOP.NP f (a :++ b)+npAppend SOP.Nil x = x+npAppend (x SOP.:* y) z = x SOP.:* npAppend y z++npToSList :: SOP.NP f a -> SOP.SList a+npToSList SOP.Nil = SOP.SNil+npToSList (_ SOP.:* x) = sListCons Proxy (npToSList x)++newtype SplitOnAux a b c = SplitOnAux { runSplitOnAux :: DecisionTree (c :++ a) b }++data SplitOn (b :: *) (x :: (*, [*])) =+ forall (c :: [[*]]) . SOP.SListI c => SplitOn (Fst x -> SOP.SOP SOP.I c) (SOP.NP (SplitOnAux (Snd x) b) c)++data DecisionTree (a :: [*]) (b :: *) = Leaf (SOP.NP SOP.I a -> b) | Split (SOP.NS (SplitOn b) (SelElem a))++eval :: DecisionTree a b -> SOP.NP SOP.I a -> b+eval (Leaf f) x = f x+eval (Split f) x = dictSList (npToSList sex) `withDict` SOP.hcollapse (SOP.hzipWith onTree sex f)+ where+ sex = npSelElem x+ onTree :: SelElemTypeAux c -> SplitOn b c -> SOP.K b _+ onTree (SelElemTypeAux a b) (SplitOn c d) = + let SOP.SOP e = c a in SOP.K $+ SOP.hcollapse $ SOP.hzipWith (\(SplitOnAux f) g -> SOP.K $ eval f (npAppend g b)) d e++entropy :: Ord a => [a] -> Double+entropy x = sum $ map (\y -> let py = fromIntegral (length y) / lenx in -py * log py) $ group $ sort x+ where+ lenx = fromIntegral $ length x :: Double++data IndexAux (l :: k) (r :: k) = l ~ r => IndexAux+newtype Index (l :: [k]) (x :: k) = Index { runIndex :: SOP.NS (IndexAux x) l }++fromIndex :: SOP.SListI l => SOP.NP f l -> Index l x -> f x+fromIndex l (Index r) = SOP.hcollapse $ SOP.hzipWith (\x IndexAux -> SOP.K x) l r++class GetIndex l x where+ getIndex :: Proxy l -> Proxy x -> Index l x++instance {-# OVERLAPPABLE #-} GetIndex r x => GetIndex (l:r) x where+ getIndex _ _ = Index $ SOP.S $ runIndex $ getIndex Proxy Proxy++instance {-# OVERLAPPING #-} GetIndex (l:r) l where+ getIndex _ _ = Index $ SOP.Z IndexAux++newtype SplitFunAuxAux b d = SplitFunAuxAux { runSplitFunAuxAux :: [(SOP.NP SOP.I d, b)] }+data SplitFunAux env a b = forall (c :: [[*]]) . (SOP.SListI2 c, SOP.All2 (GetIndex env) c) =>+ SplitFunAux (a -> SOP.SOP SOP.I c) (SOP.NP (SplitFunAuxAux b) c)+splitFunAuxP :: (SOP.SListI2 c, SOP.All2 (GetIndex env) c) => Proxy c -> (a -> SOP.SOP SOP.I c) -> SOP.NP (SplitFunAuxAux b) c -> SplitFunAux env a b+splitFunAuxP _ = SplitFunAux++data SplitFun (env :: [*]) a = SplitFun (forall b . [(a, b)] -> [SplitFunAux env a b])+runSplitFun (SplitFun f) x = f x++type SplitFuns cur env = SOP.NP (SplitFun env) cur++instance Monoid (SplitFun env a) where+ mempty = SplitFun (const [])+ SplitFun l `mappend` SplitFun r = SplitFun (\b -> l b ++ r b)++splitStaticAux :: SplitFun env a -> Proxy (GetIndex env)+splitStaticAux _ = Proxy++splitStatic :: (SOP.SListI2 c, SOP.All2 (GetIndex env) c) => (a -> SOP.SOP SOP.I c) -> SplitFun env a+splitStatic split = res where+ res = SplitFun $ \x ->+ [SplitFunAux+ split+ (foldl join def $ map (\(a, b) -> SOP.hexpand (SplitFunAuxAux []) $ SOP.hmap (\c -> SplitFunAuxAux [(c, b)]) $ SOP.unSOP $ split a) x)]+ join :: SOP.SListI2 c => SOP.NP (SplitFunAuxAux b) c -> SOP.NP (SplitFunAuxAux b) c -> SOP.NP (SplitFunAuxAux b) c+ join = SOP.hzipWith (\(SplitFunAuxAux l) (SplitFunAuxAux r) -> SplitFunAuxAux $ l ++ r)+ def :: SOP.SListI2 c => SOP.NP (SplitFunAuxAux b) c+ def = SOP.hpure $ SplitFunAuxAux []++splitOrd :: (Ord a, GetIndex env a) => SplitFun env a+splitOrd = SplitFun $+ map (\(x, y, z) -> splitFunAuxP (Proxy :: Proxy ['[a], '[], '[a]])+ (\a -> SOP.SOP $ case a `compare` fst (head y) of+ LT -> SOP.Z $ SOP.I a SOP.:* SOP.Nil+ EQ -> SOP.S $ SOP.Z SOP.Nil+ GT -> SOP.S $ SOP.S $ SOP.Z $ SOP.I a SOP.:* SOP.Nil)+ (SplitFunAuxAux (map func $ concat x) SOP.:* SplitFunAuxAux (map (\(_, a) -> (SOP.Nil, a)) y) SOP.:* SplitFunAuxAux (map func $ concat z) SOP.:* SOP.Nil)) .+ takeElem . groupBy (\(l, _) (r, _) -> l == r) . sortBy (comparing fst)+ where+ func (a, b) = (SOP.I a SOP.:* SOP.Nil, b)++splitStructure :: (SOP.Generic a, SOP.SListI2 (SOP.Code a), SOP.All2 (GetIndex env) (SOP.Code a)) => SplitFun env a+splitStructure = splitStatic SOP.from++getIndex2 :: SOP.All (GetIndex l) r => SOP.SList r -> SOP.NP (Index l) r+getIndex2 SOP.SNil = SOP.Nil+getIndex2 SOP.SCons = getIndex Proxy Proxy SOP.:* getIndex2 SOP.sList++mode :: Ord a => [a] -> a+mode = head . maximumBy (comparing length) . group . sort++nMinOnAux :: Ord b => (forall x . f x -> b) -> SOP.NP f a -> Maybe (b, SOP.NS f a)+nMinOnAux fb SOP.Nil = Nothing+nMinOnAux fb (l SOP.:* r) =+ let lb = fb l in+ case nMinOnAux fb r of+ Nothing -> Just (lb, SOP.Z l)+ Just (rb, rs) ->+ case lb `compare` rb of+ GT -> Just (rb, SOP.S rs)+ _ -> Just (lb, SOP.Z l)++nMinOn :: Ord b => (forall x . f x -> b) -> SOP.NP f a -> Maybe (SOP.NS f a)+nMinOn f = fmap snd . nMinOnAux f++data SelElemTypeAuxIndex env a = SelElemTypeAuxIndex (Index env (Fst a)) (SOP.NP (Index env) (Snd a))+selElemTypeAuxIndex :: SOP.NP (Index env) a -> SOP.NP (Index env) b -> SOP.NP (SelElemTypeAuxIndex env) (SelElemAux a b)+selElemTypeAuxIndex _ SOP.Nil = SOP.Nil+selElemTypeAuxIndex x (y SOP.:* z) = SelElemTypeAuxIndex y (npRevAppend x z) SOP.:* selElemTypeAuxIndex (y SOP.:* x) z++fromSFA :: SplitFunAux (env :: [*]) a b -> Proxy (SOP.All (GetIndex env))+fromSFA _ = Proxy++newtype BuildAuxAux a b = BuildAuxAux { runBuildAuxAux :: [(a, Fst b, SOP.NP SOP.I (Snd b))] }++data Score = Destructing | Deciding Double deriving Eq+instance Ord Score where+ Destructing `compare` Destructing = EQ+ Destructing `compare` _ = LT+ _ `compare` Destructing = GT+ Deciding l `compare` Deciding r = l `compare` r++newtype WithScore b x = WithScore { runWithScore :: (Score, (SplitOn b x)) }++buildTree :: (SOP.SListI env, Ord b) =>+ SplitFuns env env -> SOP.NP (Index env) (Snd a1) -> b -> SplitFunAux env (Fst a1) (b, SOP.NP SOP.I (Snd a1)) -> (Score, SplitOn b a1)+buildTree sf i def sfa@(SplitFunAux x y) =+ (if (==1) $ length $ filter not $ SOP.hcollapse $ SOP.hmap (\(SplitFunAuxAux z) -> SOP.K $ null z) y then+ Destructing else+ Deciding $ sum $ SOP.hcollapse $ SOP.hmap (\(SplitFunAuxAux z) -> SOP.K $ (fromIntegral (length z)*) $ entropy $ map (fst . snd) z) y,+ SplitOn x (SOP.hcmap (fromSFA sfa) (\(SplitFunAuxAux z) -> if length z == 0 then SplitOnAux $ Leaf $ const def else+ let j = fst $ head z in+ SplitOnAux $ buildAux+ (getIndex2 (npToSList j) `npAppend` i) sf (map (\(c, (d, e)) -> (c `npAppend` e, d)) z) (mode $ map (fst . snd) z)) y))++buildAux :: (SOP.SListI env, Ord b) => SOP.NP (Index env) a -> SplitFuns env env -> [(SOP.NP SOP.I a, b)] -> b -> DecisionTree a b+buildAux _ sf [] def = Leaf $ const def+buildAux i sf x@(xh:_) def =+ case dictSList $ npToSList $ npSelElem $ fst $ xh of+ Dict -> if length (group (map snd x)) == 1 then+ Leaf $ const $ snd $ head x else+ let a = map (\(l, r) -> SOP.hmap (\(SelElemTypeAux a b) -> BuildAuxAux [(r, a, b)]) $ npSelElem l) x+ b = foldl (SOP.hzipWith (\(BuildAuxAux l) (BuildAuxAux r) -> BuildAuxAux (l ++ r))) (SOP.hpure (BuildAuxAux [])) a+ in+ fromMaybe (Leaf $ const def) $ fmap (Split . SOP.hmap (\(WithScore (_, t)) -> t)) $ nMinOn (\(WithScore (s, _)) -> s) $+ SOP.hzipWith+ (\(SelElemTypeAuxIndex c d) (BuildAuxAux e) ->+ WithScore $ minimumBy (comparing fst) $+ map (buildTree sf d def) $+ runSplitFun (fromIndex sf c) $+ map (\(f, g, h) -> (g, (f, h))) e)+ (selElemTypeAuxIndex SOP.Nil i)+ b++build :: (SOP.All (GetIndex env) a, SOP.SListI env, Ord b) => SplitFuns env env -> [(SOP.NP SOP.I a, b)] -> b -> DecisionTree a b+build sf [] def = Leaf $ const def+build sf x@((np, _):_) def = buildAux (getIndex2 $ npToSList $ np) sf (sortBy (comparing snd) x) def
− src/Lib.hs
@@ -1,119 +0,0 @@-{-# LANGUAGE - DataKinds,- TypeFamilies,- TemplateHaskell,- PolyKinds,- ExistentialQuantification,- ScopedTypeVariables,- UndecidableInstances,- TypeOperators,- UndecidableSuperClasses,- GADTs,- PartialTypeSignatures-#-}--module Lib where--import Data.Singletons.Prelude-import Data.Void-import Data.Singletons.TH-import qualified Generics.SOP as SOP-import Data.Constraint-import Data.Proxy--someFunc :: IO ()-someFunc = putStrLn "someFunc"--$(singletons [d|- revAppend :: [a] -> [a] -> [a]- revAppend [] x = x- revAppend (x:xs) n = revAppend xs (x:n) - takeElemAux :: [a] -> [a] -> [(a, [a])]- takeElemAux l [] = []- takeElemAux l (r:rs) = (r, revAppend l rs) : takeElemAux (r:l) rs - takeElem :: [a] -> [(a, [a])]- takeElem = takeElemAux []- |])--class (SplitCode a ~ SOP.Code a, SOP.Generic a) => SplitStructure a where- type SplitCode a :: [[*]]- type SplitCode a = SOP.Code a- splitStructureFrom :: a -> SOP.SOP SOP.I (SplitCode a)- splitStructureFrom = SOP.from- splitStructureTo :: SOP.SOP SOP.I (SplitCode a) -> a--class Ord a => SplitOrd a--newtype SplitStructureOnAux dt b r a = SplitStructureOnAux { runSplitStructureOnAux :: dt (r :++ a) b }--newtype SplitStructureOn dt b a =- SplitStructureOn { runSplitStructureOn :: (Dict (SplitStructure (Fst a)), SOP.NP (SplitStructureOnAux dt b (Snd a)) (SplitCode (Fst a))) }--newtype SplitOrderOn dt b a = SplitOrderOn { runSplitOrderOn :: (Dict (SplitOrd (Fst a)), (Fst a), dt (Fst a:Snd a) b, dt (Snd a) b, dt (Fst a:Snd a) b) }--data DecisionTree (a :: [*]) (b :: *) =- Leaf (SOP.NP SOP.I a -> b) |- SplitOnStructure (SOP.NS (SplitStructureOn DecisionTree b) (TakeElem a)) |- SplitOnOrd (SOP.NS (SplitOrderOn DecisionTree b) (TakeElem a))--newtype TakeElemTypeAux a = TakeElemTypeAux { runTakeElemTypeAux :: (Fst a, SOP.NP SOP.I (Snd a)) }--type family TakeElemAuxType (a :: [*]) (b :: [*]) :: *-type instance TakeElemAuxType a b = SOP.NP TakeElemTypeAux (TakeElemAux a b)--type family TakeElemType (a :: [*]) :: *-type instance TakeElemType a = TakeElemAuxType '[] a--revAppendDT :: SOP.NP f a -> SOP.NP f b -> SOP.NP f (RevAppend a b)-revAppendDT SOP.Nil x = x-revAppendDT (x SOP.:* y) z = revAppendDT y (x SOP.:* z)--takeElemAuxDT :: SOP.NP SOP.I a -> SOP.NP SOP.I b -> TakeElemAuxType a b-takeElemAuxDT _ SOP.Nil = SOP.Nil-takeElemAuxDT x (SOP.I y SOP.:* z) = TakeElemTypeAux (y, revAppendDT x z) SOP.:* takeElemAuxDT (SOP.I y SOP.:* x) z--dictSList :: SOP.SList a -> Dict (SOP.SListI a)-dictSList SOP.SNil = Dict-dictSList SOP.SCons = Dict--sListCons :: Proxy a -> SOP.SList b -> SOP.SList (a:b)-sListCons _ x = dictSList x `withDict` SOP.SCons--unSListCons :: forall (a :: [k]) . SOP.SList (_:a) -> SOP.SList a-unSListCons SOP.SCons = SOP.sList--takeElemAuxDTSingAux :: SOP.SList (a:as) -> Proxy a-takeElemAuxDTSingAux _ = Proxy--takeElemAuxDTSing :: SOP.SList a -> SOP.SList b -> SOP.SList (TakeElemAux a b)-takeElemAuxDTSing _ SOP.SNil = SOP.SNil-takeElemAuxDTSing x y@SOP.SCons =- dictSList (takeElemAuxDTSing (sListCons (takeElemAuxDTSingAux y) x) (unSListCons y)) `withDict` SOP.SCons--takeElemDT :: SOP.NP SOP.I a -> TakeElemType a-takeElemDT = takeElemAuxDT SOP.Nil--sopAppend :: SOP.NP f a -> SOP.NP f b -> SOP.NP f (a :++ b)-sopAppend SOP.Nil x = x-sopAppend (x SOP.:* y) z = x SOP.:* sopAppend y z--npToSList :: SOP.NP f a -> SOP.SList a-npToSList SOP.Nil = SOP.SNil-npToSList (_ SOP.:* x) = sListCons Proxy (npToSList x)--eval :: DecisionTree a b -> SOP.NP SOP.I a -> b-eval (Leaf f) x = f x-eval (SplitOnStructure f) x =- dictSList (takeElemAuxDTSing SOP.SNil (npToSList x)) `withDict`- (SOP.hcollapse $ SOP.hzipWith- (\(TakeElemTypeAux (a, b)) (SplitStructureOn (Dict, d)) ->- let SOP.SOP e = splitStructureFrom a in- SOP.K (SOP.hcollapse $ SOP.hzipWith (\(SplitStructureOnAux f) g -> SOP.K (eval f (sopAppend b g))) d e)) (takeElemDT x) f)-eval (SplitOnOrd f) x =- dictSList (takeElemAuxDTSing SOP.SNil (npToSList x)) `withDict`- (SOP.hcollapse $ SOP.hzipWith- (\(TakeElemTypeAux (a, b)) (SplitOrderOn (Dict, d, e, f, g)) ->- SOP.K (case a `compare` d of- LT -> eval e (SOP.I a SOP.:* b)- EQ -> eval f b- GT -> eval g (SOP.I a SOP.:* b))) (takeElemDT x) f)