GSoC 2019: Ke nānā nei i nā kiʻi no ka bipartiteness a me nā mea hoʻololi monad

I ke kauwela i hala, ua komo au Ke Kūkākūkā o Google Keʻena - he polokalamu no nā haumāna mai Google. I kēlā me kēia makahiki, koho nā mea hoʻonohonoho i kekahi mau papahana Open Source, me nā hui kaulana e like me Boost.org и ʻO ka Linux Linux. Kāhea ʻo Google i nā haumāna mai ka honua holoʻokoʻa e hana i kēia mau papahana. 

Ma ke ʻano he mea komo ma Google Summer of Code 2019, ua hana wau i kahi papahana i loko o ka waihona Alga me ka hui Haskell.org, e hoʻomohala nei i ka ʻōlelo Haskell - kekahi o nā ʻōlelo hoʻolālā hana kaulana loa. He hale waihona puke ʻo Alga ʻano palekana hōʻike no nā kiʻi ma Haskell. Hoʻohana ʻia, no ka laʻana, ma helena - kahi waihona Github e kūkulu ana i nā kumulāʻau semantic, kelepona a me nā kiʻi hilinaʻi e pili ana i ke code a hiki ke hoʻohālikelike iā lākou. ʻO kaʻu papahana e hoʻohui i kahi hōʻike palekana ʻano no nā kiʻi bipartite a me nā algorithms no kēlā hōʻike. 

Ma kēia pou e kamaʻilio wau e pili ana i kaʻu hoʻokō ʻana i kahi algorithm no ka nānā ʻana i kahi pakuhi no ka bipartiteness ma Haskell. ʻOiai ʻo ka algorithm kekahi o nā mea maʻamau, ʻo ka hoʻokō ʻana me ka nani i ke ʻano hana i lawe iaʻu i nā ʻano hou a makemake nui i ka hana. ʻO ka hopena, ua hoʻoholo wau i kahi hoʻokō me nā mea hoʻololi monad. 

GSoC 2019: Ke nānā nei i nā kiʻi no ka bipartiteness a me nā mea hoʻololi monad

Noʻu

ʻO Vasily Alferov koʻu inoa, he haumāna ʻehā au ma St. Petersburg HSE. Ma mua o ka blog aʻu i kākau ai e pili ana i kaʻu papahana e pili ana i nā algorithms parameterized и e pili ana i ka huakaʻi i ZuriHac. I kēia manawa aia wau i kahi internship ma Kulanui o Bergen ma Norewai, kahi aʻu e hana nei i ka hoʻokokoke ʻana i ka pilikia Kalai Papa inoa. ʻO kaʻu mau mea hoihoi e pili ana i nā algorithm parameterized a me ka hoʻolālā hana.

E pili ana i ka hoʻokō ʻana i ka algorithm

Kauwehe

Paipai nui ʻia nā haumāna e komo ana i ka papahana e blog. Hāʻawi lākou iaʻu i kahi kahua no ka blog Kaumaha o Haskell. He unuhi kēia ʻatikala nāʻatikala, kākau ʻia e aʻu ma laila i Iulai ma ka ʻōlelo Pelekania, me kahi ʻōlelo mua pōkole. 

Hiki ke loaʻa ke noi huki me ke code i nīnau ʻia maanei.

Hiki iā ʻoe ke heluhelu e pili ana i nā hopena o kaʻu hana (ma ka ʻōlelo Pelekania) maanei.

Ua manaʻo ʻia kēia pou e hoʻomaʻamaʻa i ka mea heluhelu i nā manaʻo kumu i ka hoʻolālā hana, ʻoiai e hoʻāʻo wau e hoʻomanaʻo i nā huaʻōlelo āpau i hoʻohana ʻia ke hiki mai ka manawa.

Ke nānā ʻana i nā kiʻi no ka bipartiteness 

Hāʻawi pinepine ʻia kahi algorithm no ka nānā ʻana i ka pakuhi no ka bipartiteness ma kahi papa e pili ana i nā algorithms ma ke ʻano he mea maʻalahi loa. Maikaʻi kona manaʻo: hoʻokomo mua mākou i nā vertices ma ka ʻaoʻao hema a ʻākau paha, a ke ʻike ʻia kahi ʻaoʻao hakakā, ʻōlelo mākou ʻaʻole bipartite ka pakuhi.

