I-GSoC 2019: Ukujonga iigrafu ze-bipartiteness kunye ne-monad transformers

Ngehlobo lokugqibela ndiye ndathatha inxaxheba Ihlobo laseGoogle leKhowudi - inkqubo yabafundi abavela kuGoogle. Rhoqo ngonyaka, abaququzeleli bakhetha iiprojekthi ezininzi zoMthombo oVulekileyo, kubandakanywa nemibutho eyaziwayo njenge Boost.org и Isiseko seLinux. UGoogle umema abafundi abavela kwihlabathi liphela ukuba basebenze kwezi projekthi. 

Njengomthathi-nxaxheba kwiHlobo likaGoogle leKhowudi ka-2019, ndenze iprojekthi ngaphakathi kwithala leencwadi Alga kunye nombutho Haskell.org, ephuhlisa ulwimi lwe-Haskell - enye yezona lwimi zidumileyo zokuprograma ezisebenzayo. I-Alga lithala leencwadi elimele chwetheza ngokukhuselekileyo ukumelwa kweegrafu eHaskell. Isetyenziswa, umzekelo, kwi intsingiselo - ilayibrari yeGithub eyakha imithi ye-semantic, ifowuni kunye neegrafu ezixhomekeke kwikhowudi kwaye unokuzithelekisa. Iprojekthi yam yayikukongeza uhlobo olukhuselekileyo lokumelwa kwiigrafu ze-bipartite kunye ne-algorithms yolo melo. 

Kule post ndiza kuthetha malunga nokuphunyezwa kwam kwe-algorithm yokujonga igrafu ye-bipartiteness kwi-Haskell. Nangona i-algorithm yenye yezona zinto zisisiseko, ukuyiphumeza kakuhle kwisitayile esisebenzayo kundithathe ngokuphindaphindiweyo kwaye kufuna umsebenzi omninzi. Ngenxa yoko, ndazinza ekuphunyezweni kunye neenguqu ze-monad. 

I-GSoC 2019: Ukujonga iigrafu ze-bipartiteness kunye ne-monad transformers

Malunga nam

Igama lam nguVasily Alferov, ndingumfundi wesine eSt. Petersburg HSE. Ngaphambili kwiblogi ndabhala malunga neprojekthi yam malunga neparameterized algorithms и malunga nohambo oluya eZuriHac. Ngoku ndikwi-internship IYunivesithi yaseBergen eNorway, apho ndisebenza kwiindlela zokuhlangabezana nale ngxaki Uluhlu lwemibala. Izinto endinomdla kuzo ziquka iparameterized algorithms kunye nenkqubo esebenzayo.

Malunga nokuphunyezwa kwe-algorithm

I ngcaciso

Abafundi abathatha inxaxheba kule nkqubo bakhuthazwa kakhulu ukuba bablogu. Bandibonelele ngeqonga lebhlog Ihlobo laseHaskell. Eli nqaku yinguqulelo amanqaku, ebhalwe ndim apho ngoJulayi ngesiNgesi, enentshayelelo emfutshane. 

Ukutsalwa kwesicelo ngekhowudi echaphazelekayo inokufumaneka apha.

Unokufunda malunga neziphumo zomsebenzi wam (ngesiNgesi) apha.

Esi sithuba sithatha ukuba umfundi uqhelana neengcamango ezisisiseko kwiprogram esebenzayo, nangona ndiya kuzama ukukhumbula yonke imimiselo esetyenziswayo xa kufika ixesha.

Ukujonga iigrafu ukuba kukho kabini 

I-algorithm yokukhangela igrafu ye-bipartiteness idla ngokunikezelwa kwikhosi kwii-algorithms njengenye ye-algorithms yegrafu elula. Ingcamango yakhe iqondile: okokuqala sibeka i-vertices kwisabelo sasekhohlo okanye ekunene, kwaye xa umgca ophikisanayo ufunyenwe, siqinisekisa ukuba igrafu ayikho i-bipartite.

