GSoC MMXIX: Reprehendo graphs ad bipartiteness et monas transformers

Ultima aestate interfui Estas Code Google - Rationis studiosorum ex Google. Singulis annis moderatores aliquot incepta Open Source deligunt, ex quibus tam notis institutis ut Boost.org и In Linux Foundation. Google discipulos ex toto orbe invitat ad operandum in his inceptis. 

Ut particeps in Google Aestatis Codicis MMXIX, consilium feci in bibliotheca alga cum organization Haskell.orgquae lingua Haskell evolvit - una e clarissimis linguis programmandi functionis. Bibliotheca est Alga repraesentans typus tutum repraesentatio graphi in Haskell. Ponitur, e.g semantics — bibliotheca Github quae semantica arbores aedificat, graphas vocant et dependentiae in codice fundatae et comparare possunt. Meum consilium erat repraesentationem typo-tutam addere pro graphis bipartitis et algorithms pro illa repraesentatione. 

In hoc poste loquar de exsecutione mea algorithmi ad reprimendam grapham bipartitae in Haskell. Etiamsi algorithmus unus ex primis fundamentalibus est, illud exsequens pulchre in stilo utilitatis me nonnullas iterationes suscepit et satis multum laboris requirebat. Quam ob rem cum monas transformatoribus inserendum constitui. 

GSoC MMXIX: Reprehendo graphs ad bipartiteness et monas transformers

About Me

Nomen meum est Vasily Alferov, discipulus sum quarti anni apud St. Petersburg HSE. Antea in diario scripsi de project de parameterized algorithms и de itinere ad ZuriHac. Nunc ego in amet at Universitas Bergensis in Norvegia, ubi laboro in accessu ad problema Coloring album. Meae utilitates algorithmos parameterized et programmatio functionis includunt.

De exsequendo algorithmus

praefatio

Alumni programmatis participantes valde incitantur ad blog. Praebuerunt mihi suggestum diarii Aestas de Haskell. Hic articulus est translatio vasaa me ibi Julio Anglice scripta, cum praefatiuncula. 

Request viverra cum codice in quaestionem inveniri potest hic.

Legere potes de eventibus operis mei (Anglice) hic.

Haec epistula intendit lectorem consuescere cum notionibus fundamentalibus in programmatione functionis, licet conabimur revocare omnia verba ubi tempus venit.

Reprehendo graphs ad bipartiteness 

Algorithmus ad reprimendum graphi bipartiti- nem dari solet in cursu algorithmorum sicut unus e graphi simplicissimi algorithmorum. Idea eius directa est: primum in parte sinistra vel dextra aliqualiter vertices ponimus, et cum in margine alterno invenitur, graphum bipartitum non esse asserimus.

Aliquanto accuratius: primum verticem in aliqua parte sinistra ponimus. Videlicet omnes vicini huius vertex in dextro lobo jacere debent. Praeterea, omnes vicini vicini huius vertex in sinistro lobo jacere debent, et sic porro. Partes ad vertices assignantes pergimus quam dum adhuc sunt vertices in connexo verticis componente coepimus cum vicinis non assignavimus. Repetimus ergo hanc actionem pro omnibus componentibus connexis.

Si extremitas inter vertices in eandem partitionem incidat, haud difficile est cyclum imparem invenire in graphe, quem pervulgatum (et plane manifesto) impossibile est in graphe bipartito. Alioquin rectam partitionem habemus, quae per graphum bipartitum est.

Typice, hoc algorithmus usus impletur latitudinem primum quaerere aut profundum primum quaerere. In linguis imperativis, investigatio profundior prima plerumque adhibetur ut paulo simplicior est et additamenta notitiarum structurarum non requirit. Etiam profunditatem-primam inquisitionem elegi sicut magis traditam.

Quapropter ad sequentia schema devenimus. Vertices graphi percurrimus utentes profundiores inquisitionis primae portiones eis assignantes, mutando numerum participationis dum per ora movemus. Si partem verticis assignare conamur quae iam partem habet assignatam, tuto dicere possumus graphum bipartitum non esse. Nunc omnes vertices assignati sunt participes et perspeximus omnes oras, bonam partitionem habemus.

Puritas calculi