ʻO kahi kikoʻī hou aʻe: kau mua mākou i kahi vertex ma ka ʻaoʻao hema. ʻIke loa, pono nā hoalauna āpau o kēia vertex e moe i ka lobe ʻākau. Eia kekahi, pono e moe nā hoalauna a pau o kēia vertex ma ka lobe hema, a pēlā aku. Ke hoʻomau nei mākou i ka hāʻawi ʻana i nā ʻāpana i nā vertex ke loaʻa nā vertex i ka ʻāpana pili o ka vertex a mākou i hoʻomaka ai me ka mea ʻaʻole mākou i hoʻonohonoho i nā hoalauna. A laila hana hou mākou i kēia hana no nā ʻāpana pili.

Inā he kaʻe ma waena o nā vertices e hāʻule i loko o ka pā hoʻokahi, ʻaʻole paʻakikī ke ʻimi i kahi pōʻaiapuni ʻē aʻe i ka pakuhi, i ʻike nui ʻia (a maopopo loa) hiki ʻole i ka pakuhi bipartite. A i ʻole, loaʻa iā mākou kahi ʻāpana kūpono, ʻo ia hoʻi he bipartite ka pakuhi.

ʻO ka maʻamau, hoʻokō ʻia kēia algorithm me ka hoʻohana ʻana laula huli mua ai ole ia, huli mua hohonu. Ma nā ʻōlelo koʻikoʻi, hoʻohana pinepine ʻia ka hulina hohonu-mua no ka mea he maʻalahi iki a ʻaʻole koi i nā hale ʻikepili hou. Ua koho nō hoʻi au i ka hulina hohonu-mua no ka mea ʻoi aku ka maʻamau.

No laila, ua hiki mai mākou i ka papahana aʻe. Hele mākou i nā piko o ka pakuhi me ka huli ʻana i ka hohonu-mua a hāʻawi i nā ʻāpana iā lākou, e hoʻololi ana i ka helu o ka mahele i ko mākou neʻe ʻana ma ka lihi. Inā hoʻāʻo mākou e hāʻawi i kahi ʻāpana i kahi vertex i loaʻa i kahi ʻāpana i hāʻawi ʻia, hiki iā mākou ke ʻōlelo palekana ʻaʻole bipartite ka pakuhi. ʻO ka manawa i hāʻawi ʻia nā vertices a pau i kaʻana a ua nānā mākou i nā ʻaoʻao āpau, loaʻa iā mākou kahi ʻāpana maikaʻi.

Maʻemaʻe o ka helu ʻana

Ma Haskell manaʻo mākou ʻo nā helu āpau maʻemaʻe. Eia naʻe, inā ʻoiaʻiʻo kēia, ʻaʻohe o mākou ala e paʻi i kekahi mea i ka pale. I nā mea āpau, maʻemaʻe moloā loa ka helu ʻana a ʻaʻole hoʻokahi maʻemaʻe kumu e helu ai i kekahi mea. Hoʻokomo ʻia nā helu ʻana a pau i loko o ka papahana "maemae" monad IO.

He ala ʻo Monads e hōʻike i ka helu ʻana me hopena ma Haskell. ʻO ka wehewehe ʻana i ke ʻano o kā lākou hana ʻana ma waho o ke kiko o kēia pou. Hiki ke heluhelu ʻia kahi wehewehe maikaʻi a maopopo ma ka ʻōlelo Pelekania maanei.

Maanei, makemake wau e kuhikuhi i ka wā e hoʻokō ʻia ai kekahi mau monads, e like me IO, ma o ka compiler magic, aneane pau nā mea ʻē aʻe i hoʻokō ʻia i nā polokalamu a pau nā helu i loko o ia mau mea maʻemaʻe.

Nui nā hopena a loaʻa i kēlā me kēia me kāna monad ponoʻī. He manaʻo ikaika a nani loa kēia: hoʻokō nā monad a pau i ka interface like. E kamaʻilio mākou e pili ana i kēia mau monad ʻekolu:

  • ʻO ka ea ka helu ʻana e hoʻihoʻi i kahi waiwai o ke ʻano a a i ʻole e hoʻolei i kahi ʻokoʻa o ke ʻano e. Ua like loa ke ano o keia monad me ka lawelawe ana ma na olelo koʻikoʻi: hiki ke hopu a hoʻolilo ʻia nā hewa. ʻO ka ʻokoʻa nui ʻo ia ka hoʻokō pono ʻana o ka monad i ka hale waihona puke ma Haskell, aʻo nā ʻōlelo koʻikoʻi e hoʻohana pinepine i nā ʻōnaehana ʻōnaehana.
  • ʻO ka mokuʻāina sa he helu helu e hoʻihoʻi i kahi waiwai o ke ʻano a a loaʻa iā ia ke ʻano hoʻololi o ke ʻano s.
  • Malia paha a. Hōʻike ka Maybe monad i ka helu ʻana i hiki ke hoʻopau ʻia i kēlā me kēia manawa ma ka hoʻihoʻi ʻana ʻAʻohe mea. Eia naʻe, e kamaʻilio mākou e pili ana i ka hoʻokō ʻana o ka papa MonadPlus no ke ʻano ʻo Maybe, e hōʻike ana i ka hopena kū'ē: he helu ia e hiki ke hoʻopau ʻia i kēlā me kēia manawa ma ka hoʻihoʻi ʻana i kahi waiwai kikoʻī.