Iinkcukacha ezingakumbi: okokuqala sibeka i-vertex kwisabelo sasekhohlo. Ngokucacileyo, bonke abamelwane bale vertex kufuneka balale kwilobe elungileyo. Ngaphezu koko, bonke abamelwane babamelwane beli vertex kufuneka balale kwi-lobe ekhohlo, njalo njalo. Siyaqhubeka nokwabela izabelo kwii-vertices ukuba nje kusekho ii-vertices kwicandelo elidityanisiweyo le-vertex esiqale ngayo esingakhange sibanike abamelwane. Emva koko siphinda esi senzo kuwo onke amacandelo adibeneyo.

Ukuba kukho umda phakathi kwee-vertices eziwela kwisahlulelo esifanayo, akukho nzima ukufumana umjikelo ongaqhelekanga kwigrafu, owaziwa ngokubanzi (kwaye ngokucacileyo) awunakwenzeka kwigrafu ephindwe kabini. Ngaphandle koko, sinesahlulo esichanekileyo, oku kuthetha ukuba igrafu i-bipartite.

Ngokuqhelekileyo, le algorithm iphunyezwa kusetyenziswa ububanzi uphendlo lokuqala okanye ubunzulu uphendlo lokuqala. Kwiilwimi ezinyanzelekileyo, ukukhangela ubunzulu-kokuqala ngokuqhelekileyo kusetyenziswa njengoko kulula kancinane kwaye akufuni izakhiwo zedatha ezongezelelweyo. Ndiphinde ndakhetha ukukhangela ubunzulu-kokuqala njengoko kuqhelekile.

Ngaloo ndlela, sifike kwisicwangciso esilandelayo. Sityhutyha ii-vertices zegrafu sisebenzisa ubunzulu bokukhangela kuqala kwaye sibanike izabelo, sitshintsha inani lesabelo njengoko sihamba ecaleni komphetho. Ukuba sizama ukwabela isabelo kwi-vertex esele inesabelo esabelweyo, sinokuthi ngokukhuselekileyo ukuba igrafu ayikho i-bipartite. Lo mzuzu zonke ii-vertices zabelwa isabelo kwaye sijonge kuyo yonke imiphetho, sinolwahlulo oluhle.

Ukusulungeka kwezibalo

KwiHaskell sicinga ukuba zonke izibalo zikho icocekile. Nangona kunjalo, ukuba oku bekunjalo ngokwenene, ngekhe sibenayo indlela yokuprinta nantoni na kwiscreen. Kukonke, icocekile izibalo zonqena kangangokuba akukho namnye icocekile izizathu zokubala into. Zonke izibalo ezenzekayo kwinkqubo zinyanzeliswa ngandlela thile ukuba zingene "ingcolile" umona IO.

IiMonads yindlela yokumela izibalo nge iziphumo eHaskell. Ukuchaza indlela abasebenza ngayo kungaphaya kobubanzi besi sithuba. Inkcazo elungileyo necacileyo inokufundwa ngesiNgesi apha.

Apha ndifuna ukubonisa ukuba ngelixa ezinye iimonads, ezifana ne-IO, ziphunyezwa ngomlingo wokuhlanganisa, phantse zonke ezinye ziphunyezwa kwisofthiwe kwaye zonke izibalo kuzo zihlambulukile.

