]> Git — Sourcephile - gargantext.git/blob - src/Gargantext/Viz/Phylo/Example.hs
[Phylo] Reading cosmetics / New Tools file.
[gargantext.git] / src / Gargantext / Viz / Phylo / Example.hs
1 {-|
2 Module : Gargantext.Viz.Phylo.Example
3 Description : Phylomemy example based on history of Cleopatre.
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
8 Portability : POSIX
9
10 -- | Cesar et Cleôpatre
11 -- Exemple de phylomemie
12 -- French without accents
13
14
15 TODO:
16 - split the functions : RAW -> Document -> Ngrams
17
18 -- reverse history: antechronologique
19 -- metrics support
20
21
22 -}
23
24 {-# LANGUAGE NoImplicitPrelude #-}
25 {-# LANGUAGE FlexibleContexts #-}
26 {-# LANGUAGE OverloadedStrings #-}
27
28 module Gargantext.Viz.Phylo.Example where
29
30 import Control.Lens hiding (both)
31 import Data.List (concat, union, intersect, tails, tail, head, last, null, zip, sort, length, any, (++), nub)
32 import qualified Data.List as List
33 import Data.Text (Text, unwords, toLower, words)
34 import Data.Tuple.Extra
35 import Data.Semigroup (Semigroup)
36
37 import Data.Map (Map, elems, member, adjust, singleton, (!), keys, restrictKeys, mapWithKey)
38 import qualified Data.Map as Map
39
40 import Data.Vector (Vector, fromList, elemIndex)
41 import qualified Data.Vector as Vector
42 import qualified Data.Maybe as Maybe
43
44 import Data.Tuple (fst, snd)
45 import qualified Data.Tuple as Tuple
46
47 import Data.Bool (Bool, not)
48 import qualified Data.Bool as Bool
49
50 import Data.Set (Set)
51 import qualified Data.Set as Set
52 import qualified Data.Matrix as DM'
53
54 import Gargantext.Text.Metrics.FrequentItemSet (fisWithSizePolyMap, Size(..))
55 import Gargantext.Text.Terms.Mono (monoTexts)
56 import Gargantext.Prelude hiding (head)
57 import Gargantext.Viz.Phylo
58 import Gargantext.Viz.Phylo.Tools
59
60 ------------------------------------------------------------------------
61 -- | Types | --
62
63
64 -- | Date : a simple Integer
65 type Date = Int
66 -- | Document : a piece of Text linked to a Date
67 data Document = Document
68 { date :: Date
69 , text :: Text
70 } deriving (Show)
71 -- | Corpus : a list of Documents
72 type Corpus = [Document]
73
74
75 type MapList = [Ngrams]
76 type PeriodeSize = Int
77 -- data Periodes b a = Map (b,b) a
78 type Occurrences = Int
79
80 data Levels = Level_m1 | Level_0 | Level_1 | Level_2 | Level_N
81 deriving (Show, Eq, Enum, Bounded)
82
83
84
85
86 data LinkLvlLabel = Link_m1_0 | Link_0_m1 | Link_1_0 | Link_0_1 | Link_x_y
87 deriving (Show, Eq, Enum, Bounded)
88
89 data LinkLvl = LinkLvl
90 { linkLvlLabel :: LinkLvlLabel
91 , linkLvlFrom :: Int
92 , linkLvlTo :: Int
93 } deriving (Show)
94
95
96 data PhyloError = LevelDoesNotExist
97 | LevelUnassigned
98 deriving (Show)
99
100
101 --------------------------------------------------------------------
102 phyloExampleFinal :: Phylo
103 phyloExampleFinal = undefined
104
105 --------------------------------------------------------------------
106 appariement :: Map (Date, Date) (Map (Set Ngrams) Int)
107 appariement = undefined
108
109 ------------------------------------------------------------------------
110 -- | STEP 10 | -- Incrementaly cluster the PhyloGroups n times, link them through the Periods and build level n of the Phylo
111
112
113 ------------------------------------------------------------------------
114 -- | STEP 8 | -- Cluster the Fis
115
116 ------------------------------------------------------------------------
117 -- | STEP 9 | -- Link the PhyloGroups of level 1 through the Periods
118
119 shouldPair :: PhyloGroup -> PhyloGroup -> Bool
120 shouldPair g g' = (not . null) $ intersect (getNgrams g) (getNgrams g')
121
122
123 getKeyPair :: (Int,Int) -> Map (Int,Int) a -> (Int,Int)
124 getKeyPair (x,y) m = case findPair (x,y) m of
125 Nothing -> panic "[ERR][Viz.Phylo.Example.getKeyPair] Nothing"
126 Just i -> i
127 where
128 --------------------------------------
129 findPair :: (Int,Int) -> Map (Int,Int) a -> Maybe (Int,Int)
130 findPair (x,y) m
131 | member (x,y) m = Just (x,y)
132 | member (y,x) m = Just (y,x)
133 | otherwise = Nothing
134 --------------------------------------
135
136 listToCombi :: (a -> b) -> [a] -> [(b,b)]
137 listToCombi f l = [(f x, f y) | (x:rest) <- tails l, y <- rest]
138
139 fisToCooc :: Map (Date, Date) Fis -> Map (Int, Int) Double
140 fisToCooc m = map (/docs)
141 $ foldl (\mem x -> adjust (+1) (getKeyPair x mem) mem) cooc
142 $ concat
143 $ map (\x -> listToCombi findIdx $ (Set.toList . fst) x) fis
144 where
145 --------------------------------------
146 fis :: [(Clique,Support)]
147 fis = concat $ map (\x -> Map.toList x) (elems m)
148 --------------------------------------
149 fisNgrams :: [Ngrams]
150 fisNgrams = foldl (\mem x -> union mem $ (Set.toList . fst) x) [] fis
151 --------------------------------------
152 docs :: Double
153 docs = fromIntegral $ foldl (\mem x -> mem + (snd x)) 0 fis
154 --------------------------------------
155 cooc :: Map (Int, Int) (Double)
156 cooc = Map.fromList $ map (\x -> (x,0)) (listToCombi findIdx fisNgrams)
157 --------------------------------------
158
159
160
161 phyloWithAppariement1 :: Phylo
162 phyloWithAppariement1 = phyloLinked_0_1
163
164 ------------------------------------------------------------------------
165 -- | STEP 8 | -- Find the Fis out of Documents and Ngrams and build level 1 of the Phylo
166
167 phyloLinked_0_1 :: Phylo
168 phyloLinked_0_1 = phyloToLinks lvl_0_1 phyloLinked_1_0
169
170 lvl_0_1 :: LinkLvl
171 lvl_0_1 = (LinkLvl Link_0_1 0 1)
172
173 phyloLinked_1_0 :: Phylo
174 phyloLinked_1_0 = phyloToLinks lvl_1_0 phyloWithGroups1
175
176 lvl_1_0 :: LinkLvl
177 lvl_1_0 = (LinkLvl Link_1_0 1 0)
178
179 phyloWithGroups1 :: Phylo
180 phyloWithGroups1 = updatePhyloByLevel Level_1 phyloLinked_m1_0
181
182 cliqueToGroup :: PhyloPeriodId -> Int -> Int -> Ngrams -> (Clique,Support) -> PhyloGroup
183 cliqueToGroup period lvl idx label fis = PhyloGroup ((period, lvl), idx)
184 label
185 (sort $ map (\x -> findIdx x) $ Set.toList $ fst fis)
186 (singleton "support" (fromIntegral $ snd fis))
187 [] [] [] []
188
189 fisToPhyloLevel :: Map (Date, Date) Fis -> Phylo -> Phylo
190 fisToPhyloLevel m p = over (phylo_periods . traverse)
191 (\period ->
192 let periodId = _phylo_periodId period
193 fisList = zip [1..] (Map.toList (m ! periodId))
194 in over (phylo_periodLevels)
195 (\levels ->
196 let groups = map (\fis -> cliqueToGroup periodId 1 (fst fis) "" (snd fis)) fisList
197 in (PhyloLevel (periodId, 1) groups) : levels
198 ) period
199 ) p
200
201 -- | To preserve nonempty periods from filtering, please use : filterFisBySupport False ...
202 phyloFisFiltered :: Map (Date, Date) Fis
203 phyloFisFiltered = filterFisBySupport True 1 (filterFisByNested phyloFis)
204
205 filterFisBySupport :: Bool -> Int -> Map (Date, Date) Fis -> Map (Date, Date) Fis
206 filterFisBySupport empty min m = case empty of
207 True -> Map.map (\fis -> filterMinorFis min fis) m
208 False -> Map.map (\fis -> filterMinorFisNonEmpty min fis) m
209
210 filterMinorFis :: Int -> Fis -> Fis
211 filterMinorFis min fis = Map.filter (\s -> s > min) fis
212
213 filterMinorFisNonEmpty :: Int -> Fis -> Fis
214 filterMinorFisNonEmpty min fis = if (Map.null fis') && (not $ Map.null fis)
215 then filterMinorFisNonEmpty (min - 1) fis
216 else fis'
217 where
218 fis' = filterMinorFis min fis
219
220 doesContains :: [Ngrams] -> [Ngrams] -> Bool
221 doesContains l l'
222 | null l' = True
223 | length l' > length l = False
224 | elem (head l') l = doesContains l (tail l')
225 | otherwise = False
226
227 doesAnyContains :: Set Ngrams -> [Set Ngrams] -> [Set Ngrams] -> Bool
228 doesAnyContains h l l' = any (\c -> doesContains (Set.toList c) (Set.toList h)) (l' ++ l)
229
230 filterNestedCliques :: Set Ngrams -> [Set Ngrams] -> [Set Ngrams] -> [Set Ngrams]
231 filterNestedCliques h l l'
232 | null l = if doesAnyContains h l l'
233 then l'
234 else h : l'
235 | doesAnyContains h l l' = filterNestedCliques (head l) (tail l) l'
236 | otherwise = filterNestedCliques (head l) (tail l) (h : l')
237
238
239 filterFisByNested :: Map (Date, Date) Fis -> Map (Date, Date) Fis
240 filterFisByNested = map (\fis -> restrictKeys fis
241 $ Set.fromList
242 $ filterNestedCliques (head (keys fis)) (keys fis) []
243 )
244
245 phyloFis :: Map (Date, Date) Fis
246 phyloFis = termsToFis phyloTerms
247
248 termsToFis :: Map (Date, Date) [Document]
249 -> Map (Date, Date) Fis
250 termsToFis = corpusToFis (words . text)
251
252 -- | TODO: parameters has to be checked
253 -- | TODO FIS on monotexts
254 corpusToFis :: (Document -> [Ngrams])
255 -> Map (Date, Date) [Document]
256 -> Map (Date, Date) (Map (Set Ngrams) Int)
257 corpusToFis f = map (\d -> fisWithSizePolyMap (Segment 1 20) 1 (map f d))
258
259
260 ------------------------------------------------------------------------
261 -- | STEP 7 | -- Link level -1 to level 0
262
263
264 phyloLinked_m1_0 :: Phylo
265 phyloLinked_m1_0 = phyloToLinks lvl_m1_0 phyloLinked_0_m1
266
267 lvl_m1_0 :: LinkLvl
268 lvl_m1_0 = (LinkLvl Link_m1_0 (-1) 0)
269
270
271 ------------------------------------------------------------------------
272 -- | STEP 6 | -- Link level 0 to level -1
273
274
275 addPointer :: Semigroup field
276 => ASetter current target identity (field -> field)
277 -> field -> current -> target
278 addPointer field targetPointer current =
279 set field (<> targetPointer) current
280
281 getNgrams :: PhyloGroup -> [Int]
282 getNgrams = _phylo_groupNgrams
283
284 getGroups :: Phylo -> [PhyloGroup]
285 getGroups = view (phylo_periods . traverse . phylo_periodLevels . traverse . phylo_levelGroups)
286
287 getGroupId :: PhyloGroup -> PhyloGroupId
288 getGroupId = view (phylo_groupId)
289
290 getGroupLvl :: PhyloGroup -> Int
291 getGroupLvl = snd . fst . getGroupId
292
293 getGroupPeriod :: PhyloGroup -> (Date,Date)
294 getGroupPeriod = fst . fst . getGroupId
295
296 getGroupsByLevelAndPeriod :: Int -> (Date,Date) -> Phylo -> [PhyloGroup]
297 getGroupsByLevelAndPeriod lvl period p = List.filter testGroup (getGroups p)
298 where
299 testGroup group = (getGroupLvl group == lvl )
300 && (getGroupPeriod group == period)
301
302 containsIdx :: [Int] -> [Int] -> Bool
303 containsIdx l l'
304 | null l' = False
305 | last l < head l' = False
306 | head l' `elem` l = True
307 | otherwise = containsIdx l (tail l')
308
309 shouldLink :: LinkLvl -> [Int] -> [Int] -> Bool
310 shouldLink lvl current target = case linkLvlLabel lvl of
311 Link_0_m1 -> containsIdx target current
312 Link_m1_0 -> containsIdx target current
313 Link_0_1 -> containsIdx target current
314 Link_1_0 -> containsIdx target current
315 Link_x_y -> undefined
316 _ -> panic ("error link level to be defined")
317
318 linkGroupToGroups :: LinkLvl -> PhyloGroup -> [PhyloGroup] -> PhyloGroup
319 linkGroupToGroups lvl current targets
320 | linkLvlFrom lvl < linkLvlTo lvl = setLevelParents current
321 | linkLvlFrom lvl > linkLvlTo lvl = setLevelChilds current
322 | otherwise = current
323 where
324 setLevelChilds :: PhyloGroup -> PhyloGroup
325 setLevelChilds = over (phylo_groupLevelChilds) addPointers
326
327 setLevelParents :: PhyloGroup -> PhyloGroup
328 setLevelParents = over (phylo_groupLevelParents) addPointers
329
330 addPointers :: [Pointer] -> [Pointer]
331 addPointers lp = lp ++ Maybe.mapMaybe (\target -> if shouldLink lvl (_phylo_groupNgrams current)
332 (_phylo_groupNgrams target )
333 then Just ((getGroupId target),1)
334 else Nothing
335 ) targets
336
337 addPointers' :: [Pointer] -> [Pointer]
338 addPointers' lp = lp ++ map (\target -> ((getGroupId target),1)) targets
339
340 linkGroupsByLevel :: LinkLvl -> Phylo -> [PhyloGroup] -> [PhyloGroup]
341 linkGroupsByLevel lvl p groups = map (\group ->
342 if getGroupLvl group == linkLvlFrom lvl
343 then linkGroupToGroups lvl group (getGroupsByLevelAndPeriod (linkLvlTo lvl) (getGroupPeriod group) p)
344 else group ) groups
345
346 phyloToLinks :: LinkLvl -> Phylo -> Phylo
347 phyloToLinks lvl p = over ( phylo_periods
348 . traverse
349 . phylo_periodLevels
350 . traverse
351 . phylo_levelGroups
352 )
353 (linkGroupsByLevel lvl p) p
354
355 phyloLinked_0_m1 :: Phylo
356 phyloLinked_0_m1 = phyloToLinks lvl_0_m1 phyloWithGroups0
357
358 lvl_0_m1 :: LinkLvl
359 lvl_0_m1 = (LinkLvl Link_0_m1 0 (-1))
360
361
362 ------------------------------------------------------------------------
363 -- | STEP 5 | -- Build level 0 (for the moment it's just a durty copy of level -1)
364
365
366 setGroupIdLvl :: Int -> PhyloGroup -> PhyloGroup
367 setGroupIdLvl lvl (PhyloGroup ((period, lvl'), idx) gLabel gNgrams gQ gPP gPC gLP gLC)
368 = PhyloGroup ((period, lvl), idx) gLabel gNgrams gQ gPP gPC gLP gLC
369
370 setPhyloLevel :: Int -> PhyloLevel -> PhyloLevel
371 setPhyloLevel lvl (PhyloLevel (periodId, lvl') lvlGroups)
372 = PhyloLevel (periodId, lvl) lvlGroups'
373 where
374 lvlGroups' = map (\g -> setGroupIdLvl lvl g) lvlGroups
375
376 copyPhyloLevel :: Int -> [PhyloLevel] -> [PhyloLevel]
377 copyPhyloLevel lvl l = (setPhyloLevel lvl (head l)) : l
378
379 alterLvl :: Int -> [PhyloPeriod] -> [PhyloPeriod]
380 alterLvl lvl l = map (\p -> PhyloPeriod (_phylo_periodId p) (copyPhyloLevel lvl $ _phylo_periodLevels p)) l
381
382 phyloWithGroups0 :: Phylo
383 phyloWithGroups0 = updatePhyloByLevel Level_0 phyloWithGroupsm1
384
385
386 ------------------------------------------------------------------------
387 -- | STEP 4 | -- Build level -1
388
389
390 findIdx :: Ngrams -> Int
391 findIdx n = case (elemIndex n (_phylo_ngrams phylo)) of
392 Nothing -> panic "PhyloError"
393 Just i -> i
394
395 ngramsToGroup :: [Ngrams] -> Text -> Int -> Int -> Int -> Int -> PhyloGroup
396 ngramsToGroup terms label idx lvl from to = PhyloGroup (((from, to), lvl), idx)
397 label
398 (sort (map (\x -> findIdx x) terms))
399 (Map.empty)
400 [] [] [] []
401
402 docsToLevel :: (Date, Date) -> Corpus -> PhyloLevel
403 docsToLevel k v = PhyloLevel (k,(-1)) (map (\x ->
404 ngramsToGroup [snd x] (snd x) (fst x) (-1) (fst k) (snd k)
405 ) $ zip [1..] $ (nub . concat) $ map (words . text) v)
406
407 corpusToPhyloPeriod :: Map (Date,Date) Corpus -> [PhyloPeriod]
408 corpusToPhyloPeriod corpus = map (\x -> PhyloPeriod (fst x) [(snd x)]) $ zip (keys mapLvl) (elems mapLvl)
409 where
410 mapLvl :: Map (Date,Date) PhyloLevel
411 mapLvl = mapWithKey docsToLevel corpus
412
413 updatePhyloByLevel :: Levels -> Phylo -> Phylo
414 updatePhyloByLevel lvl (Phylo pDuration pNgrams pPeriods)
415 = case lvl of
416
417 Level_m1 -> Phylo pDuration pNgrams pPeriods'
418 where pPeriods' = (corpusToPhyloPeriod phyloTerms) ++ pPeriods
419
420 Level_0 -> Phylo pDuration pNgrams pPeriods'
421 where pPeriods' = alterLvl 0 pPeriods
422
423 Level_1 -> fisToPhyloLevel phyloFisFiltered (Phylo pDuration pNgrams pPeriods)
424
425 _ -> panic ("error level to be defined")
426
427 phyloWithGroupsm1 :: Phylo
428 phyloWithGroupsm1 = updatePhyloByLevel Level_m1 phylo
429
430
431 ------------------------------------------------------------------------
432 -- | STEP 3 | -- Split the Corpus into Periods and reduce each Document as a list of Ngrams
433
434
435 phyloTerms :: Map (Date, Date) [Document]
436 phyloTerms = toPeriodes date 5 3 $ cleanCorpus cleanedActants phyloCorpus
437
438 toPeriodes :: (Ord date, Enum date) => (doc -> date)
439 -> Grain -> Step -> [doc] -> Map (date, date) [doc]
440 toPeriodes _ _ _ [] = panic "Empty corpus can not have any periods"
441 toPeriodes f g s es = Map.fromList $ zip hs $ map (inPeriode f es) hs
442 where
443 hs = steps g s $ both f (head es, last es)
444 --------------------------------------------------------------------
445 -- | Define overlapping periods of time by following regular steps
446 inPeriode :: Ord b => (t -> b) -> [t] -> (b, b) -> [t]
447 inPeriode f' h (start,end) =
448 fst $ List.partition (\d -> f' d >= start && f' d <= end) h
449 --------------------------------------------------------------------
450 -- | Find steps of linear and homogenous time of integer
451 steps :: (Eq date, Enum date) => Grain -> Step -> (date, date) -> [(date, date)]
452 steps s' o' (start,end) = map (\l -> (head l, last l))
453 $ chunkAlong s' o' [start .. end]
454
455 cleanCorpus :: MapList -> Corpus -> Corpus
456 cleanCorpus ml = map (\(Document d t) -> Document d (unwords $ filter (\x -> elem x ml) $ monoTexts t))
457
458
459 ------------------------------------------------------------------------
460 -- | STEP 2 | -- Find some Ngrams (ie: phyloGroup of level -1) out of the Corpus & init the phylo
461
462
463 phylo = Phylo (both date $ (last &&& head) phyloCorpus) phyloNgrams []
464
465 phyloNgrams :: PhyloNgrams
466 phyloNgrams = Vector.fromList cleanedActants
467
468 cleanedActants :: [Ngrams]
469 cleanedActants = map toLower actants
470
471 actants :: [Ngrams]
472 actants = [ "Cleopatre" , "Ptolemee", "Ptolemee-XIII", "Ptolemee-XIV"
473 , "Marc-Antoine", "Cesar" , "Antoine" , "Octave" , "Rome"
474 , "Alexandrie" , "Auguste" , "Pompee" , "Cassius" , "Brutus"]
475
476
477 ------------------------------------------------------------------------
478 -- | STEP 1 | -- Get a corpus of Documents
479
480
481 phyloCorpus :: Corpus
482 phyloCorpus = map (\(d,t) -> Document d t) exampleDocuments
483
484 exampleDocuments :: [(Date, Text)]
485 exampleDocuments = List.sortOn fst [ (-51,"Cleopatre règne sur l’egypte entre 51 et 30 av. J.-C. avec ses frères-epoux Ptolemee-XIII et Ptolemee-XIV, puis aux côtes du general romain Marc-Antoine. Elle est celèbre pour avoir ete la compagne de Jules Cesar puis d'Antoine, avec lesquels elle a eu plusieurs enfants. Partie prenante dans la guerre civile opposant Antoine à Octave, elle est vaincue à la bataille d'Actium en 31 av. J.-C. Sa defaite va permettre aux Romains de mener à bien la conquête de l’egypte, evenement qui marquera la fin de l'epoque hellenistique."), (-40,"Il existe relativement peu d'informations sur son sejour à Rome, au lendemain de l'assassinat de Cesar, ou sur la periode passee à Alexandrie durant l'absence d'Antoine, entre -40 et -37."), (-48,"L'historiographie antique lui est globalement defavorable car inspiree par son vainqueur, l'empereur Auguste, et par son entourage, dont l'interêt est de la noircir, afin d'en faire l'adversaire malfaisant de Rome et le mauvais genie d'Antoine. On observe par ailleurs que Cesar ne fait aucune mention de sa liaison avec elle dans les Commentaires sur la Guerre civile"), (-69,"Cleopatre est nee au cours de l'hiver -69/-686 probablement à Alexandrie."), (-48,"Pompee a en effet ete le protecteur de Ptolemee XII, le père de Cleopatre et de Ptolemee-XIII dont il se considère comme le tuteur."), (-48,"Ptolemee-XIII et Cleopatre auraient d'ailleurs aide Pompee par l'envoi d'une flotte de soixante navires."), (-48,"Mais le jeune roi Ptolemee-XIII et ses conseillers jugent sa cause perdue et pensent s'attirer les bonnes graces du vainqueur en le faisant assassiner à peine a-t-il pose le pied sur le sol egyptien, près de Peluse, le 30 juillet 48 av. J.-C., sous les yeux de son entourage."), (-48,"Cesar fait enterrer la tête de Pompee dans le bosquet de Nemesis en bordure du mur est de l'enceinte d'Alexandrie. Pour autant la mort de Pompee est une aubaine pour Cesar qui tente par ailleurs de profiter des querelles dynastiques pour annexer l’egypte."), (-48,"Il est difficile de se prononcer clairement sur les raisons qui ont pousse Cesar à s'attarder à Alexandrie. Il y a des raisons politiques, mais aussi des raisons plus sentimentales (Cleopatre ?). Il tente d'abord d'obtenir le remboursement de dettes que Ptolemee XII"), (-46,"Les deux souverains sont convoques par Cesar au palais royal d'Alexandrie. Ptolemee-XIII s'y rend après diverses tergiversations ainsi que Cleopatre."), (-47,"A Rome, Cleopatre epouse alors un autre de ses frères cadets, à Alexandrie, Ptolemee-XIV, sur l'injonction de Jules Cesar"), (-46,"Cesar a-t-il comme objectif de montrer ce qu'il en coûte de se revolter contre Rome en faisant figurer dans son triomphe la sœur de Cleopatre et de Ptolemee-XIV, Arsinoe, qui s'est fait reconnaître reine par les troupes de Ptolemee-XIII ?"), (-44,"Au debut de l'annee -44, Cesar est assassine par Brutus. Profitant de la situation confuse qui s'ensuit, Cleopatre quitte alors Rome à la mi-avril, faisant escale en Grèce. Elle parvient à Alexandrie en juillet -44."), (-44,"La guerre que se livrent les assassins de Cesar, Cassius et Brutus et ses heritiers, Octave et Marc-Antoine, oblige Cleopatre à des contorsions diplomatiques."), (-41,"Nous ignorons depuis quand Cleopatre, agee de 29 ans en -41, et Marc-Antoine, qui a une quarantaine d'annees, se connaissent. Marc-Antoine est l'un des officiers qui ont participe au retablissement de Ptolemee XII. Il est plus vraisemblable qu'ils se soient frequentes lors du sejour à Rome de Cleopatre."), (-42,"Brutus tient la Grèce tandis que Cassius s'installe en Syrie. Le gouverneur de Cleopatre à Chypre, Serapion, vient en aide à Cassius."), (-42,"Cassius aurait envisage de s'emparer d'Alexandrie quand le 'debarquement' en Grèce d'Antoine et d'Octave l'oblige à renoncer à ses projets")]
486