Ka hoʻokō ʻana i ka algorithm

Loaʻa iā mākou ʻelua ʻano ʻikepili, ʻo Graph a a me Bigraph ab, ʻo ka mea mua e hōʻike ana i nā kiʻi me nā vertices i hōʻailona ʻia me nā waiwai o ke ʻano a, a ʻo ka lua e hōʻike ana i nā kiʻi bipartite me nā ʻaoʻao hema hema i hōʻailona ʻia me nā waiwai o ke ʻano a me ka ʻākau. -ʻaoʻao vertice i hōʻailona ʻia me nā waiwai o ke ʻano b.

ʻAʻole kēia nā ʻano mai ka waihona Alga. ʻAʻohe o Alga i hōʻike no nā kiʻi bipartite kuhikuhi ʻole. Ua hana au i nā ʻano like me kēia no ka maopopo.

Pono mākou i nā hana kōkua me nā pūlima aʻe:

-- Список соседей данной вершины.
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)

He mea maʻalahi ke ʻike inā ʻike mākou i kahi ʻaoʻao hakakā i ka wā o ka hulina mua, aia ka pōʻai ʻē aʻe ma luna o ka waihona recursion. No laila, no ka hoʻihoʻi hou ʻana, pono mākou e ʻoki i nā mea āpau mai ka recursion stack a hiki i ka hanana mua o ka vertex hope.

Hoʻokō mākou i ka hulina hohonu-mua ma ka mālama ʻana i kahi hui hui o nā helu kaʻana no kēlā me kēia vertex. E mālama pono ʻia ka waihona hoʻihoʻi ma o ka hoʻokō ʻana i ka papa Functor o ka monad a mākou i koho ai: pono mākou e kau i nā vertices a pau mai ke ala i ka hopena i hoʻihoʻi ʻia mai ka hana recursive.

ʻO kaʻu manaʻo mua e hoʻohana i ka Either monad, ka mea e hoʻokō pono i nā hopena e pono ai mākou. ʻO ka hoʻokō mua aʻu i kākau ai ua kokoke loa i kēia koho. ʻO kaʻoiaʻiʻo, ua loaʻa iaʻu nā hoʻokō ʻokoʻa ʻelima i hoʻokahi manawa a ua hoʻoholo hope i kekahi.

ʻO ka mea mua, pono mākou e mālama i kahi hui hui o nā mea hōʻike - he mea kēia e pili ana i ka Moku'āina. ʻO ka lua, pono mākou e hiki ke hoʻōki ke ʻike ʻia kahi hakakā. Hiki iā ia ke Monad no Either, a i ʻole MonadPlus no paha. ʻO ka ʻokoʻa nui ʻo ia ka hiki ke hoʻihoʻi i kahi waiwai inā ʻaʻole i hoʻōki ʻia ka helu ʻana, a hiki paha ke hoʻihoʻi wale i ka ʻike e pili ana i kēia ma kēia hihia. No ka mea ʻaʻole pono mākou i kahi waiwai ʻokoʻa no ka kūleʻa (ua mālama ʻia ma ka Mokuʻāina), koho mākou ʻo paha. A i ka manawa e pono ai mākou e hoʻohui i nā hopena o ʻelua mau monads, puka mai lākou nā mea hoʻololi monad, ka mea i hoʻohui pono i kēia mau hopena.

No ke aha wau i koho ai i kēlā ʻano paʻakikī? ʻElua kumu. ʻO ka mea mua, ua like ka hoʻokō ʻana me ka imperative. ʻO ka lua, pono mākou e hoʻololi i ka waiwai hoʻihoʻi i ka hihia i ka wā e hoʻi ai mai ka recursion e hoʻihoʻi i ka loop loop, ʻoi aku ka maʻalahi o ka hana ʻana i ka monad Maybe.