Kukho iziphumo ezininzi kwaye nganye ine-monad yayo. Le ithiyori eyomeleleyo kwaye intle: zonke iimonads zisebenzisa ujongano olufanayo. Siza kuthetha ngezi monads ezintathu zilandelayo:

  • Nokuba i-ea lubalo olubuyisela ixabiso lohlobo a okanye oluphosa ngaphandle kohlobo e. Indlela yokuziphatha yale monad ifana kakhulu nokuphatha ngaphandle kweelwimi ezinyanzelekileyo: iimpazamo zinokubanjwa okanye zigqithiswe. Umahluko ophambili kukuba i-monad iphunyezwe ngokupheleleyo kwithala leencwadi elisemgangathweni eHaskell, ngelixa iilwimi eziyimfuneko zihlala zisebenzisa iindlela zokusebenza.
  • I-State sa lubalo olubuyisela ixabiso lohlobo a kwaye inokufikelela kwisimo esiguqukayo sohlobo s.
  • Mhlawumbi a. I-Maybe monad ivakalisa i-computing enokuphazamiseka nangaliphi na ixesha ngokubuyisela Akukho nto. Nangona kunjalo, siya kuthetha malunga nokuphunyezwa kweklasi ye-MonadPlus yoMnambi uhlobo, olubonisa umphumo ochaseneyo: lubalo olunokuphazamiseka nangaliphi na ixesha ngokubuyisela ixabiso elithile.

Ukuphunyezwa kwe-algorithm

Sineentlobo ezimbini zedatha, iGrafu a kunye neBigraph ab, eyokuqala emele iigrafu ezineendidi ezibhalwe ngamaxabiso odidi a, kwaye eyesibini imele iigrafu zebipartite ezinecala lasekhohlo elibhalwe ngamaxabiso odidi a kunye nasekunene. -i-vertices esecaleni ebhalwe ngamaxabiso ohlobo b.

Ezi ayizontlobo ezivela kwithala leencwadi laseAlga. I-alga ayinayo inkcazo yeegrafu ze-bipartite ezingayalwanga. Ndenze iintlobo ezinje ukuze zicace.

Siza kuphinda sifune imisebenzi yabancedi ngezi tyikityo zilandelayo:

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

Kulula ukubona ukuba ngexesha lokukhangela ubunzulu bokuqala sifumene umda ophikisanayo, umjikelo ongaqhelekanga ulele phezu kwe-stack recursion. Ke, ukuyibuyisela, kufuneka sinqumle yonke into ukusuka kwi-recursion stack ukuya kwisenzeko sokuqala se-vertex yokugqibela.

Siphumeza ukhangelo olunzulu lokuqala ngokugcina uluhlu oludibeneyo lwamanani ezabelo kwivertex nganye. I-recursion stack iya kugcinwa ngokuzenzekelayo ngokuphunyezwa kweklasi ye-Functor ye-monad esiyikhethileyo: siya kufuna kuphela ukubeka zonke ii-vertices ukusuka kwindlela eya kwisiphumo esibuyisiweyo ukusuka kumsebenzi wokuphindaphinda.

Umbono wam wokuqala yayikukusebenzisa i-Monad, ebonakala ngathi iphumeza kanye iziphumo esizidingayo. Ukuphunyezwa kokuqala endikubhalileyo kwakukufutshane kakhulu kolu khetho. Ngapha koko, bendinokuphunyezwa okuhlanu okwahlukileyo ngexesha elinye kwaye ekugqibeleni ndahlala kwenye.

Okokuqala, kufuneka sigcine uluhlu oludibeneyo lwezichongi zezabelo - le yinto malunga noMbuso. Okwesibini, kufuneka sikwazi ukuyeka xa kubhaqwe ingxabano. Oku kunokuba yiMonad nokuba Kunye, okanye iMonadPlus mhlawumbi. Umahluko ophambili kukuba Nokuba inokubuyisela ixabiso ukuba ubalo aluzange lumiswe, kwaye Mhlawumbi ubuyisela ulwazi kuphela malunga noku kulo mzekelo. Ekubeni asifuni ixabiso elahlukileyo lokuphumelela (sele ligcinwe kwi-State), sikhetha Mhlawumbi. Kwaye okwangoku xa kufuneka sidibanise imiphumo yeemonads ezimbini, ziphuma ii-monad transformers, edibanisa ngokuchanekileyo le miphumo.

Kwakutheni ukuze ndikhethe uhlobo oluntsonkothileyo? Izizathu ezibini. Okokuqala, ukuphunyezwa kufana kakhulu nomyalelo. Okwesibini, kufuneka sisebenzise ixabiso lokubuyisela kwimeko yongquzulwano xa ubuya umva ukubuyisela i-loop engaqhelekanga, ekulula ukuyenza kwi-Maybe monad.

