Ny fahavaratra lasa teo dia nandray anjara aho
Amin'ny maha mpandray anjara amin'ny Google Summer of Code 2019 dia nanao tetikasa tao anatin'ny tranomboky aho
Ato amin'ity lahatsoratra ity aho dia hiresaka momba ny fampiharana ny algorithm amin'ny fanamarinana ny kisary ho an'ny bipartiteness ao Haskell. Na dia iray amin'ireo fototra indrindra aza ny algorithm, ny fampiharana azy amin'ny fomba tsara tarehy amin'ny fomba fiasa dia nitondra fanamafisam-peo maromaro ary nitaky asa be dia be. Vokatr'izany dia nanorim-ponenana tamin'ny fampiharana miaraka amin'ny transformer monad aho.
Ny tenako
Vasily Alferov no anarako, mpianatra taona fahefatra ao amin'ny HSE St. Petersburg aho. Tany am-boalohany tao amin'ny bilaogy no nanoratako
Momba ny fampiharana ny algorithm
sasin-teny
Ireo mpianatra mandray anjara amin'ny fandaharana dia entanina mafy hanao bilaogy. Nomen'izy ireo sehatra ho an'ny bilaogy aho
Pull Request miaraka amin'ny kaody resahina dia azo jerena
Azonao atao ny mamaky momba ny vokatry ny asako (amin'ny teny anglisy)
Ity lahatsoratra ity dia mihevitra fa ny mpamaky dia mahafantatra ny foto-kevitra fototra amin'ny fandaharana miasa, na dia hiezaka ny hitadidy ny teny rehetra ampiasaina aza aho rehefa tonga ny fotoana.
Fanamarinana ny grafika ho an'ny fizarazarana roa
Ny algorithm amin'ny fanamarinana ny kisary ho an'ny bipartite dia matetika omena amin'ny fampianarana momba ny algorithm ho iray amin'ireo algorithm amin'ny grafika tsotra indrindra. Ny heviny dia mahitsy: aloha isika dia mametraka vertices amin'ny ampahany havia na havanana, ary rehefa hita ny sisiny mifanipaka, dia manamafy isika fa tsy bipartite ny grafika.
Fanazavana fanampiny: apetrakay ny vertex amin'ny ampahany havia. Mazava ho azy fa ny mpifanolo-bodirindrina amin'io vertex io dia tsy maintsy mandry eo amin'ny lobe havanana. Ankoatr'izay, ny mpifanolo-bodirindrina amin'ny mpifanolo-bodirindrina amin'ity vertex ity dia tsy maintsy mandry ao amin'ny lobe havia, sy ny sisa. Manohy manendry ampahany amin'ny vertex izahay raha mbola misy vertex ao amin'ny singa mifandray amin'ny vertex izay natombokay izay tsy nomenay mpifanolo-bodirindrina aminy. Averinay indray ity hetsika ity ho an'ny singa mifandray rehetra.
Raha misy sisiny eo anelanelan'ny vertices izay misaraka amin'ny fizarazarana mitovy, dia tsy sarotra ny mahita tsingerina hafahafa ao amin'ny grafika, izay fantatry ny maro (ary mazava ho azy) tsy azo atao amin'ny kisary bipartite. Raha tsy izany dia manana fizarazarana marina isika, izay midika fa ny grafika dia bipartite.
Amin'ny ankapobeny, ity algorithm ity dia ampiharina amin'ny fampiasana
Noho izany dia tonga tamin'ny drafitra manaraka izahay. Mandalo ny vertices amin'ny grafika amin'ny alΓ lan'ny fikarohana lalina-voalohany izahay ary manome fizarana ho azy ireo, manova ny isan'ny anjara rehefa mandroso amin'ny sisiny. Raha manandrana manendry ampahany amin'ny vertex izay efa manana anjara voatendry isika, dia afaka milaza tsara fa tsy bipartite ny grafika. Rehefa nomena anjara ny vertices rehetra ary nojerentsika ny sisiny rehetra dia manana fizarazarana tsara isika.
Fahadiovan'ny kajy
Ao amin'ny Haskell dia mihevitra isika fa ny kajy rehetra dia madio. Na izany aza, raha izany no zava-misy, dia tsy hanana fomba hanonta na inona na inona amin'ny efijery izahay. Na izany aza, madio malaina ny kajy fa tsy misy MADIO antony hanaovana kajy zavatra. Ny kajikajy rehetra mitranga ao amin'ny programa dia voatery miditra "maloto" monad IO.
Ny Monads dia fomba iray hanehoana ny kajy amin'ny TSY MAHOMBY ao Haskell. Ny fanazavana ny fomba fiasan'izy ireo dia ivelan'ny faritr'ity lahatsoratra ity. Ny famaritana tsara sy mazava dia azo vakiana amin'ny teny anglisy
Eto dia tiako ny manamarika fa raha ny monads sasany, toy ny IO, dia ampiharina amin'ny alalan'ny majika compiler, saika ny hafa rehetra dia ampiharina amin'ny rindrambaiko ary madio avokoa ny kajy ao anatiny.
Betsaka ny effets ary samy manana ny monad ny tsirairay. Tena teoria matanjaka sy tsara tarehy ity: ny monads rehetra dia mampihatra ny interface mitovy. Hiresaka momba ireto monad telo manaraka ireto isika:
- Na ny ea dia kajy izay mamerina ny sandan'ny karazana a na manipy fanavahana karazana e. Ny fitondran-tenan'ity monad ity dia mitovy amin'ny fikarakarana manokana amin'ny fiteny imperative: azo tratrarina na ampitaina ny fahadisoana. Ny fahasamihafana lehibe dia ny hoe ny monad dia ampiharina tanteraka ao amin'ny tranomboky mahazatra ao Haskell, fa ny fiteny imperative dia matetika mampiasa mekanika rafitra miasa.
- State sa dia kajy izay mamerina ny sandan'ny karazana a ary afaka miditra amin'ny toetry ny karazana s.
- Angamba a. Ny Monad Maybe dia maneho kajy izay mety ho tapaka amin'ny fotoana rehetra amin'ny famerenana ny Tsy misy. Na izany aza, hiresaka momba ny fampiharana ny kilasy MonadPlus ho an'ny karazana Mety isika, izay maneho ny fiantraikany mifanohitra amin'izany: kajy izay mety ho tapaka amin'ny fotoana rehetra amin'ny famerenana sanda manokana.
Fampiharana ny algorithm
Manana karazana data roa izahay, Graph a sy Bigraph ab, ny voalohany dia maneho ny grafika misy vertices misy marika amin'ny soatoavin'ny karazana a, ary ny faharoa dia maneho ny bipartite grafika misy vertices ankavia misy marika amin'ny soatoavina karazana a sy havanana. - ireo vertices amin'ny sisiny misy marika karazana b.
Tsy karazana avy amin'ny tranomboky Alga ireo. Alga dia tsy manana solontena ho an'ny sarin'ny roa tonta. Nanao karazana toy izao aho mba hazava.
Mila asa mpanampy miaraka amin'ireto sonia manaraka ireto koa izahay:
-- Π‘ΠΏΠΈΡΠΎΠΊ ΡΠΎΡΠ΅Π΄Π΅ΠΉ Π΄Π°Π½Π½ΠΎΠΉ Π²Π΅ΡΡΠΈΠ½Ρ.
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)
Mora ny mahita fa raha nandritra ny fikarohana lalina-voalohany dia nahita sisiny mifanipaka isika, ny tsingerina hafahafa dia mipetraka eo an-tampon'ny stack recursion. Noho izany, mba hamerenana azy io, dia mila manapaka ny zava-drehetra manomboka amin'ny fitambaran'ny recursion ka hatramin'ny fisehoana voalohany amin'ny vertex farany.
Manatanteraka fikarohana lalina-voalohany izahay amin'ny alΓ lan'ny fikojakojana ny laharan'ny fizarana iombonana ho an'ny vertex tsirairay. Ny stack recursion dia hotazonina ho azy amin'ny alΓ lan'ny fampiharana ny kilasy Functor amin'ny monad nofidianay: tsy maintsy mametraka ny vertices rehetra avy amin'ny lalana mankany amin'ny valiny miverina avy amin'ny asa recursive fotsiny isika.
Ny hevitro voalohany dia ny fampiasana ny Either monad, izay toa mampihatra tsara ny vokatra ilaintsika. Ny fampiharana voalohany nosoratako dia tena akaiky an'io safidy io. Raha ny marina, nanana fampiharana dimy samihafa aho tamin'ny fotoana iray ary niorina tamin'ny iray hafa.
Voalohany, mila mitazona andiana mpizara mpizara isika - zavatra momba ny Fanjakana izany. Faharoa, mila afaka mijanona isika rehefa misy fifandirana hita. Ity dia mety ho Monad ho an'ny Either, na MonadPlus for Maybe. Ny tena maha samy hafa dia ny hoe Na afaka mamerina sanda iray raha toa ka tsy nijanona ny kajy, ary Angamba tsy mamerina afa-tsy vaovao momba izany amin'ity tranga ity. Koa satria tsy mila sanda mitokana ho an'ny fahombiazana (efa voatahiry ao amin'ny Fanjakana izany), dia misafidy angamba isika. Ary amin'izao fotoana izao rehefa mila manambatra ny fiantraikan'ny monads roa isika dia mivoaka izy ireo
Nahoana aho no nifidy karazana sarotra toy izany? Antony roa. Voalohany, ny fampiharana dia mitovitovy amin'ny imperative. Faharoa, mila manodinkodina ny sandan'ny fiverenana isika raha misy fifandirana rehefa miverina avy amin'ny fiverenana mba hamerenana amin'ny laoniny ny loop hafahafa, izay mora kokoa ny manao ao amin'ny Monad.
Noho izany dia mahazo izany fampiharana izany isika.
{-# 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)
Ny hoe block no fototry ny algorithm. Hiezaka aho hanazava ny zava-mitranga ao anatiny.
- inVertex dia ampahany amin'ny fikarohana lalina izay hitsidihantsika voalohany ny vertex. Eto izahay dia manome laharana fizarana amin'ny vertex ary mihazakazaka onEdge amin'ny mpifanolo-bodirindrina rehetra. Eo ihany koa no hamerenanay ny antso an-tariby: raha namerina sanda iray i msum, dia manosika ny vertex v any izahay.
- onEdge no ampahany hitsidihanay ny sisiny. Antsoina indroa isaky ny sisiny. Eto isika dia manamarina raha efa voatsidika ny vertex amin'ny ilany iray, ary tsidiho izany raha tsy izany. Raha tsidihina dia jereo raha mifanipaka ny sisiny. Raha izany no izy dia averinay ny sandany - ny tampony indrindra amin'ny stack recursion, izay hapetraka ny vertices hafa rehetra rehefa miverina.
- processVertex manamarina ny vertex tsirairay raha efa notsidihina ary mandeha amin'ny inVertex raha tsy izany.
- dfs dia mihazakazaka processVertex amin'ny vertex rehetra.
Izay ihany.
Ny tantaran'ny teny INLINE
Ny teny hoe INLINE dia tsy tao amin'ny fampiharana voalohany ny algorithm; niseho taty aoriana. Rehefa nanandrana nitady fampiharana tsara kokoa aho, dia hitako fa somary miadana kokoa ny dikan-teny tsy INLINE amin'ny grafika sasany. Raha jerena fa tokony hiasa mitovy amin'ny semantically ny asa, dia tena nahagaga ahy izany. Na dia vahiny aza, amin'ny milina hafa miaraka amin'ny dikan-teny GHC hafa dia tsy misy fahasamihafana hita maso.
Rehefa avy nandany herinandro namaky ny famoahana ny GHC Core aho dia afaka namaha ny olana tamin'ny andalana INLINE mazava. Tamin'ny fotoana iray teo anelanelan'ny GHC 8.4.4 sy GHC 8.6.5 dia nijanona tsy nanao izany irery ny optimizer.
Tsy nanantena ny hahita loto toy izany aho amin'ny fandaharana Haskell. Na izany aza, na dia amin'izao fotoana izao aza, manao fahadisoana indraindray ny optimizers, ary anjarantsika ny manome azy ireo torohevitra. Ohatra, eto isika dia mahafantatra fa ny asa dia tokony ho inlined satria inlined ao amin'ny dikan-imperative, ary izany no antony hanome ny compiler soso-kevitra.
Inona no nitranga taorianβizay?
Avy eo dia nampihatra ny algorithm Hopcroft-Karp niaraka tamin'ny monad hafa aho, ary izay no niafaran'ny fandaharana.
Noho ny Google Summer of Code, dia nahazo traikefa azo ampiharina amin'ny fandaharana miasa aho, izay tsy vitan'ny hoe nanampy ahy hahazo internship tao amin'ny Jane Street ny fahavaratra manaraka (tsy azoko antoka fa tena fantatry ny mpihaino an'i Habr ity toerana ity, fa iray ihany izy io. amin'ireo vitsy azonao atao mandritra ny fahavaratra mba hirotsaka amin'ny fandaharana miasa), fa nampahafantatra ahy ihany koa ny tontolo mahafinaritra amin'ny fampiharana ity paradigma ity amin'ny fampiharana, tsy mitovy amin'ny traikefako amin'ny fiteny nentim-paharazana.
Source: www.habr.com