In Haskell supponimus omnes calculi purgant. Attamen, si ita se res haberet, nullo modo aliquid ad scrinii imprimendi rationem haberemus. Omnino, clean calculi tam piger ut nemo non clean de causis aliquid computare. Omnes calculi in programmatis occurrentes quodammodo coguntur "purus" monas IO.

Monades sunt modo ad calculos repraesentet effectus apud Haskell. Explicans quomodo opus sit extra ambitum huius stationis. Bona et perspicua descriptio Anglice legi potest hic.

Hic notare libet quod dum quaedam monades, ut IO, per magicas compilator perficiuntur, omnes fere aliae in programmate perficiuntur et omnes in eis calculi puri sunt.

Multus effectus es, et unusquisque monadem suum habet. Haec opinio validissima et pulcherrima est: omnes monades efficiunt eandem machinam. De tribus sequentibus monadibus loquemur:

  • Aut e a est calculus qui valorem type a reddit aut exceptionem generis e eiicit. Mores huius monadis valde similes sunt exceptioni in linguis imperativis tractandis: errores capi possunt vel transigi. Praecipua differentia est quod monas in bibliotheca vexillum in Haskell perfecte logice impletur, dum linguae imperativae machinationes operatrices plerumque utuntur.
  • Status s est calculus qui valorem type a reddit et aditum habet ad statum mutabilem typus s.
  • Fortasse a. Forsitan monas computationem exprimit quae nullo tempore interrumpi potest nihil reddens. Nihilominus loquemur de exsecutione ordinis MonadPlus pro typo Forsan, quod contrarium effectum exprimit: est calculus quovis tempore interrumpi potest valorem specificum reddendo.

Exsecutio algorithmus

Duas figuras datas habemus, Graph a et bigraphum a b, quarum prima graphs cum vertices intitulatis cum valores typo a repraesentat, et secunda graphos bipartitos cum vertices sinistro latere intitulatos cum valoribus typo a et dextra repraesentat. -side vertices cum valores generis intitulatum b.

Hae non sunt typi ex bibliotheca Alga. Alga repraesentationem pro graphis bipartitis indirectis non habet. Huiusmodi rationes ad claritatem feci.

Muneribus adiutoriis etiam egebimus cum subscriptionibus sequentibus:

-- Список соседей данной вершины.
neighbours :: Ord a => a -> Graph a -> [a]

-- Построить двудольный граф по графу и функции, для каждой вершины
-- выдающей её долю и пометку в новой доле, игнорируя конфликтные рёбра.
toBipartiteWith :: (Ord a, Ord b, Ord c) => (a -> Either b c)
                                         -> Graph a
                                         -> Bigraph b c

-- Список вершин в графе
vertexList :: Ord a => Graph a -> [a]
Сигнатура функции, которую мы будем писать, выглядит так:

type OddCycle a = [a]
detectParts :: Ord a => Graph a -> Either (OddCycle a) (Bigraph a a)

Facile perspicitur, si in profunditate primae inquisitionis repugnantem invenimus aciem, impar cyclus in vertice ACERVUS recursus iacet. Ita ut eam restituamus, necesse est ut omnia a recursionis acervo usque ad primum ultimi vertex occursum praecidant.

Investigationem primam efficiendam aggredimur, servando consociationem ordinatam numerorum communium pro singulis verticibus. BIBLIOTHECA recursio automatice conservabitur per exsecutionem ordinis Functoris monadis quam elegimus: tantum necesse est omnes vertices ponere a via in exitum recurrentis functionis recurrentis.

Prima opinio mea erat utendi vel monade, quae ad effectum deduci videtur effectibus quibus opus est. Primum exsecutionem scripsimus huic optioni proximus fuit. Nam in uno puncto quinque varias exsecutiones habui, et tandem in alio conlocavi.

Primum, necesse est ponere ordinatam aciem participes identificantium - hoc est aliquid de re publica. Alio modo, quando detegitur conflictus prohibere posse. Hoc esse potest vel Monad pro Aut, vel MonadPlus pro Forsan. Praecipua differentia est, quod Aut valorem reddere potest si ratio non cessat, et fortasse solum informationes de hoc casu redit. Cum non opus sit singulari pretii successu (iam in re publica conditur), fortasse eligimus. Et in momento, quo duo monadum effectus miscere necesse est, exeunt Monad transformersquae sane cohaerent.

Cur eligo genus tam implicatum? Duas rationes. Uno modo, exsecutio evadit imperativi simillima. Secundo, opus est valorem reditus mutare in casu conflictus cum regressus a recursus ad restituendum ansam impar, quod multo facilius est facere in Forsitan monad.