Ngaloo ndlela sifumana oku kuphunyezwa.

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

Indawo apho ibhloko ingundoqo we-algorithm. Ndiza kuzama ukucacisa okwenzekayo ngaphakathi kuyo.

  • I-inVertex yinxalenye yokukhangela ubunzulu-kokuqala apho sindwendwela i-vertex okokuqala. Apha sabela inombolo yesabelo kwi-vertex kwaye siqhube i-OneEdge kubo bonke abamelwane. Apha kukwalapho sibuyisela khona isitaki sokufowuna: ukuba i-msum ibuyise ixabiso, sityhala i-vertex v apho.
  • I-OneEdge yindawo esindwendwela kuyo umda. Ibizwa kabini kumphetho ngamnye. Apha sijonga ukuba i-vertex kwelinye icala ihanjelwe, kwaye uyindwendwele ukuba akunjalo. Ukuba sityelelwe, sijonga ukuba umphetho uyaphikisana. Ukuba kunjalo, sibuyisela ixabiso - elona xabiso liphezulu le-recursion stack, apho zonke ezinye ii-vertices ziya kubekwa emva koko.
  • processVertex ijonga ivertex nganye ukuba ihanjelwe na kwaye iqhuba kwiVertex kuyo ukuba akunjalo.
  • dfs iqhuba processVertex kuzo zonke ii-vertices.

Kuko konke.

Imbali yegama elithi INLINE

Igama elithi INLINE lalingekho kuphunyezo lokuqala lwe-algorithm; livele kamva. Xa ndizama ukufumana uphumezo olungcono, ndafumanisa ukuba inguqulelo engeyo-INLINE yayicotha ngokubonakalayo kwezinye iigrafu. Ukuthathela ingqalelo ukuba ngokwesemantiki imisebenzi kufuneka isebenze ngokufanayo, oku kwandothusa kakhulu. Nokuba umfokazi, komnye umatshini onenguqu eyahlukileyo ye-GHC kwakungekho mahluko obonakalayo.

Emva kokuchitha iveki ndifunda i-GHC Core output, ndiye ndakwazi ukulungisa ingxaki ngomgca omnye we-INLINE ecacileyo. Ngexesha elithile phakathi kwe-GHC 8.4.4 kunye ne-GHC 8.6.5 i-optimizer iyeka ukwenza oku ngokwayo.

Khange ndilindele ukudibana nokungcola okunjalo kwinkqubo yeHaskell. Nangona kunjalo, nanamhlanje, izilungisi ngamanye amaxesha ziyazenza iimpazamo, kwaye ngumsebenzi wethu ukubanika iingcebiso. Umzekelo, apha siyazi ukuba umsebenzi kufuneka ufakwe emgceni kuba ufakwe emgceni kuguqulelo lomyalelo, kwaye esi sisizathu sokunika umqokeleli ingcebiso.

Kwenzeka ntoni emva koko?

Emva koko ndasebenzisa i-algorithm yeHopcroft-Karp kunye nezinye iimonads, kwaye oko yaba sisiphelo senkqubo.

Ndiyabulela kwiHlobo likaGoogle leKhowudi, ndifumene amava asebenzayo kwiprogram esebenzayo, engandincedanga nje ukuba ndifumane i-internship eJane Street kwihlobo elilandelayo (andiqinisekanga ukuba le ndawo yaziwa kangakanani na phakathi kwabaphulaphuli abanolwazi lukaHabr, kodwa yenye kwabambalwa apho unokuthi ehlotyeni ubandakanyeke kwinkqubo esebenzayo), kodwa wandazisa kwihlabathi elimangalisayo lokusebenzisa le paradigm ekusebenzeni, eyahlukileyo kakhulu kumava am kwiilwimi zesintu.

umthombo: www.habr.com

Yongeza izimvo