No laila, loaʻa iā mākou kēia hoʻokō.

{-# 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)

ʻO kahi poloka ke kumu o ka algorithm. E ho'āʻo wau e wehewehe i nā mea e hana nei i loko.

  • ʻO inVertex ka ʻāpana o ka hulina hohonu-mua kahi a mākou e kipa ai i ka vertex no ka manawa mua. Maanei mākou e hāʻawi ai i kahi helu kaʻana i ka vertex a holo ma onEdge ma nā hoalauna āpau. ʻO kēia hoʻi kahi e hoʻihoʻi ai mākou i ka waihona kelepona: inā hoʻihoʻi ʻo msum i kahi waiwai, e pana mākou i ka vertex v ma laila.
  • ʻO onEdge ka ʻāpana a mākou e kipa aku ai i ka lihi. Kāhea ʻia ʻelua no kēlā me kēia ʻaoʻao. Maanei mākou e nānā inā ua kipa ʻia ka vertex ma kēlā ʻaoʻao, a kipa aku inā ʻaʻole. Inā kipa ʻia, nānā mākou inā kūʻē paha ka ʻaoʻao. Inā ʻo ia, e hoʻihoʻi mākou i ka waiwai - ka luna loa o ka waihona recursion, kahi e kau ʻia ai nā vertices ʻē aʻe a pau i ka hoʻi ʻana.
  • Nānā processVertex no kēlā me kēia vertex inā ua kipa ʻia a holo i loko o Vertex inā ʻaʻole.
  • holo ka dfs i ka processVertex ma nā piko a pau.

ʻo ia wale nō.

Moolelo o ka huaolelo INLINE

ʻAʻole ka huaʻōlelo INLINE i ka hoʻokō mua ʻana o ka algorithm; ua ʻike ʻia ma hope. I koʻu hoʻāʻo ʻana e ʻimi i kahi hoʻokō ʻoi aku ka maikaʻi, ʻike wau ua ʻoi aku ka lohi o ka mana non-INLINE ma kekahi mau kiʻi. Ke noʻonoʻo nei e hana like nā hana i ka semantically, ua kāhāhā nui kēia iaʻu. ʻO ka malihini, ma kahi mīkini ʻē aʻe me kahi ʻano ʻē aʻe o GHC ʻaʻohe ʻokoʻa ʻike.

Ma hope o ka hoʻolilo ʻana i hoʻokahi pule i ka heluhelu ʻana i ka puka GHC Core, ua hiki iaʻu ke hoʻoponopono i ka pilikia me hoʻokahi laina o INLINE. I kekahi manawa ma waena o GHC 8.4.4 a me GHC 8.6.5 ua ho'ōki ka mea hoʻoponopono i ka hana ʻana ma kāna iho.

ʻAʻole wau i manaʻo e hālāwai me ia lepo i ka polokalamu Haskell. Eia nō naʻe, i kēia lā, hana hewa ka poʻe optimizers i kekahi manawa, a ʻo kā mākou hana ke hāʻawi iā lākou i nā hōʻailona. Eia kekahi laʻana, maʻaneʻi mākou eʻike pono e hoʻokomoʻia ka hana no ka mea ua hoʻokomoʻia i ka mana imperative, a he kumu kēia e hāʻawi ai i ka mea hōʻuluʻulu i kahi hint.

He aha ka hope?

A laila ua hoʻokō au i ka algorithm Hopcroft-Karp me nā monads ʻē aʻe, a ʻo ia ka hopena o ka papahana.

Mahalo iā Google Summer of Code, ua loaʻa iaʻu ka ʻike kūpono i ka hoʻolālā hana, ʻaʻole ia i kōkua wale iaʻu e loaʻa i kahi internship ma Jane Street i ke kauwela e hiki mai ana (ʻaʻole maopopo iaʻu i ka kaulana o kēia wahi ma waena o ka poʻe ʻike ʻike o Habr, akā hoʻokahi nō. o nā wahi liʻiliʻi e hiki ai iā ʻoe ke kauwela e komo i ka hoʻolālā hana), akā ua hoʻolauna pū iaʻu i ka honua kupaianaha o ka hoʻohana ʻana i kēia paradigm i ka hana, ʻokoʻa loa mai koʻu ʻike ma nā ʻōlelo kuʻuna.

Source: www.habr.com

Pākuʻi i ka manaʻo hoʻopuka