Unde hanc exsecutionem consequimur.

{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE ScopedTypeVariables #-}

data Part = LeftPart | RightPart

otherPart :: Part -> Part
otherPart LeftPart  = RightPart
otherPart RightPart = LeftPart

type PartMap a = Map.Map a Part
type OddCycle a = [a]

toEither :: Ord a => PartMap a -> a -> Either a a
toEither m v = case fromJust (v `Map.lookup` m) of
                    LeftPart  -> Left  v
                    RightPart -> Right v

type PartMonad a = MaybeT (State (PartMap a)) [a]

detectParts :: forall a. Ord a => Graph a -> Either (OddCycle a) (Bigraph a a)
detectParts g = case runState (runMaybeT dfs) Map.empty of
                     (Just c, _)  -> Left  $ oddCycle c
                     (Nothing, m) -> Right $ toBipartiteWith (toEither m) g
    where
        inVertex :: Part -> a -> PartMonad a
        inVertex p v = ((:) v) <$> do modify $ Map.insert v p
                                      let q = otherPart p
                                      msum [ onEdge q u | u <- neigbours v g ]

        {-# INLINE onEdge #-}
        onEdge :: Part -> a -> PartMonad a
        onEdge p v = do m <- get
                        case v `Map.lookup` m of
                             Nothing -> inVertex p v
                             Just q  -> do guard (q /= p)
                                           return [v]

        processVertex :: a -> PartMonad a
        processVertex v = do m <- get
                             guard (v `Map.notMember` m)
                             inVertex LeftPart v

        dfs :: PartMonad a
        dfs = msum [ processVertex v | v <- vertexList g ]

        oddCycle :: [a] -> [a]
        oddCycle c = tail (dropWhile ((/=) last c) c)

Ubi scandalum est nucleus algorithmi. Quid intus agatur, conabor explicare.

  • inVertex est pars profundissimae inquisitionis ubi primum verticem invisimus. Hic numerum ad verticem communem assignamus et in omnibus vicinis unum Edge est. Hoc est etiam ubi restituimus vocamus acervum: si msum valorem reddidimus, vertex v illic impellimus.
  • oneEdge est pars qua nos visitamus in ore. Bis pro quolibet ore dicitur. Hic refutamus si vertex in altera parte visitata est, et si non visitamus. Si visitatur, refutamus utrum obstet. Si est, redimus valorem ipsum cacumen recursionis acervi, ubi omnes alii vertices tunc in reditu collocabuntur.
  • processusVertex pro utroque vertice cohibet utrum visitata sit et inVertex in ea currit, si non.
  • dfs processVertex in omnes vertices decurrit.

Id omne.

Historia verbi INLINE

Verbum INLINE non fuit in prima algorithmi exsecutione, postea apparuit. Cum conabar exsequendam meliorem invenire, inveni versionem non-INLINEI in quibusdam graphis notabiliter tardiorem fuisse. Cum functiones semantically eadem operari deberent, id me valde miratus sum. Etiam peregrinus in alia machina cum GHC diversa versione nulla notabilis differentia fuit.

Cum per hebdomadam legerem GHC Core output, potui problema una linea expressa INLINE figere. In aliquo puncto inter GHC 8.4.4 et GHC 8.6.5 optimizer se facere desiit.

Non expectavi ut haskell in programmatibus sordes tantas occurreret. Tamen etiam hodie optimizers interdum peccant, et nostrum officium est illis innuere. Exempli gratia, hic scimus quia debet inlineari munus, quia in versione imperativi inlinetur, et hoc est causa admoniti compilatoris.

§ ± » ° » € µ?

Deinde algorithmum Hopcroft-Karp cum aliis monadibus induxi, et ille finis progressionis fuit.

Gratias Google Aestatis Codicis, experientiam practicam consecutus sum in programmatione functionis, quae non solum me adiuvit ut proximam aestatem in Jane Vico amet (Non certo scio quam notissimus locus sit etiam apud discentium audientiam Habr, sed unus est. paucorum in quibus aestas potes programmandi munus exercere), sed etiam me induxit ad mirificum mundum applicandi hoc paradigma in praxi, insigniter diversum ab experientia in traditis linguis.

Source: www.habr.com

Add a comment