]> Git — Sourcephile - gargantext.git/blob - src/Gargantext/Viz/Phylo/Example.hs
Begining of the Pair step
[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 (makeLenses, both, Level)
31
32 import Data.Bool (Bool, not)
33 import Data.List (concat, union, intersect, tails, tail, head, last, null, zip, sort, length, any, (++), (!!), nub, sortOn, reverse)
34 import Data.Map (Map, elems, member, adjust, singleton, (!), keys, restrictKeys, mapWithKey)
35 import Data.Semigroup (Semigroup)
36 import Data.Set (Set)
37 import Data.Text (Text, unwords, toLower, words)
38 import Data.Tuple (fst, snd)
39 import Data.Tuple.Extra
40 import Data.Vector (Vector, fromList, elemIndex)
41
42 import Gargantext.Prelude hiding (head)
43 import Gargantext.Text.Metrics.FrequentItemSet (fisWithSizePolyMap, Size(..))
44 import Gargantext.Text.Terms.Mono (monoTexts)
45 import Gargantext.Viz.Phylo
46 import Gargantext.Viz.Phylo.Tools
47
48 import qualified Data.Bool as Bool
49 import qualified Data.List as List
50 import qualified Data.Map as Map
51 import qualified Data.Maybe as Maybe
52 import qualified Data.Set as Set
53 import qualified Data.Tuple as Tuple
54 import qualified Data.Vector as Vector
55
56
57 ------------------------------------------------------------------------
58 -- | STEP 12 | -- Incrementaly cluster the PhyloGroups n times, link them through the Periods and build level n of the Phylo
59
60
61 ------------------------------------------------------------------------
62 -- | STEP 11 | -- Cluster the Fis
63
64
65 ------------------------------------------------------------------------
66 -- | STEP 10 | -- Link the PhyloGroups of level 1 through the Periods
67
68
69 -- | Are two PhyloGroups sharing at leats one Ngrams
70 shareNgrams :: PhyloGroup -> PhyloGroup -> Bool
71 shareNgrams g g' = (not . null) $ intersect (getGroupNgrams g) (getGroupNgrams g')
72
73
74 -- | To get the good pair of keys (x,y) or (y,x) in a given Map (a,b) c
75 getKeyPair :: (Int,Int) -> Map (Int,Int) a -> (Int,Int)
76 getKeyPair (x,y) m = case findPair (x,y) m of
77 Nothing -> panic "[ERR][Viz.Phylo.Example.getKeyPair] Nothing"
78 Just i -> i
79 where
80 --------------------------------------
81 findPair :: (Int,Int) -> Map (Int,Int) a -> Maybe (Int,Int)
82 findPair (x,y) m
83 | member (x,y) m = Just (x,y)
84 | member (y,x) m = Just (y,x)
85 | otherwise = Nothing
86 --------------------------------------
87
88
89 -- | To get all combinations of a list with no repetition and apply a function to the resulting list of pairs
90 listToCombi :: forall a b. (a -> b) -> [a] -> [(b,b)]
91 listToCombi f l = [ (f x, f y) | (x:rest) <- tails l, y <- rest ]
92
93
94 -- | To transform the Fis into a coocurency Matrix in a Phylo
95 fisToCooc :: Map (Date, Date) Fis -> Phylo -> Map (Int, Int) Double
96 fisToCooc m p = map (/docs)
97 $ foldl (\mem x -> adjust (+1) (getKeyPair x mem) mem) cooc
98 $ concat
99 $ map (\x -> listToCombi (\x -> ngramsToIdx x p) $ (Set.toList . fst) x) fis
100 where
101 --------------------------------------
102 fis :: [(Clique,Support)]
103 fis = concat $ map (\x -> Map.toList x) (elems m)
104 --------------------------------------
105 fisNgrams :: [Ngrams]
106 fisNgrams = foldl (\mem x -> union mem $ (Set.toList . fst) x) [] fis
107 --------------------------------------
108 docs :: Double
109 docs = fromIntegral $ foldl (\mem x -> mem + (snd x)) 0 fis
110 --------------------------------------
111 cooc :: Map (Int, Int) (Double)
112 cooc = Map.fromList $ map (\x -> (x,0)) (listToCombi (\x -> ngramsToIdx x p) fisNgrams)
113 --------------------------------------
114
115 data Proximity = WeightedLogJaccard | Other
116
117 data Candidates = Childs | Parents
118
119 weightedLogJaccard :: PhyloGroup -> PhyloGroup -> (PhyloGroupId, Double)
120 weightedLogJaccard group group' = (getGroupId group', 1)
121
122 getProximity :: Proximity -> PhyloGroup -> PhyloGroup -> (PhyloGroupId, Double)
123 getProximity p group group' = case p of
124 WeightedLogJaccard -> weightedLogJaccard group group'
125 Other -> undefined
126 _ -> panic ("[ERR][Viz.Phylo.Example.getProximity] Proximity function not defined")
127
128 getPhyloPeriods :: Phylo -> [PhyloPeriodId]
129 getPhyloPeriods p = map _phylo_periodId
130 $ view (phylo_periods) p
131
132 -- | Trouver un moyen de naviguer dans la liste des périodes next or prévious depuis getCandidates
133 -- | lié getCandidates à pair group
134 -- | faire rentrer de la récurence de profondeur 5 au plus dans pair group
135 -- | faire le jaccard
136 -- | faire les pointeurs
137 -- | faire l'amont de pair group
138 -- | faire le double sens
139
140 getCandidates :: Candidates -> PhyloGroup -> Phylo -> [PhyloGroup]
141 getCandidates c group p = getGroupsWithFilters (getGroupLevel group) prd p
142 where
143 --------------------------------------
144 prd = case c of
145 Childs -> getGroupPeriod group
146 Parents -> getGroupPeriod group
147 _ -> panic ("[ERR][Viz.Phylo.Example.getCandidates] Candidates type not defined")
148
149 pairGroupToGroups :: Double -> PhyloGroup -> [PhyloGroup] -> PhyloGroup
150 pairGroupToGroups thr group l = if (not . null) $ keepBest thr scores
151 then group
152 else group
153 where
154 --------------------------------------
155 scores :: [(PhyloGroupId, Double)]
156 scores = map (\group' -> getProximity WeightedLogJaccard group group') l
157 --------------------------------------
158 keepBest :: Double -> [(PhyloGroupId, Double)] -> [(PhyloGroupId, Double)]
159 keepBest thr l = reverse
160 $ sortOn snd
161 $ filter (\(id,s) -> s >= thr) l
162 --------------------------------------
163
164
165
166 phyloWithAppariement1 :: Phylo
167 phyloWithAppariement1 = phyloLinked_0_1
168
169
170 ------------------------------------------------------------------------
171 -- | STEP 9 | -- Build level 1 of the Phylo
172
173
174 -- | To Cliques into Groups
175 cliqueToGroup :: PhyloPeriodId -> Int -> Int -> Ngrams -> (Clique,Support) -> Phylo -> PhyloGroup
176 cliqueToGroup period lvl idx label fis p = PhyloGroup ((period, lvl), idx)
177 label
178 (sort $ map (\x -> ngramsToIdx x p)
179 $ Set.toList
180 $ fst fis
181 )
182 (singleton "support" (fromIntegral $ snd fis))
183 [] [] [] []
184
185
186 -- | To transform Fis into PhyloLevels
187 fisToPhyloLevel :: Map (Date, Date) Fis -> Phylo -> Phylo
188 fisToPhyloLevel m p = over (phylo_periods . traverse)
189 (\period ->
190 let periodId = _phylo_periodId period
191 fisList = zip [1..] (Map.toList (m ! periodId))
192 in over (phylo_periodLevels)
193 (\levels ->
194 let groups = map (\fis -> cliqueToGroup periodId 1 (fst fis) "" (snd fis) p) fisList
195 in levels ++ [PhyloLevel (periodId, 1) groups]
196 ) period ) p
197
198
199 phyloLinked_0_1 :: Phylo
200 phyloLinked_0_1 = alterLevelLinks lvl_0_1 phyloLinked_1_0
201
202
203 lvl_0_1 :: LevelLink
204 lvl_0_1 = initLevelLink (initLevel 0 Level_0) (initLevel 1 Level_1)
205
206
207 phyloLinked_1_0 :: Phylo
208 phyloLinked_1_0 = alterLevelLinks lvl_1_0 phyloWithGroups1
209
210
211 lvl_1_0 :: LevelLink
212 lvl_1_0 = initLevelLink (initLevel 1 Level_1) (initLevel 0 Level_0)
213
214
215 phyloWithGroups1 :: Phylo
216 phyloWithGroups1 = updatePhyloByLevel (initLevel 1 Level_1) phyloLinked_m1_0
217
218
219 ------------------------------------------------------------------------
220 -- | STEP 8 | -- Create Frequent Items Sets by Period and filter them
221
222
223 -- | To Filter Fis by support
224 filterFisBySupport :: Bool -> Int -> Map (Date, Date) Fis -> Map (Date, Date) Fis
225 filterFisBySupport empty min m = case empty of
226 True -> Map.map (\fis -> filterMinorFis min fis) m
227 False -> Map.map (\fis -> filterMinorFisNonEmpty min fis) m
228
229
230 -- | To filter Fis with small Support, to preserve nonempty periods please use : filterFisBySupport False
231 filterMinorFis :: Int -> Fis -> Fis
232 filterMinorFis min fis = Map.filter (\s -> s > min) fis
233
234
235 -- | To filter Fis with small Support but by keeping non empty Periods
236 filterMinorFisNonEmpty :: Int -> Fis -> Fis
237 filterMinorFisNonEmpty min fis = if (Map.null fis') && (not $ Map.null fis)
238 then filterMinorFisNonEmpty (min - 1) fis
239 else fis'
240 where
241 --------------------------------------
242 fis' :: Fis
243 fis' = filterMinorFis min fis
244 --------------------------------------
245
246
247 -- | To filter nested Fis
248 filterFisByNested :: Map (Date, Date) Fis -> Map (Date, Date) Fis
249 filterFisByNested = map (\fis -> restrictKeys fis
250 $ Set.fromList
251 $ filterNestedSets (head (keys fis)) (keys fis) []
252 )
253
254
255 -- | To transform a list of Documents into a Frequent Items Set
256 docsToFis :: Map (Date, Date) [Document] -> Map (Date, Date) Fis
257 docsToFis docs = map (\d -> fisWithSizePolyMap
258 (Segment 1 20)
259 1
260 (map (words . text) d)) docs
261
262
263 phyloFisFiltered :: Map (Date, Date) Fis
264 phyloFisFiltered = filterFisBySupport True 1 (filterFisByNested phyloFis)
265
266
267 phyloFis :: Map (Date, Date) Fis
268 phyloFis = docsToFis phyloPeriods
269
270
271 ------------------------------------------------------------------------
272 -- | STEP 7 | -- Link level -1 to level 0
273
274
275 phyloLinked_m1_0 :: Phylo
276 phyloLinked_m1_0 = alterLevelLinks lvl_m1_0 phyloLinked_0_m1
277
278
279 lvl_m1_0 :: LevelLink
280 lvl_m1_0 = initLevelLink (initLevel (-1) Level_m1) (initLevel 0 Level_0)
281
282
283 ------------------------------------------------------------------------
284 -- | STEP 6 | -- Link level 0 to level -1
285
286
287 -- | To set the LevelLinks between a given PhyloGroup and a list of childs/parents PhyloGroups
288 linkGroupToGroups :: LevelLink -> PhyloGroup -> [PhyloGroup] -> PhyloGroup
289 linkGroupToGroups lvl current targets
290 | getLevelLinkValue From lvl < getLevelLinkValue To lvl = setLevelParents current
291 | getLevelLinkValue From lvl > getLevelLinkValue To lvl = setLevelChilds current
292 | otherwise = current
293 where
294 --------------------------------------
295 setLevelChilds :: PhyloGroup -> PhyloGroup
296 setLevelChilds = over (phylo_groupLevelChilds) addPointers
297 --------------------------------------
298 setLevelParents :: PhyloGroup -> PhyloGroup
299 setLevelParents = over (phylo_groupLevelParents) addPointers
300 --------------------------------------
301 addPointers :: [Pointer] -> [Pointer]
302 addPointers lp = lp ++ Maybe.mapMaybe (\target ->
303 if shouldLink lvl (_phylo_groupNgrams current)
304 (_phylo_groupNgrams target )
305 then Just ((getGroupId target),1)
306 else Nothing) targets
307 --------------------------------------
308
309
310 -- | To set the LevelLinks between two lists of PhyloGroups
311 linkGroupsByLevel :: LevelLink -> Phylo -> [PhyloGroup] -> [PhyloGroup]
312 linkGroupsByLevel lvl p groups = map (\group ->
313 if getGroupLevel group == getLevelLinkValue From lvl
314 then linkGroupToGroups lvl group (getGroupsWithFilters (getLevelLinkValue To lvl) (getGroupPeriod group) p)
315 else group ) groups
316
317
318 -- | To set the LevelLink of all the PhyloGroups of a Phylo
319 alterLevelLinks :: LevelLink -> Phylo -> Phylo
320 alterLevelLinks lvl p = alterPhyloGroups (linkGroupsByLevel lvl p) p
321
322
323 phyloLinked_0_m1 :: Phylo
324 phyloLinked_0_m1 = alterLevelLinks lvl_0_m1 phyloWithGroups0
325
326
327 lvl_0_m1 :: LevelLink
328 lvl_0_m1 = initLevelLink (initLevel 0 Level_0) (initLevel (-1) Level_m1)
329
330
331 ------------------------------------------------------------------------
332 -- | STEP 5 | -- Build level 0 as a copy of level -1
333
334
335 -- | To clone the last PhyloLevel of each PhyloPeriod and update it with a new LevelValue
336 clonePhyloLevel :: Int -> Phylo -> Phylo
337 clonePhyloLevel lvl p = alterPhyloLevels (\l -> addPhyloLevel
338 (setPhyloLevelId lvl $ head l)
339 l) p
340
341
342 phyloWithGroups0 :: Phylo
343 phyloWithGroups0 = updatePhyloByLevel (initLevel 0 Level_0) phyloWithGroupsm1
344
345
346 ------------------------------------------------------------------------
347 -- | STEP 4 | -- Build level -1
348
349
350 -- | To transform a list of Documents into a PhyloLevel
351 docsToPhyloLevel :: Int ->(Date, Date) -> [Document] -> Phylo -> PhyloLevel
352 docsToPhyloLevel lvl (d, d') docs p = initPhyloLevel
353 ((d, d'), lvl)
354 (map (\(f,s) -> initGroup [s] s f lvl d d' p)
355 $ zip [1..]
356 $ (nub . concat)
357 $ map (words . text) docs)
358
359
360 -- | To transform a Map of Periods and Documents into a list of PhyloPeriods
361 docsToPhyloPeriods :: Int -> Map (Date,Date) [Document] -> Phylo -> [PhyloPeriod]
362 docsToPhyloPeriods lvl docs p = map (\(id,l) -> initPhyloPeriod id l)
363 $ Map.toList levels
364 where
365 --------------------------------------
366 levels :: Map (Date,Date) [PhyloLevel]
367 levels = mapWithKey (\k v -> [docsToPhyloLevel lvl k v p]) docs
368 --------------------------------------
369
370
371 -- | To update a Phylo for a given Levels
372 updatePhyloByLevel :: Level -> Phylo -> Phylo
373 updatePhyloByLevel lvl p
374 = case getLevelLabel lvl of
375
376 Level_m1 -> appendPhyloPeriods (docsToPhyloPeriods (getLevelValue lvl) lvlData p) p
377 where
378 --------------------------------------
379 lvlData :: Map (Date,Date) [Document]
380 lvlData = phyloPeriods
381 --------------------------------------
382
383 Level_0 -> clonePhyloLevel (getLevelValue lvl) p
384
385 Level_1 -> fisToPhyloLevel lvlData p
386 where
387 --------------------------------------
388 lvlData :: Map (Date, Date) Fis
389 lvlData = phyloFisFiltered
390 --------------------------------------
391
392 _ -> panic ("[ERR][Viz.Phylo.Example.updatePhyloByLevel] Level not defined")
393
394
395 phyloWithGroupsm1 :: Phylo
396 phyloWithGroupsm1 = updatePhyloByLevel (initLevel (-1) Level_m1) phylo
397
398
399 ------------------------------------------------------------------------
400 -- | STEP 3 | -- Parse the Documents and group them by Periods
401
402
403 -- | To init a set of periods out of a given Grain and Step
404 docsToPeriods :: (Ord date, Enum date) => (doc -> date)
405 -> Grain -> Step -> [doc] -> Map (date, date) [doc]
406 docsToPeriods _ _ _ [] = panic "[ERR][Viz.Phylo.Example.docsToPeriods] Empty [Documents] can not have any periods"
407 docsToPeriods f g s es = Map.fromList $ zip hs $ map (inPeriode f es) hs
408 where
409 --------------------------------------
410 hs = steps g s $ both f (head es, last es)
411 --------------------------------------
412 inPeriode :: Ord b => (t -> b) -> [t] -> (b, b) -> [t]
413 inPeriode f' h (start,end) =
414 fst $ List.partition (\d -> f' d >= start && f' d <= end) h
415 --------------------------------------
416 steps :: (Eq date, Enum date) => Grain -> Step -> (date, date) -> [(date, date)]
417 steps s' o' (start,end) = map (\l -> (head l, last l))
418 $ chunkAlong s' o' [start .. end]
419 --------------------------------------
420
421
422 -- | To parse a list of Documents by filtering on a Vector of Ngrams
423 parseDocs :: PhyloNgrams -> [Document] -> [Document]
424 parseDocs l docs = map (\(Document d t) -> Document d (unwords
425 $ filter (\x -> Vector.elem x l)
426 $ monoTexts t)) docs
427
428
429 -- | To group a list of Documents by fixed periods
430 groupDocsByPeriod :: Grain -> Step -> [Document] -> Phylo -> Map (Date, Date) [Document]
431 groupDocsByPeriod g s docs p = docsToPeriods date g s
432 $ parseDocs (getPhyloNgrams p) docs
433
434
435 phyloPeriods :: Map (Date, Date) [Document]
436 phyloPeriods = groupDocsByPeriod 5 3 phyloDocs phylo
437
438
439 ------------------------------------------------------------------------
440 -- | STEP 2 | -- Init an initial list of Ngrams and a Phylo
441
442
443 -- | To init a Phylomemy
444 initPhylo :: [Document] -> PhyloNgrams -> Phylo
445 initPhylo docs ngrams = Phylo (both date $ (last &&& head) docs) ngrams []
446
447
448 -- | To init a PhyloNgrams as a Vector of Ngrams
449 initNgrams :: [Ngrams] -> PhyloNgrams
450 initNgrams l = Vector.fromList $ map toLower l
451
452
453 phylo :: Phylo
454 phylo = initPhylo phyloDocs (initNgrams actants)
455
456
457 ------------------------------------------------------------------------
458 -- | STEP 1 | -- Get a list of Document
459
460
461 -- | To transform a corpus of texts into a structured list of Documents
462 corpusToDocs :: [(Date, Text)] -> [Document]
463 corpusToDocs l = map (\(d,t) -> Document d t) l
464
465
466 phyloDocs :: [Document]
467 phyloDocs = corpusToDocs corpus
468
469
470 ------------------------------------------------------------------------
471 -- | STEP 0 | -- Let's start with an example
472
473
474 actants :: [Ngrams]
475 actants = [ "Cleopatre" , "Ptolemee", "Ptolemee-XIII", "Ptolemee-XIV"
476 , "Marc-Antoine", "Cesar" , "Antoine" , "Octave" , "Rome"
477 , "Alexandrie" , "Auguste" , "Pompee" , "Cassius" , "Brutus"]
478
479
480 corpus :: [(Date, Text)]
481 corpus = 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")]