2 Module : Gargantext.Core.Text.List.Social
4 Copyright : (c) CNRS, 2018-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
11 module Gargantext.Core.Text.List.Social
15 import Gargantext.Core.Types.Individu
16 import Gargantext.Database.Admin.Config
17 import Gargantext.Database.Admin.Types.Node
18 import Gargantext.Database.Prelude
19 import Gargantext.Database.Query.Table.Node.Error
20 import Gargantext.Database.Query.Tree
21 import Gargantext.Database.Query.Tree.Root (getRootId)
22 import Gargantext.Prelude
25 import Data.Maybe (fromMaybe)
28 import Data.Semigroup (Semigroup(..))
29 import Data.Text (Text)
30 import Gargantext.API.Ngrams.Tools -- (getListNgrams)
31 import Gargantext.API.Ngrams.Types
32 import Gargantext.Core.Types.Main
33 import Gargantext.Database.Schema.Ngrams
34 import qualified Data.List as List
35 import qualified Data.Map as Map
36 import qualified Data.Set as Set
38 ------------------------------------------------------------------------
39 flowSocialList :: ( RepoCmdM env err m
44 => User -> NgramsType -> Set Text
45 -> m (Map ListType (Set Text))
46 flowSocialList user nt ngrams' = do
47 privateLists <- flowSocialListByMode Private user nt ngrams'
48 -- printDebug "* privateLists *: \n" privateLists
49 -- here preference to privateLists (discutable)
50 sharedLists <- flowSocialListByMode Shared user nt (termsByList CandidateTerm privateLists)
51 -- printDebug "* sharedLists *: \n" sharedLists
54 let result = unions [ Map.mapKeys (fromMaybe CandidateTerm) privateLists
55 , Map.mapKeys (fromMaybe CandidateTerm) sharedLists
57 -- printDebug "* socialLists *: results \n" result
60 ------------------------------------------------------------------------
61 unions :: (Ord a, Semigroup a, Semigroup b, Ord b)
62 => [Map a (Set b)] -> Map a (Set b)
63 unions = invertBack . Map.unionsWith (<>) . map invertForw
65 invertForw :: (Ord b, Semigroup a) => Map a (Set b) -> Map b a
66 invertForw = Map.unionsWith (<>)
67 . (map (\(k,sets) -> Map.fromSet (\_ -> k) sets))
70 invertBack :: (Ord a, Ord b) => Map b a -> Map a (Set b)
71 invertBack = Map.fromListWith (<>)
72 . (map (\(b,a) -> (a, Set.singleton b)))
75 unions_test :: Map ListType (Set Text)
76 unions_test = unions [m1, m2]
78 m1 = Map.fromList [ (StopTerm , Set.singleton "Candidate")]
79 m2 = Map.fromList [ (CandidateTerm, Set.singleton "Candidate")
80 , (MapTerm , Set.singleton "Candidate")
83 ------------------------------------------------------------------------
84 termsByList :: ListType -> (Map (Maybe ListType) (Set Text)) -> Set Text
85 termsByList CandidateTerm m = Set.unions
86 $ map (\lt -> fromMaybe Set.empty $ Map.lookup lt m)
87 [ Nothing, Just CandidateTerm ]
89 fromMaybe Set.empty $ Map.lookup (Just l) m
92 flowSocialListByMode :: ( RepoCmdM env err m
97 => NodeMode -> User -> NgramsType -> Set Text
98 -> m (Map (Maybe ListType) (Set Text))
99 flowSocialListByMode mode user nt ngrams' = do
100 listIds <- findListsId mode user
102 [] -> pure $ Map.fromList [(Nothing, ngrams')]
104 counts <- countFilterList ngrams' nt listIds Map.empty
105 -- printDebug "flowSocialListByMode counts" counts
106 let r = toSocialList counts ngrams'
107 -- printDebug "flowSocialListByMode r" r
110 ------------------------------------------------------------------------
111 -- TODO: maybe use social groups too
112 toSocialList :: Map Text (Map ListType Int)
114 -> Map (Maybe ListType) (Set Text)
115 toSocialList m = Map.fromListWith (<>)
117 . Set.map (toSocialList1 m)
119 -- | TODO what if equality ?
120 -- choice depends on Ord instance of ListType
121 -- for now : data ListType = StopTerm | CandidateTerm | MapTerm
122 -- means MapTerm > CandidateTerm > StopTerm in case of equality of counts
123 -- (we minimize errors on MapTerms if doubt)
124 toSocialList1 :: Map Text (Map ListType Int)
126 -> (Maybe ListType, Set Text)
127 toSocialList1 m t = case Map.lookup t m of
128 Nothing -> (Nothing, Set.singleton t)
129 Just m' -> ( (fst . fst) <$> Map.maxViewWithKey m'
133 toSocialList1_testIsTrue :: Bool
134 toSocialList1_testIsTrue = result == (Just MapTerm, Set.singleton token)
136 result = toSocialList1 (Map.fromList [(token, m)]) token
138 m = Map.fromList [ (CandidateTerm, 1)
143 ------------------------------------------------------------------------
144 -- | [ListId] does not merge the lists (it is for Master and User lists
145 -- here we need UserList only
146 countFilterList :: RepoCmdM env err m
147 => Set Text -> NgramsType -> [ListId]
148 -> Map Text (Map ListType Int)
149 -> m (Map Text (Map ListType Int))
150 countFilterList st nt ls input =
151 foldM' (\m l -> countFilterList' st nt [l] m) input ls
154 countFilterList' :: RepoCmdM env err m
155 => Set Text -> NgramsType -> [ListId]
156 -> Map Text (Map ListType Int)
157 -> m (Map Text (Map ListType Int))
158 countFilterList' st nt ls input = do
159 ml <- toMapTextListType <$> getListNgrams ls nt
160 -- printDebug "countFilterList'" ml
161 pure $ Set.foldl' (\m t -> countList t ml m) input st
163 ------------------------------------------------------------------------
164 -- FIXME children have to herit the ListType of the parent
165 toMapTextListType :: Map Text NgramsRepoElement -> Map Text ListType
166 toMapTextListType m = Map.fromListWith (<>)
171 ----------------------
172 -- | Tools to inherit groupings
173 ----------------------
176 parentUnionsMerge :: (Ord a, Ord b, Num c)
179 parentUnionsMerge = Map.unionsWith (Map.unionWith (+))
181 -- This Parent union is specific
182 -- [Private, Shared, Public]
183 -- means the following preferences:
184 -- Private > Shared > Public
185 -- if data have not been tagged privately, then use others tags
186 -- This unions behavior takes first key only and ignore others
187 parentUnionsExcl :: Ord a
190 parentUnionsExcl = Map.unions
194 -> Map Text (Map Parent Int)
196 hasParent t m = case Map.lookup t m of
198 Just m' -> (fst . fst) <$> Map.maxViewWithKey m'
201 toMapTextParent :: Set Text
202 -> Map Text (Map Parent Int)
203 -> [Map Text NgramsRepoElement]
204 -> Map Text (Map Parent Int)
205 toMapTextParent ts = foldl' (toMapTextParent' ts)
208 toMapTextParent' :: Set Text
209 -> Map Text (Map Parent Int)
210 -> Map Text NgramsRepoElement
211 -> Map Text (Map Parent Int)
212 toMapTextParent' ts' to from = Set.foldl' (toMapTextParent'' ts' from) to ts'
215 toMapTextParent'' :: Set Text
216 -> Map Text NgramsRepoElement
217 -> Map Text (Map Parent Int)
219 -> Map Text (Map Parent Int)
220 toMapTextParent'' ss from to t = case Map.lookup t from of
222 Just nre -> case _nre_parent nre of
223 Just (NgramsTerm p') -> if Set.member p' ss
224 then Map.alter (addParent p') t to
227 addParent p'' Nothing = Just $ addCountParent p'' Map.empty
228 addParent p'' (Just ps) = Just $ addCountParent p'' ps
230 addCountParent :: Parent -> Map Parent Int -> Map Parent Int
231 addCountParent p m = Map.alter addCount p m
233 addCount Nothing = Just 1
234 addCount (Just n) = Just $ n + 1
239 ------------------------------------------------------------------------
240 toList :: Map Text NgramsRepoElement -> (Text, NgramsRepoElement) -> [(Text, ListType)]
241 toList m (t, nre@(NgramsRepoElement _ _ _ _ (MSet children))) =
242 List.zip terms (List.cycle [lt'])
245 -- <> maybe [] (\n -> [unNgramsTerm n]) root
246 -- <> maybe [] (\n -> [unNgramsTerm n]) parent
247 <> (map unNgramsTerm $ Map.keys children)
250 listOf :: Map Text NgramsRepoElement -> NgramsRepoElement -> ListType
251 listOf m ng = case _nre_parent ng of
252 Nothing -> _nre_list ng
253 Just p -> case Map.lookup (unNgramsTerm p) m of
254 Just ng' -> listOf m ng'
255 Nothing -> CandidateTerm
256 -- panic "[G.C.T.L.Social.listOf] Nothing: Should Not happen"
258 ------------------------------------------------------------------------
261 -> Map Text (Map ListType Int)
262 -> Map Text (Map ListType Int)
263 countList t m input = case Map.lookup t m of
265 Just l -> Map.alter addList t input
267 addList Nothing = Just $ addCountList l Map.empty
268 addList (Just lm) = Just $ addCountList l lm
270 addCountList :: ListType -> Map ListType Int -> Map ListType Int
271 addCountList l m = Map.alter (plus l) l m
273 plus CandidateTerm Nothing = Just 1
274 plus CandidateTerm (Just x) = Just $ x + 1
276 plus _ Nothing = Just 3
277 plus _ (Just x) = Just $ x + 3
279 ------------------------------------------------------------------------
280 findListsId :: (HasNodeError err, HasTreeError err)
281 => NodeMode -> User -> Cmd err [NodeId]
282 findListsId mode u = do
284 ns <- map _dt_nodeId <$> filter (\n -> _dt_typeId n == nodeTypeId NodeList)
285 <$> findNodes' mode r
286 -- printDebug "findListsIds" ns
290 findNodes' :: HasTreeError err
291 => NodeMode -> RootId
292 -> Cmd err [DbTreeNode]
293 findNodes' Private r = findNodes Private r $ [NodeFolderPrivate] <> commonNodes
294 findNodes' Shared r = findNodes Shared r $ [NodeFolderShared ] <> commonNodes
295 findNodes' Public r = findNodes Public r $ [NodeFolderPublic ] <> commonNodes
297 commonNodes:: [NodeType]
298 commonNodes = [NodeFolder, NodeCorpus, NodeList]