në shtëpi » përpunimi i kërpudhave » Algoritmet gjenetike kërkojnë një zgjidhje. Zbatimi i algoritmeve gjenetike

Algoritmet gjenetike kërkojnë një zgjidhje. Zbatimi i algoritmeve gjenetike

Ai dha një zbrazëti fisnike. Megjithatë, niveli i pamjaftueshëm *censuruar* e shtyu datën e botimit dhe vetëm tani, pas një lutjeje të turpshme të lodhshme nga ana ime, ky artikull pati mundësinë të tregohej para botës. Gjatë kësaj periudhe kohore janë botuar të paktën tre (aq sa kam hasur) artikuj mbi një temë të ngjashme dhe ka gjasa që ju të mos lexoni diçka të shkruar më poshtë për herë të parë. Për njerëz të tillë, unë sugjeroj të mos vrenjten në një përpjekje tjetër të një të riu të papërvojë për të shpjeguar GA në një mënyrë popullore shkencore, por të shkojnë në ekspozitën tjetër në pjesën e dytë, e cila përshkruan krijimin e një roboti të bazuar në GA për Robokodin. lojë programimi. Kjo, sipas informacioneve të fundit të inteligjencës, ende nuk është përmbushur në Habré.

Pjesa e pare. Jeta dhe puna e algoritmit gjenetik.

Le të fillojmë nga larg. Ekziston një grup i caktuar problemesh që duhet të zgjidhen. Qëllimi ynë është të gjejmë veprime që mund të transformohen E dhënë(kushtet fillestare të problemeve) në Përgjigju(gjendja e synuar).

Nëse situata është e thjeshtë, dhe zgjidhja e një problemi të tillë mund të llogaritet qartë nga kushtet me ndihmën e këtyre matanëve tuaj, atëherë është mirë, këtu gjithçka është në rregull edhe pa hilet tona, u dreqëm, të gjithë u shpërndamë. Për shembull, kur zgjidhet një ekuacion kuadratik, përgjigja (vlerat x1, x2) merret nga kushti fillestar (koeficientët a, b, c) duke zbatuar formulën që kemi mësuar të gjithë në shkollë. Dhe çfarë të bëni në një rast më të trishtuar, kur nuk ka formulë të nevojshme në tekst? Ju mund të provoni stuhi mendimesh për të zgjidhur një nga problemet. Në mënyrë analitike. Metodat numerike. Nga forca e një numërimi të dëshpëruar funksionesh. Pas pak, do të dëgjoni studentin ëndërrimtar "nëse do të zgjidhej vetë". Po, ja ku dalim nga pas perdeve. Pra, qëllimi është të shkruhet një program që do të gjente një funksion (program) që merr të dhënat fillestare si hyrje dhe kthen numra të vlefshëm. Fuqia e metaprogramimit, në betejë!

Hmm, si do ta arrijmë një qëllim të tillë? Le të bëjmë një sakrificë për perënditë e rekursionit rreth zjarrit: shkruani një program që do të shkruajë një program që do të gjente një funksion (program) ... Jo, kjo nuk do të funksionojë herën e dytë. Më mirë të marrim një shembull nga natyra, duke hedhur sytë mbi fenomene të tilla si mekanizmi i evolucionit, seleksionimi natyror. Gjithçka është si në jetë: programet tona do të jetojnë, çiftëzohen, lindin dhe vdesin nën zgjedhën e individëve më të përshtatur, duke ua përcjellë cilësitë e tyre më të mira pasardhësve të tyre. Tingëllon e çmendur, por ia vlen të shikohet.

Zoti i botës sonë të softuerit është detyra jonë. Programet duhet të besojnë tek ajo, të bashkohen për të, të vendosin qirinj në kishë për nder të saj dhe të jetojnë me qëllimin e vetëm për të gjetur kuptimin e jetës dhe për të zgjidhur këtë problem. Ai që është më i përshtatur me mjedisin (ai që i afrohet zgjidhjes së problemit) bëhet mashkull alfa, mbijeton dhe jep pasardhës të fortë. Një humbës që e kaloi gjithë jetën e tij duke luajtur lojëra në internet dhe nuk e dinte suksesin në zgjidhjen e një problemi, ka shanse shumë të vogla për të dhënë pasardhës. Pishina e gjeneve do të pastrohet nga kontributi i këtyre shokëve puçërr dhe e gjithë shoqëria e programeve do të ecë drejt një të ardhmeje më të ndritur për problemin e zgjidhur. Epo, në terma të përgjithshëm tashmë është e qartë, tani duhet të merreni me nuancat: së pari, si i imagjinoni programet e çiftimit? së dyti, nga do ta marrim gjeneratën e parë të programeve? së treti, mbi çfarë baze do të përcaktojmë aftësinë fizike të individëve dhe si do të ndikojë në kalimin? së katërti, ia vlen të vendosni për kushtet për përfundimin e algoritmit, kur të ndaloni gjithë këtë orgji.

Arti i çiftimit të softuerit

Unë mendoj se shumë prej nesh ndonjëherë kanë një dëshirë të zjarrtë për programe të sulmeve seksuale. Këtu jemi të detyruar të paralajmërojmë paraprakisht se devijime të tilla ndërspeciale nuk inkurajohen në vendin tonë. Ne kemi gjithçka siç ka lënë amanet Kisha Katolike: një program me program, vetëm pas martesës ... dhe partnerët nuk ndryshojnë, edhe nëse ai djaloshi i lodhur të ka blerë një koktej në bar. Edhe pse jo, po gënjej, po lulëzon poligamia e tipit harem. Po, dhe megjithatë, pavarësisht përdorimit të fjalëve të tilla si "babai" ose "biri" më poshtë, programet tona janë hermafroditë. Epo, edhe inçesti… Uh, dhe fola edhe për kishën *facepalm*. Mirë, më shumë për këtë më vonë.

Çështja e kryqëzimit të programeve nuk është aq e thjeshtë. Një shkëmbim aksidental i funksioneve, vargjeve ose variablave do të rezultojë në një rrjedhë të trashë fjalësh të frikshme që ju drejtohen nga përpiluesi / interpretuesi dhe jo një program i ri. Kjo do të thotë, është e nevojshme të gjendet një mënyrë për të kryqëzuar programet saktë. Xhaxhallarët e zgjuar gjetën një rrugëdalje. Dhe djemtë dhe vajzat e zgjuar që studiuan strukturën e përpiluesve gjithashtu kanë hamendësuar tashmë. Po, po, kjo është një pemë sintakse.

Do ta zbut menjëherë aromën time: mjekra jonë nuk është ende shumë e trashë, kështu që do të përdorim llojet më të thjeshta të programeve. Ata që dëshirojnë mund të shkojnë në luginën e pasurisë së patreguar të programimit, por gjithçka është e thjeshtë për ne - programi përbëhet nga shprehje, të cilat nga ana e tyre përbëhen nga funksione të thjeshta me disa vlera, variabla dhe konstante. Çdo shprehje numëron një nga vlerat e kthyera nga programi.

Për shembull: një program individual katror i dy shprehjeve, duke u përpjekur (jo shumë me sukses) të zgjidhë një ekuacion kuadratik:
funksioni katror(a, b, c)( x1 = min(sin(b)*(a+1), 0); x2 = 3 + exp(log(b*a)); kthimi (x1, x2); )
Ne kemi vendosur për prezantimin, tani duhet të merremi me ruajtjen. Meqenëse ka ende shumë vallëzime rreth këtyre programeve, duke përfshirë transferimin e tyre nga një pjesë e sistemit në tjetrin (të cilat, në përgjithësi, në rastin tim janë shkruar përgjithësisht në gjuhë të ndryshme), atëherë ruajtja e individit tonë në formën e një peme është jo shumë i përshtatshëm. Për ta përfaqësuar atë në një mënyrë më të përshtatshme (në mënyrë ideale, një grup vargjesh mbi një alfabet të fundëm), grupi_e_pemëve-programeve tona individuale do të duhet të mësojnë se si të kodojnë / deshifrojnë.

Duket si një pemë, por nuk është
Pra, ne duhet të përfaqësojmë pemën si një varg. Këtu fuqia e pemëve karva do të na ndihmojë. Për të filluar, ia vlen të vendosni për një grup funksionesh, variablash dhe konstante që mund të gjenden në pemë. Variablat dhe konstantat korrespondojnë me gjethet e pemës dhe do të quhen terminale, funksionet - për nyjet e mbetura (të brendshme) të pemës, quhen jo-terminale. Vlen gjithashtu t'i kushtohet vëmendje faktit që funksionet mund të kenë një numër të ndryshëm argumentesh, prandaj, do të na duhet vërtet një njohuri e tillë ("arnost", - fjala u përshkoi qetësisht mbi buzët e ekspertëve). Rezultati është një tabelë kodimi, për shembull, kjo:

Këtu n, +, *, nëse janë funksione; 2 - konstante; a dhe b janë variabla. Në problemet reale, tabela është më e rëndë, me një grup të tillë dhe ekuacioni kuadratik nuk mund të zgjidhet. Ju gjithashtu duhet të mbani parasysh faktin se për të shmangur ndarjen me zero dhe skenarë të tjerë të apokalipsit, të gjitha funksionet duhet të përcaktohen në të gjithë grupin e numrave realë (mirë, ose çfarëdo grupi që përdorni në detyrë). Përndryshe, do t'ju duhet të uleni në roje, të kapni logaritmet nga zero dhe më pas të kuptoni se çfarë të bëni me të. Ne nuk jemi njerëz krenarë, do të shkojmë në rrugën e lehtë, duke përjashtuar opsione të tilla.

Pra, me ndihmën e një tabele të tillë, ndjekja e funksioneve nga një pemë në një vijë dhe mbrapa nuk është problem. Për shembull, kemi marrë vargun e mëposhtëm për deshifrim:

Ne identifikojmë secilin element sipas tabelës, kujtojmë gjithashtu për aritjen:

Tani, duke përdorur arity, vendosim lidhje me argumentet e funksionit:

Ju lutemi kushtojini vëmendje faktit që 3 elementët e fundit të listës rezultuan të padobishëm për askënd dhe vlerat e tyre nuk ndikojnë në asnjë mënyrë rezultatin e funksionit. Kjo ndodhi për shkak të faktit se numri i elementeve të listës së përfshirë, numri i nyjeve të pemëve noton vazhdimisht në varësi të karakteristikave të tyre. Pra, është më mirë të grumbulloheni sesa të vuani me një pemë të gabuar më vonë.

Tani, nëse e tërheqim atë me elementin e parë, atëherë do të kemi një pemë shprehjeje të varur në dorë:

Vlera e funksionit mund të llogaritet me kalimin rekurziv të pemës, e kemi kështu:

Sytë i kam nga babai im
Ne kthehemi në më të nxehtin - në kalim. Ne vendosëm kushtet e mëposhtme për operacionet e kryqëzimit të programit: së pari, dy individë të kryqëzuar japin dy pasardhës (dmth. madhësia e popullsisë është konstante); së dyti, si rezultat i kryqëzimit, pasardhësit duhet, në një masë të caktuar, të kenë karakteristikat e të dy prindërve (d.m.th., molla nuk duhet të rrotullohet shumë larg pemës së mollës). Tani kemi mësuar se si do të përfaqësohet programi - është një grup vargjesh apo pemësh. Prandaj, ato mund të kryqëzohen si vargje ose si pemë.

Kryqëzimi i pemëve është shkëmbimi i degëve të zgjedhura rastësisht. Kryqëzimi i vargjeve mund të zbatohet në disa mënyra: rikombinim me një pikë (ngjitje pjesë-pjesë), rikombinim me dy pika, shkëmbim element pas elementi, etj. Ato mund të përshkruhen me fjali të gjata komplekse me fraza ndajfoljore, por një vështrim në diagram. mjafton për të kuptuar se çfarë është:

Vlen të përmendet vetëm se vendet e ngjitjes në rikombinim zgjidhen në mënyrë të rastësishme, ashtu si në kryqëzimin element pas elementi, shkëmbimi bëhet me një probabilitet të caktuar. Kryqëzimi i pemëve për sa i përket trashëgimisë duket më premtues, por është më i vështirë për t'u zbatuar.

Hej, kjo vajzë është me mua!

Jemi trajtuar me pjesën më intime të procesit (shumë prej tyre e kanë ndjerë tashmë përmes këtij artikulli se sa e varfër është jeta personale e autorit). Tani le të kalojmë nga marrëdhënia midis një çifti individësh në themelet shoqërore.

Individët ndahen në breza. Brezi i ri përbëhet nga fëmijët e gjeneratës së mëparshme. Rezulton se ekziston brezi aktual i djemve dhe vajzave, brezi i baballarëve dhe nënave, gjyshërve, stërgjysheve, e kështu me radhë deri në brezin zero - paraardhësit e të gjithë njerëzve krenarë. Çdo individ i gjeneratës së re pas lindjes përpiqet të zgjidhë problemin, veprimet e tij vlerësohen nga një funksion hyjnor fitnesi dhe në varësi të vlerësimit të tij për aktivitetin e të riut, individi merr disa shanse për të riprodhuar pasardhës, domethënë për të rënë në klasa e përfaqësuesve më të mirë të brezit të zgjedhur për riprodhim. Bota jonë është e ashpër dhe mizore, dhe sipas të gjitha kanuneve të distopive (ose sipas ideve të Fuhrer-it, sipas dëshirës tuaj), prindërit pensionistë të padobishëm, pasi kryejnë misionin e tyre për të pasur pasardhës, shkojnë në një udhëtim me një vagon gazi. , duke liruar hapësirën e jetesës për një çift prej fëmijëve të tyre. Fëmijët ndjekin gjurmët e prindërve të tyre dhe kështu brez pas brezi.

I njëjti funksion fitnesi (ose funksioni i fitnesit) që lëshon kuotat e çiftëzimit duhet të vlerësojë në mënyrë adekuate aftësinë e një individi për të zgjidhur një problem dhe të japë një shprehje numerike të kësaj përshtatshmërie (sa më e madhe të jetë vlera, aq më e mirë fitnesi). Për shembull, në rastin e të njëjtit ekuacion kuadratik, kjo mund të jetë një masë se sa afër zeros është vlera e anës së majtë të ekuacionit me vlerat e zëvendësuara x1, x2 të llogaritura nga programi individual.

Funksioni i fitnesit i jep çdo individi të gjeneratës një numër të caktuar që tregon dobinë e tij, fitnesin. Kjo vlerë do të ndikojë në procedurën e përzgjedhjes (përzgjedhjes): sa më e madhe të jetë kjo vlerë për një individ, aq më shumë ka të ngjarë të gjejë një palë për kryqëzim (dhe madje më shumë se një). Në praktikë, pas llogaritjes së përshtatshmërisë për të gjithë individët e një brezi, ne i normalizojmë këto vlera (në mënyrë që shuma e përshtatshmërisë së individëve të jetë e barabartë me 1) dhe për secilin nga vendet e puthjes hidhet shumë (një numër i rastësishëm nga 0 në 1), që përcakton fatin. Mashkulli alfa mund të marrë disa vende, humbësi nuk merr asgjë dhe do të mbetet vetëm me një kalendar të shkretë të vitit 1994 me Pamelën. Kjo metodë e përzgjedhjes quhet "zgjedhja e ruletës" dhe në mënyrë skematike duket diçka si kjo:

Ka metoda të tjera përzgjedhjeje, por të gjitha ato i përmbahen rregullit të përgjithshëm: sa më shumë palestër të ketë një individ, aq më shumë duhet të marrë pjesë në kalim. Gjithashtu, procesi mund të përfshijë opsionin e elitizmit, kur përfaqësuesi më i mirë i brezit merr një çmim në formën e viteve shtesë të jetës për shërbime ndaj Atdheut: ai kalon në brezin e ardhshëm pa ndryshime, megjithëse mund të bëjë fëmijë në paralele. Kjo na lejon të mos humbasim një zgjidhje shumë të mirë, e cila mund të shkatërrohet gjatë kalimit.

Këtu përmendim edhe mutacionin. Ky operacion ndryshon rastësisht një fragment të një individi me një probabilitet të vogël, gjë që lejon diversifikimin e grupit të gjeneve. Një gjë e dobishme, papritmas një mutacion i tillë do të ndihmojë në zbërthimin e laktozës! Dhe nëse jo, dhe një dorë tjetër është e tepërt, atëherë vuani me të deri në fund të ditëve tuaja, dhënia e pasardhësve nuk është ende një shans i mjaftueshëm.

Krijimi i botës dhe Apokalipsi

Ne zbuluam se si të kalojmë brez pas brezi, tani pyetja tjetër është "cila ishte shkaku kryesor, si filloi gjithçka?". Ndryshe nga kjo botë juaja, ne nuk kemi pse të nxjerrim truke si “big bang” apo “7 ditë” për të shpjeguar gjëra të tilla. Këtu përgjigja është jashtëzakonisht e qartë - gjithçka filloi me gjeneratën zero, e cila u krijua rastësisht. Po, po, ne thjesht gjenerojmë në mënyrë të rastësishme vargje / pemë. Kërkesa e vetme është korrektësia e individit dhe askujt nuk i intereson se sa me të meta është, përzgjedhja do të bëjë punën e saj.

Bota jonë ekziston për aq kohë sa kemi nevojë. Ne ose vendosim shiritin për fitnesin që na kënaq dhe kur shfaqet një individ mjaft i ftohtë, ne e ndalojmë procesin, ose kontrollojmë se sa ndryshojnë individët e një brezi nga njëri-tjetri. Është logjike që nëse i gjithë brezi përbëhet nga binjakë identikë, atëherë çiftëzimi i mëtejshëm eksiton nuk do t'i japë asgjë të re grupit të gjeneve, dhe është naive të shpresojmë për një mutacion. Ju gjithashtu mund të vendosni një kufi kohor.

Hej, ti! Haroshsh fluturo trurin! Cili është rezultati përfundimtar?

Le të ndalemi në këtë folje magjepsëse dhe të shohim prapa (mirë, lart). Për ta përmbledhur, algoritmi gjenetik duket si ky:

Ne mësojmë të paraqesim zgjidhjen e një problemi si një shembull i një algoritmi gjenetik - një listë me gjatësi fikse mbi një alfabet. Pas kësaj, ne zgjedhim një funksion fitnesi që mund të vlerësojë individët dhe të gjenerojë rastësisht gjeneratën zero. Këtu fillon cikli i dashurisë së lirë: llogaritet fitnesi i individëve të gjeneratës, sipas këtyre të dhënave formohen çifte (humbësit hidhen jashtë dhe meshkujt alfa nuk kufizohen në një palë), pjesa tjetër çiftëzohet, lindë nja dy fëmijë (për të cilët është zbatuar edhe mutacioni) dhe vendosin duart mbi veten e tyre. Kjo vazhdon derisa të gjendet i zgjedhuri, ose ndryshimet pushojnë së na kënaqur, ose jemi të lodhur nga e gjithë kjo. Epo, si mund të bëj pa një skemë:

Pjesa e dyte. Roli i algoritmit gjenetik në imazhin e robotit Robocode.

Diçka që pjesa e parë u zvarrit, të gjithë jemi të lodhur, ndaj nuk do ta përsërisim veten. Ne gjithashtu heqim disa veçori të zbatimit.
Mund të zbuloni se çfarë është Robocode këtu: habrahabr.ru/blogs/programmers_games/59784 (fotografitë janë humbur megjithatë). Me pak fjalë - kjo lojë programimi, e krijuar fillimisht për të mësuar tiparet e gjuhës Java, e cila u lejon pjesëmarrësve të krijojnë robotët e tyre dhe të organizojnë zënka midis tyre. Secili pjesëmarrës shkruan kodin Java që kontrollon një tank të vogël dhe lufton tanke të tjerë të ngjashëm.

Ne përballemi me detyrën e mëposhtme: zhvillimin e një sistemi të automatizuar kontrolli për një bot-tank duke përdorur një algoritëm gjenetik. Roboti duhet të krijohet dhe modifikohet automatikisht, d.m.th. në rrjedhën e evolucionit të tij, "përshtatuni" me një kundërshtar specifik dhe të parazgjedhur në betejat 1v1.

Si të përfaqësohet zgjidhja e problemit në formën e një individi

Së pari, le të përcaktojmë aftësitë e rezervuarit. Lista e veprimeve themelore që një robot mund të kryejë gjatë një beteje është e kufizuar në katër pika: rrotulloni armën, ktheni trupin, gjuani, lëvizni. Ne e përjashtuam veprimin e pestë, rrotullimin e radarit, nga shqyrtimi, duke e zbatuar atë në një rrotullim të parëndësishëm - të vazhdueshëm (kështu, tanku do të ketë gjithmonë informacione të përditësuara për pozicionin e armikut).

Natyrisht, për një luftim të suksesshëm, këto veprime nuk duhet të kryhen rastësisht, por duhet të varen nga situata (gjendja) në fushën e betejës: nga pozicioni i tankeve, shpejtësia e tyre, energjia dhe parametrat e tjerë. Kështu, procesi i kontrollit të një tanku reduktohet në kryerjen e veprimeve të mësipërme bazuar në gjendjen e betejës. Ligji që përcakton sjelljen e tankut (veprimet e tij) bazuar në situatën në fushën e betejës, ne do ta quajmë funksionin e kontrollit, dhe ai do të jetë individi i algoritmit tonë gjenetik.

Meqenëse funksioni i kontrollit duhet të kthejë 4 vlera (energjia e goditjes, këndi i kalimit të frëngjisë, këndi i kalimit të bykut, lëvizja e rezervuarit), atëherë, siç shpjegohet në pjesën e fundit, ai do të përbëhet nga katër shprehje, d.m.th. me katër rreshta/pemë.

Për të përpiluar një tabelë kodimi, duhet të vendosni për një grup funksionesh bazë, variabla dhe konstante.

Funksione:
+(x, y) = x + y
++(x, y, z) = x + y + z
n(x) = -x
*(x, y) = x * y
**(x, y) = x * y * z
min(x, y) = x > y? y:x
s(x) = 1/(1+exp(-x))
nëse(x, y, z, w) = x > y? z:w

Variablat:
x, y - koordinatat e rezervuarit të kundërshtarit në lidhje me tankun tonë;
dr - distanca e mbetur për të "arritur" tankin tonë;
tr - këndi i mbetur për rrotullimin e rezervuarit tonë;
w është distanca nga rezervuari ynë deri në skajin e fushës;
dh - këndi ndërmjet drejtimit të tankut të kundërshtarit dhe topit të tankut tonë;
GH - këndi i rrotullimit të armës së rezervuarit tonë;
h - drejtimi i lëvizjes së tankut të kundërshtarit;
d është distanca midis tankut tonë dhe tankut të kundërshtarit;
e - energjia e rezervuarit të kundërshtarit;
E është energjia e rezervuarit tonë.

Epo, konstantet: 0,5, 0, 1, 2, 10

funksioni i fitnesit

Le të përshkruajmë se si u zgjodh funksioni i fitnesit. Rezultatet e betejës "Robocode" formohen në bazë të shumë nuancave. Ky nuk është vetëm numri i fitoreve, por edhe të gjitha llojet e pikëve për aktivitet, për mbijetesë, për të goditur një kundërshtar, etj. Si rezultat, "Robocode" i rendit robotët sipas parametrit "pikat totale", i cili merr parasysh të gjitha hollësitë e përshkruara më sipër. Ne do ta përdorim atë gjatë llogaritjes së përshtatshmërisë së një individi: përshtatshmëria përfundimtare do të jetë e barabartë me përqindjen e pikëve të rezervuarit tonë nga shuma e pikëve të të dy tankeve dhe merr një vlerë nga 0 në 100. Prandaj, nëse vlera e fitnesit është më i madh se 50, atëherë roboti ynë shënoi më shumë pikë se kundërshtari është pra më i fortë se ai. Vini re se sipas një sistemi të tillë numërimi, vendin e parë nuk e zë gjithmonë ai që fitoi më shumë raunde të betejës. Epo, këtu ngremë supet me frazën për skuterin: krijuesit i kanë përcaktuar kriteret, ne i ndjekim.

Në përgjithësi, llogaritja e aftësisë fizike të një individi përfshin një sërë grindjesh! Ato. një pikë e tillë në dukje e parëndësishme si një llogaritje e gabuar e fitnesit përbëhet nga vallëzime të tilla me një dajre:
1) Sistemi ynë ruan kromozomet e koduara të një individi në skedarin chromosome.dat;
2) Për çdo individ lançohet ambienti Robocode, i cili organizon duelin. Ne i japim atij një skedar të formatit .battle që përshkruan kushtet e betejës - një listë me tanke luftarake, madhësitë e fushës, numrin e raundeve, e kështu me radhë;
3) Për betejë, Robocode ngarkon tanke, roboti ynë guaskë lexon skedarin chromosome.dat me sjellje të koduar, e interpreton atë në një grup veprimesh dhe lufton sipas tyre;
4) Në fund të duelit, mjedisi Robocode shkruan rezultatin e betejës në skedarin results.txt dhe përfundon punën e tij për këtë;
5) Sistemi ynë zgjedh këtë skedar, analizon dhe nxjerr prej tij vlerat e rezultatit total të rezervuarit tonë dhe kundërshtarit. Me aritmetikë të thjeshtë, marrim vlerën e përshtatshmërisë.

Si janë tanët, apo jo?

Le të përmbledhim rezultatet e byrosë sonë të projektimit. Sistemi ynë përbëhet nga dy pjesë (programe). E para prej tyre, bazuar në një algoritëm gjenetik, mbledh një individ dhe e ruan atë si një grup vargjesh, dhe i dyti (kodi i robotit) e interpreton atë (duke e përpunuar atë në një pemë shprehjeje) dhe kontrollon rezervuarin (duke llogaritur vlerën e shprehjes pemët me kalim rekurziv për variablat e dhëna, domethënë beteja aktuale e gjendjes). Programi i parë është i shkruar në gjuhën C, i dyti është shkruar në gjuhën Java.

Gjatë zbatimit të algoritmit gjenetik, numri i individëve në popullatë u zgjodh të ishte 51 (25 çifte + një individ elitar). Një hap i evolucionit (ndryshimi i popullsisë) zgjat rreth një duzinë minuta, prandaj, në total, çështja zvarritet për disa orë.

Si rezultat, ne do të demonstrojmë rezultatet e krijimit të një kundërshtari për robotët Walls dhe Crazy:




Në rastin e parë e kemi ndërprerë procesin pasi njëri prej individëve ka arritur pragun e fitnesit 70, në rastin e dytë na ka mjaftuar që mesatarja e fitnesit të individëve të brezit të kalojë 50.

Shpëlajini sytë me alkool pas meditimit

Nëse dikush nuk ka frikë të qajë lot të përgjakshëm në konvulsione nga soditja e bllokimit (sidomos flokët do të fillojnë të lëvizin nga kodi i robotit - ne kemi urrejtje të ndërsjellë me java), atëherë bashkangjit

Një nga detyrat e sistemeve inteligjente është gjetja e zgjidhjes optimale: kur një sistem ndikohet nga shumë faktorë të jashtëm dhe të brendshëm, një pajisje inteligjente duhet t'i marrë parasysh të gjitha dhe të zgjedhë sjelljen optimale nga pikëpamja e përfitimit të saj. Për shembull, nëse jeni pronar i një magazine, duhet të merrni parasysh shumë faktorë (kostoja e njësive të mallrave, kërkesa, kostoja e ruajtjes së mallrave të ndryshme në një magazinë etj.) për të minimizuar kostot dhe për të maksimizuar fitimet.

Një shembull tjetër: jeni duke vozitur në një rrugë të rrëshqitshme dhe papritmas makina juaj fillon të rrëshqasë, një shtyllë është në të djathtën tuaj disa metra larg dhe një kamion po lëviz në korsinë e ardhshme. Vëmendje në pyetjen: si të dilni nga situata me më pak humbje, dhe është më mirë pa to fare. Ka shumë faktorë për t'u marrë parasysh: shpejtësia juaj dhe shpejtësia e makinës që po afrohet, distanca deri në shtyllë, "ftohtësia" e rrëshqitjes, etj. Çfarë duhet të bëjmë? Hapni gazin, duke u përpjekur të dilni nga rrëshqitja, ose frenoni, ose ndoshta përpiquni të futeni me kujdes në hendek në mënyrë që të mos goditni shtyllën. Ka shumë opsione, dhe për të përcaktuar atë optimale, duhet t'i provoni të gjitha. Nëse do të ishte një lojë kompjuterike, mund të ruani dhe të riluani derisa të jeni të kënaqur me rezultatin. Ky është kërkimi i zgjidhjes optimale.

Në sistemet e inteligjencës artificiale, ato përdoren për të zgjidhur probleme të tilla.

Algoritmet gjenetike– metodat adaptive të kërkimit që përdoren për të zgjidhur problemet e optimizimit funksional. Ato bazohen në mekanizmat dhe modelet e evolucionit, dhe proceset gjenetike të algoritmeve biologjike.

Le ta themi thjesht: në fakt, një algoritëm gjenetik është një metodë e numërimit të zgjidhjeve për ato probleme në të cilat është e pamundur të gjendet një zgjidhje duke përdorur formula matematikore. Megjithatë, një numërim i thjeshtë i zgjidhjeve në një problem kompleks shumëdimensional është pafundësisht i gjatë. Prandaj, algoritmi gjenetik nuk kalon nëpër të gjitha zgjidhjet, por vetëm ato më të mirat. Algoritmi merr një grup zgjidhjesh dhe kërkon më të përshtatshmet prej tyre. Pastaj ai i ndryshon pak - ai merr zgjidhje të reja, ndër të cilat ai përsëri zgjedh më të mirët dhe hedh poshtë ato më të këqijat. Kështu, në çdo hap të punës, algoritmi zgjedh zgjidhjet më të përshtatshme (kryen përzgjedhjen), duke besuar se ato do të japin zgjidhje edhe më të mira në hapin tjetër (evoluojnë).

Po biologjia?

Siç e keni kuptuar tashmë, në teorinë e algoritmeve gjenetike, bëhet një analogji midis një detyre dhe një procesi biologjik. Prandaj terminologjia...

Individual- një zgjidhje për problemin.

popullatëështë një grup zgjidhjesh problematike. Në fillim të algoritmit, një grup zgjidhjesh (popullata fillestare) krijohet rastësisht. Këto zgjidhje do të bëhen më të mira (evoluojnë) gjatë rrjedhës së algoritmit derisa të plotësojnë kushtet e problemit.

Dhe menjëherë shembulli më i thjeshtë klasik. Le të themi se roboti duhet të kalojë rreth gjashtë pikave të kontrollit në kohën më të shkurtër. Distanca nga çdo pikë në secilën është dhënë si matricë e distancës.

Ky është një variant i problemit të shitësit udhëtues (udhëtar) - i përket klasës së atyre të kompletuara NP, me fjalë të tjera, nuk mund të zgjidhet duke përdorur formula matematikore.

Zgjidhja e problemit është një sekuencë e kalimit të pikave të kontrollit. Le të marrim disa zgjidhje të mundshme (individë) - kjo është .

Përkufizimet e cilësisë së vendimit

Funksioni i fitnesitështë një funksion që përcakton cilësinë e individëve në një popullsi. Në shembullin tonë, kjo do të jetë shuma e distancave nga pika në pikë në rrugën e zgjedhur.

FP \u003d P (1) + P (2) + P (3) + P (4) + P (5) + P (6),

ku P(1) ... P(6) është distanca ndërmjet pikave në kalimin përkatës nga matrica e distancës

Ne duhet të gjejmë distancën minimale, prandaj, sa më e vogël të jetë vlera FF për një individ, aq më mirë.

Le të llogarisim funksionet e fitnesit. Për individin e parë:

Për individët e mbetur, marrim në të njëjtën mënyrë.

Rreth katër vjet më parë, në universitet, dëgjova për një metodë të tillë optimizimi si një algoritëm gjenetik. Saktësisht dy fakte u raportuan për të gjithandej: ai është i ftohtë dhe nuk punon. Përkundrazi, funksionon, por është i ngadalshëm, jo ​​i besueshëm dhe nuk duhet të përdoret askund. Por ai mund të demonstrojë bukur mekanizmat e evolucionit. Në këtë artikull, unë do të tregoj një mënyrë të bukur për të parë proceset evolucionare drejtpërdrejt duke përdorur këtë metodë të thjeshtë si shembull. Gjithçka që ju nevojitet është pak matematikë, programim dhe e gjithë kjo e kalitur me imagjinatë.

Shkurtimisht për algoritmin

Pra, çfarë është një algoritëm gjenetik? Kjo është, para së gjithash, një metodë e optimizimit shumëdimensional, d.m.th. Metoda për gjetjen e minimumit të një funksioni shumëdimensional. Potencialisht, kjo metodë mund të përdoret për optimizimin global, por ka vështirësi me këtë, unë do t'i përshkruaj më vonë.

Vetë thelbi i metodës qëndron në faktin se ne modulojmë procesin evolucionar: kemi një lloj popullate (bashkësi vektorësh) që riprodhohet, e cila ndikohet nga mutacionet dhe seleksionimi natyror kryhet në bazë të minimizimit të funksionit objektiv. Le t'i hedhim një vështrim më të afërt këtyre proceseve.

Pra, para së gjithash, popullsia jonë duhet shumohen. Parimi themelor i riprodhimit është se pasardhësit janë të ngjashëm me prindërit e tyre. Ato. ne duhet të krijojmë një lloj mekanizmi të trashëgimisë. Dhe do të ishte më mirë nëse ai përfshinte një element fati. Por shkalla e zhvillimit të sistemeve të tilla është shumë e ulët - diversiteti gjenetik po bie, popullsia po degjeneron. Ato. vlera e funksionit pushon së minimizuari.

Për të zgjidhur këtë problem, u prezantua një mekanizëm mutacionet, e cila konsiston në një ndryshim të rastësishëm të disa individëve. Ky mekanizëm ju lejon të sillni diçka të re në diversitetin gjenetik.
Mekanizmi tjetër i rëndësishëm është përzgjedhje. Siç u tha, përzgjedhja është përzgjedhja e individëve (është e mundur vetëm nga ata që kanë lindur, por është e mundur nga të gjithë - praktika tregon se kjo nuk luan një rol vendimtar), të cilët minimizojnë më mirë funksionin. Zakonisht zgjidhen aq individë sa ka pasur para riprodhimit, në mënyrë që nga epoka në epokë të kemi një numër konstant individësh në popullatë. Është gjithashtu e zakonshme të zgjidhni "ata me fat" - një numër i caktuar individësh që, ndoshta, nuk e minimizojnë mirë funksionin, por do të sjellin diversitet në brezat pasardhës.

Këto tre mekanizma shpesh nuk janë të mjaftueshëm për të minimizuar funksionin. Kështu degjeneron popullsia - herët a vonë minimumi lokal e bllokon gjithë popullsinë me vlerën e tij. Kur kjo ndodh, një proces i quajtur duke u tundur(në natyrë, analogjitë janë kataklizma globale), kur pothuajse e gjithë popullata shkatërrohet dhe shtohen individë të rinj (të rastësishëm).

Këtu është një përshkrim i algoritmit gjenetik klasik, është i lehtë për t'u zbatuar dhe ka vend për imagjinatë dhe kërkime.

Formulimi i problemit

Pra, kur vendosa tashmë që doja të provoja të zbatoja këtë algoritëm legjendar (megjithëse të pasuksesshëm), biseda u kthye në atë që do të minimizoja? Zakonisht ata marrin një funksion të tmerrshëm shumëdimensional me sinus, kosinus, etj. Por kjo nuk është shumë interesante dhe aspak vizuale. Doli një ide e thjeshtë - për shfaqjen e një vektori shumëdimensional, një imazh është i shkëlqyeshëm, ku vlera është përgjegjëse për shkëlqimin. Pra, ne mund të prezantojmë një funksion të thjeshtë - distancën nga imazhi ynë i synuar, i matur në ndryshimin e shkëlqimit të pikselit. Për thjeshtësi dhe shpejtësi, bëra imazhe me një shkëlqim prej 0 ose 255.

Nga pikëpamja e matematikës, një optimizim i tillë është thjesht një gjë e vogël. Grafiku i një funksioni të tillë është një "gropë" e madhe shumëdimensionale (si një parabaloid tredimensional në figurë), në të cilën në mënyrë të pashmangshme do të rrëshqasni nëse ndiqni gradientin. I vetmi minimum lokal është global. .

Problemi i vetëm është se tashmë afër minimumit, numri i shtigjeve që mund të zbrisni është reduktuar shumë, dhe në total kemi aq drejtime sa ka dimensione (d.m.th., numrin e pikselave). Natyrisht, nuk ia vlen të zgjidhet ky problem duke përdorur një algoritëm gjenetik, por ne mund të shohim procese interesante që ndodhin në popullatën tonë.

Zbatimi

Të gjithë mekanizmat e përshkruar në paragrafin e parë janë zbatuar. Riprodhimi u krye thjesht duke kryqëzuar pikselë të rastësishëm nga "nëna" dhe nga "babai". Mutacionet u bënë duke ndryshuar vlerën e një piksel të rastësishëm në një individ të rastësishëm në të kundërtën. Dhe shkundja bëhej nëse minimumi nuk ndryshonte për pesë hapa. Pastaj prodhohet një "mutacion ekstrem" - zëvendësimi ndodh më intensivisht se zakonisht.

Kam marrë jonograme ("fjalëkryqe japoneze") si fotografi fillestare, por, në të vërtetë, ju mund të merrni vetëm katrorë të zinj - nuk ka absolutisht asnjë ndryshim. Më poshtë tregohen rezultatet për imazhe të shumta. Këtu, për të gjithë, përveç "shtëpisë", numri mesatar i mutacioneve ishte 100 për individ, kishte 100 individë në popullatë dhe gjatë riprodhimit, popullsia u rrit me 4 herë. Ata me fat ishin 30% në çdo epokë. Për shtëpinë u zgjodhën vlera më të vogla (30 individë në popullatë, 50 mutacione për individ).




Eksperimentalisht, zbulova se përdorimi i "me fat" në përzgjedhje ul shkallën e popullatës që priret në minimum, por ndihmon për të dalë nga stanjacioni - pa "fat", stanjacioni do të jetë konstant. Çfarë shihet nga grafikët: grafiku i majtë është zhvillimi i popullatës “faraon” me fatlumët, i djathti është pa fat.


Kështu, ne shohim se ky algoritëm na lejon të zgjidhim problemin, megjithëse për një kohë shumë të gjatë. Shumë tronditje, në rastin e imazheve të mëdha, mund të vendosin për më shumë individë në popullatë. Unë e lë zgjedhjen optimale të parametrave për dimensione të ndryshme përtej qëllimit të këtij postimi.

Optimizimi global

Siç u tha, optimizimi lokal është një detyrë mjaft e parëndësishme, madje edhe për rastet shumëdimensionale. Është shumë më interesante të shihet se si algoritmi do të përballet me optimizimin global. Por për ta bërë këtë, së pari duhet të ndërtoni një funksion me shumë minimume lokale. Dhe kjo nuk është aq e vështirë në rastin tonë. Mjafton të marrësh një minimum distancash në disa imazhe (shtëpi, dinosaur, peshk, varkë). Pastaj algoritmi origjinal do të "rrokulliset" në një vrimë të rastësishme. Dhe thjesht mund ta ekzekutoni disa herë.

Por ka një zgjidhje më interesante për këtë problem: ne mund të kuptojmë se kemi rrëshqitur në një minimum lokal, të bëjmë një tronditje të fortë (ose edhe të inicojmë sërish individë) dhe të shtojmë më tej dënimet kur i afrohemi një minimumi të njohur. Siç mund ta shihni, fotografitë janë të ndërthurura. Vërej se nuk kemi të drejtë të prekim funksionin origjinal. Por ne mund të kujtojmë minimumet lokale dhe të shtojmë vetë penalltitë.

Kjo foto tregon rezultatin kur, me arritjen e një minimumi lokal (stanjacion i fortë), popullsia thjesht vdes.

Këtu popullsia vdes dhe shtohet një gjobë e vogël (në shumën e distancës së zakonshme në një minimum të njohur). Kjo zvogëlon shumë gjasat e përsëritjeve.

Është më interesante kur popullsia nuk shuhet, por thjesht fillon të përshtatet me kushtet e reja (figura vijuese). Kjo arrihet me një dënim prej 0.000001 * shuma ^ 4. Në këtë rast, imazhet e reja bëhen pak të zhurmshme:

Kjo zhurmë hiqet duke kufizuar dënimin në maksimum (0.000001 * shuma^4, 20). Por ne shohim se minimumi i katërt lokal (dinosauri) nuk mund të arrihet - ka shumë të ngjarë sepse është shumë afër me ndonjë tjetër.

Interpretimi biologjik


Nga çfarë konkluzione mund të nxjerrim, nuk kam frikë nga kjo fjalë, modeling? Para së gjithash, ne shohim se riprodhimi seksual është motori më i rëndësishëm i zhvillimit dhe përshtatjes. Por vetëm ajo nuk mjafton. Roli i ndryshimeve të rastësishme, të vogla është jashtëzakonisht i rëndësishëm. Janë ata që sigurojnë shfaqjen e specieve të reja të kafshëve në procesin e evolucionit, dhe në vendin tonë siguron diversitetin e popullsisë.

Rolin më të rëndësishëm në evolucionin e Tokës e luajtën fatkeqësitë natyrore dhe zhdukjet masive (zhdukjet e dinosaurëve, insekteve etj. - gjithsej ishin rreth dhjetë të mëdhenj - shih diagramin më poshtë). Kjo u vërtetua edhe nga simulimet tona. Dhe përzgjedhja e "me fat" tregoi se organizmat më të dobët sot janë në gjendje të bëhen bazë për brezat e ardhshëm në të ardhmen.

Siç thonë ata, gjithçka është si në jetë. Kjo metodë evolucioni bëjeni vetë tregon qartë mekanizmat interesantë dhe rolin e tyre në zhvillim. Sigurisht, ka shumë modele evolucionare më të vlefshme (të bazuara, natyrisht, në Difurs), të cilat marrin parasysh më shumë faktorë që janë më afër jetës. Sigurisht, ka metoda më efikase të optimizimit.

P.S.

Kam shkruar një program në Matlab (ose më mirë, edhe në Octave), sepse gjithçka këtu është matrica budallaqe, dhe ka mjete për të punuar me fotografi. Kodi burimor është bashkangjitur.

Burimi

funksioni res = gjenetik(skedar) %gjeneron A B globale; im2line (skedar); dim = gjatësi(A(1,:)); numërimi = 100; riprodhimi = 4; mut = 100; zgjidhni = 0.7; ngecje = 0,8; pop = rrumbullakët(rand(numërimi, dim)); res = ; B = ; lokalmin = ; llogaritja lokale = ; për k = 1:300 %riprodhim për j = 1:count * reprod pop = ; fundi %mutacioni idx = 10 * (gjatësia(res) > 5 && std(res(1:5)) == 0) + 1; për j = 1: numërim * mut a = dysheme(rand() * numërim) + 1; b = dysheme(rand() * dim) + 1; pop(a,b) = ~pop(a,b); fund %selection val = func(pop); val(1:count) = val(1:count) * 10; npop = zero (numërimi, dim); = sort(val); res = ; opt = pop(i(1),:); fn = sprintf("rezultat/%05d-%d.png",k,s(1)); line2im (opt*255,fn); nëse (s(1) == 0 || numërimi lokal > 10) localmin = ; numërimi lokal = ; B = ; %pop = rrumbullakët(rand(count,dim)); vazhdo; %break; fundi për j = 1:kat(numëroni * zgjidhni) npop(j,:) = pop(i(j),:); fund %duke shtuar fate për j = (kat(numëroni*zgjedh)+1) : numëroni npop(j,:) = pop(kat(rand() * numërim) + 1,:); fund %rregullimi i stagnimit if (gjatësia(res) > 5 && std(res(1:5)) == 0) nëse (lokalmin == res(1)) llogaria lokale = llogaria lokale+1; tjetër numër lokal = 1; fund localmin = res(1); për j = 1: numërim*stagn a = dysheme(rand() * numërim) + 1; npop(a,:) = crossingover(npop(a,:),rand(1,dim)); fund fund pop = npop; fund res = res(gjatesi(res):-1:1); Funksioni fundor res = kryqëzim(a, b) x = rrumbullakët(rand(madhësia(a))); res = a .* x + b .* (~x); funksioni fundor res = func(v) global A B; res = inf; për i = 1: madhësia (A,1) res = min (res, shuma (v ~= A (i,:), 2)); fundi për i = 1: madhësia (B,1) res = res + max(0.000001 * shuma (v == B(i,:),2) .^ 4,20); fundi i funksionit = im2line(skedarët) global A sz; A = ; skedarë = cellstr(skedarë); për i = 1: madhësia (skedarët, 1) imorig = imread (char(skedarët (i,:))); sz = madhësia (imorig); A = )]; fundi A = A / 255; funksioni fundor = line2im(im,skedar) global sz; imwrite(riforma(im*255,sz),skedar); fund

Etiketa: Shtoni etiketa

Kohët e fundit, është folur gjithnjë e më shumë për algoritme të reja, të tilla si rrjetet nervore dhe një algoritëm gjenetik. Sot do të flas për algoritmet gjenetike, por këtë herë le të përpiqemi të bëjmë pa përkufizime abstruktive dhe terma komplekse.
Siç tha një nga shkencëtarët e mëdhenj: "Nëse nuk mund t'ia shpjegoni teorinë tuaj gruas suaj, teoria juaj është e pavlerë!" Pra, le të përpiqemi të kuptojmë gjithçka në rregull.

Një majë historie

Siç thotë Wikipedia: "Babai themelues i algoritmeve gjenetike, John Holland, i cili doli me idenë e përdorimit të gjenetikës për qëllimet e tij tashmë në 1975." Për referencë, Altair 8800 u shfaq në të njëjtin vit, dhe jo, ky nuk është një terrorist, por kompjuteri i parë personal. Në atë kohë, Gjoni ishte tashmë 46 vjeç.

Ku përdoret

Meqenëse algoritmi është vetë-mësues, gama e aplikacioneve është jashtëzakonisht e gjerë:
  • Detyrat për grafikët
  • Ndërtoni detyra
  • Planifikimi
  • Krijimi i "Inteligjencës Artificiale"

Parimi i funksionimit

Algoritmi gjenetik është kryesisht një algoritëm evolucionar, me fjalë të tjera, tipari kryesor i algoritmit është kryqëzimi (kombinimi). Siç mund ta merrni me mend, ideja e algoritmit u mor me paturpësi nga natyra, pasi ajo nuk do ta padisë atë. Pra, duke renditur dhe, më e rëndësishmja, përzgjedhje, merret "kombinimi" i saktë.
Algoritmi është i ndarë në tre faza:
  • Ciftezim i kryqezuar
  • Përzgjedhja (përzgjedhja)
  • Formimi i një brezi të ri
Nëse rezultati nuk na përshtatet, këto hapa përsëriten derisa rezultati të fillojë të na kënaqë ose të ndodhë një nga kushtet e mëposhtme:
  • Numri i gjeneratave (cikleve) do të arrijë një maksimum të paracaktuar
  • Koha e skaduar për mutacion
Mësoni më shumë rreth hapave
Krijimi i një popullsie të re. Në këtë hap, krijohet një popullsi fillestare, e cila, me shumë mundësi, nuk do të jetë kosher, por ka të ngjarë që algoritmi ta korrigjojë këtë problem. Gjëja kryesore është që ato të korrespondojnë me "formatin" dhe të "përshtaten me riprodhim".
riprodhimi. Epo, gjithçka është si me njerëzit, kërkohen dy prindër për të marrë një pasardhës. Gjëja kryesore është që pasardhësi (fëmija) mund të trashëgojë tiparet e tyre nga prindërit. Në të njëjtën kohë, të gjithë rriten, jo vetëm të mbijetuarit (kjo frazë është veçanërisht absurde, por duke qenë se ne kemi gjithçka në një vakum sferik, gjithçka është e mundur), përndryshe do të bie në sy një mashkull alfa, gjenet e të cilit do të mbivendosen me të gjithë të tjerët, dhe kjo është thelbësisht e papranueshme për ne.
Mutacionet. Mutacionet janë të ngjashme me riprodhimin, një numër i caktuar individësh zgjidhen nga mutantët dhe ndryshohen në përputhje me operacionet e paracaktuara.
Përzgjedhja. Këtu fillon gjëja më e ëmbël, fillojmë të zgjedhim nga popullsia proporcionin e atyre që "shkojnë më tej". Në të njëjtën kohë, ne përcaktojmë proporcionin e "të mbijetuarve" pas përzgjedhjes sonë paraprakisht me dorë, duke e treguar atë si një parametër. Mjerisht, pjesa tjetër e individëve duhet të vdesë.

Praktikoni

Ju keni dëgjuar me sukses "përrallën" për algoritmin e mrekullisë dhe ka shumë mundësi që keni pritur që ne të fillojmë ta përdorim atë, më në fund, dua t'ju kënaq, ka ardhur koha.
Le të shohim shembullin e ekuacioneve të mia të preferuara Diophantine (Ekuacionet me rrënjë të plota).
Ekuacioni ynë: a+2b+3c+4d=30
Ju ndoshta tashmë dyshoni se rrënjët e këtij ekuacioni qëndrojnë në intervalin , kështu që marrim 5
vlerat e rastësishme a,b,c,d. (Kufiri prej 30 merret posaçërisht për të thjeshtuar detyrën)
Dhe kështu, ne kemi gjeneratën e parë:
  1. (1,28,15,3)
  2. (14,9,2,4)
  3. (13,5,7,3)
  4. (23,8,16,19)
  5. (9,13,5,2)
Për të llogaritur shkallët e mbijetesës, ne zëvendësojmë secilën zgjidhje në shprehje. Distanca nga vlera e marrë në 30 do të jetë vlera e dëshiruar.
  1. |114-30|=84
  2. |54-30|=24
  3. |56-30|=26
  4. |163-30|=133
  5. |58-30|=28
Prandaj, vlerat më të vogla më afër 30 janë më të dëshirueshme. Rezulton se vlerat më të mëdha do të kenë një shkallë më të ulët të mbijetesës. Për të krijuar një sistem, ne llogarisim probabilitetin e zgjedhjes së secilit (kromozomit). Por zgjidhja është të marrim shumën e reciprokeve të koeficientëve dhe të llogarisim përqindjet prej saj. ( P.S. 0.135266 - shuma e koeficientëve reciprokë)
  1. (1/84)/0.135266 = 8.80%
  2. (1/24)/0.135266 = 30.8%
  3. (1/26)/0.135266 = 28.4%
  4. (1/133)/0.135266 = 5.56%
  5. (1/28)/0.135266 = 26.4%
Më pas do të zgjedhim pesë çifte prindërish që do të kenë saktësisht nga një fëmijë. Ne do t'i japim shfryrje rastit saktësisht pesë herë, çdo herë mundësia për t'u bërë prind do të jetë e njëjtë dhe do të jetë e barabartë me mundësinë e mbijetesës.
3-1, 5-2, 3-5, 2-5, 5-3
Siç u përmend më herët, pasardhësit përmbajnë informacione për gjenet e babait dhe nënës. Kjo mund të arrihet në mënyra të ndryshme, por në këtë rast, do të përdoret një "crossover". (| = vijë ndarëse)
  • H.-babai: a1 | b1,c1,d1 H.-nëna: a2 | b2,c2,d2 H.-pasardhës: a1,b2,c2,d2 ose a2,b1,c1,d1
  • H.-babai: a1,b1 | c1,d1 H.-nëna: a2,b2 | c2,d2 H.-pasardhës: a1,b1,c2,d2 ose a2,b2,c1,d1
  • H.-babai: a1,b1,c1 | d1 H.-nëna: a2,b2,c2 | d2 H.-pasardhës: a1,b1,c1,d2 ose a2,b2,c2,d1
Ka kaq shumë mënyra për t'i kaluar informacionet një pasardhësi, dhe kryqëzimi është vetëm një nga shumë. Vendndodhja e ndarësit mund të jetë absolutisht arbitrare, si dhe fakti që babai ose nëna do të jenë në të majtë të linjës.
Tani le të bëjmë të njëjtën gjë me fëmijët:
  • H.-babai: (13 | 5,7,3) H.-nëna:(1 | 28,15,3) H.-pasardhës: (13,28,15,3)
  • H.-babai: (9,13 | 5,2) H.-nëna: (14,9 | 2,4) H.-pasardhës: (9,13,2,4)
  • H.-babai: (13,5,7 | 3) H.-nëna: (9,13,5 | 2) H.-pasardhës: (13,5,7,2)
  • H.-babai: (14 | 9,2,4) H.-nëna: (9 | 13,5,2) H.-pasardhës: (14,13,5,2)
  • H.-babai: (13,5 | 7, 3) H.-nëna: (9,13 | 5, 2) H.-pasardhës: (13,5,5,2)
Tani ne llogarisim normat e mbijetesës së pasardhësve.
  • (13,28,15,3) - |126-30|=96(9,13,2,4) - |57-30|=27
    (13,5,7,2) - |57-30|=22
    (14,13,5,2) - |63-30|=33
    (13,5,5,2) - |46-30|=16

    Është e trishtueshme sepse fitnesi mesatar i pasardhësve doli të ishte 38.8, ndërsa për prindërit ky koeficient ishte 59.4. Është në këtë moment që është më e përshtatshme të përdoret një mutacion, për këtë ne do të zëvendësojmë një ose më shumë vlera me një numër të rastësishëm nga 1 në 30.
    Algoritmi do të funksionojë derisa shkalla e mbijetesës të jetë zero. Ato. do të jetë zgjidhja e ekuacionit.
    Sistemet me popullsi më të madhe (p.sh. 50 në vend të 5) konvergojnë në nivelin e dëshiruar (0) më shpejt dhe në mënyrë konsistente.

    Kodi

    Këtu përfundon thjeshtësia dhe fillon C++ e mrekullueshme...
    Një klasë C++ kërkon 5 vlera gjatë inicializimit: 4 koeficientë dhe një rezultat. Për shembullin e mësipërm, do të duket kështu: CDiofantine dp(1,2,3,4,30);

    Pastaj, për të zgjidhur ekuacionin, thirrni funksionin Solve(), i cili do të kthejë alelin që përmban zgjidhjen. Thirrni GetGene() për të marrë gjenin me vlerat e sakta a, b, c, d. Procedura standarde main.cpp duke përdorur këtë klasë mund të jetë:

    #përfshi" " #include "diophantine.h" void main() ( CDiophantine dp(1,2,3,4,30); int ans; ans = dp.Solve(); if (ans == -1) (cout<< "No solution found." << endl; } else { gene gn = dp.GetGene(ans); cout << "The solution set to a+2b+3c+4d=30 is:\n"; cout << "a = " << gn.alleles << "." << endl; cout << "b = " << gn.alleles << "." << endl; cout << "c = " << gn.alleles << "." << endl; cout << "d = " << gn.alleles << "." << endl; } }

    Vetë klasa CDiofantine:

    #përfshi #përfshi #define MAXPOP 25 struct genin ( int alele; int fitness;<4;i++) { if (gn.alleles[i] != alleles[i]) return false; } return true; } }; class CDiophantine { public: CDiophantine(int, int, int, int, int);// Constructor with coefficients for a,b,c,d. int Solve();// Solve the equation. // Returns a given gene. gene GetGene(int i) { return population[i];} protected: int ca,cb,cc,cd;// The coefficients. int result; gene population;// Population. int Fitness(gene &);// Fitness function. void GenerateLikelihoods(); // Generate likelihoods. float MultInv();// Creates the multiplicative inverse. int CreateFitnesses(); void CreateNewPopulation(); int GetIndex(float val); gene Breed(int p1, int p2); }; CDiophantine::CDiophantine(int a, int b, int c, int d, int res) : ca(a), cb(b), cc(c), cd(d), result(res) {} int CDiophantine::Solve() { int fitness = -1; // Generate initial population. srand((unsigned)time(NULL)); for(int i=0;i25) pushim; ) temppop[i] = Breed(prind1, prind2);// Krijo një fëmijë. ) për(i=0;i

    Artikulli bazohet në materiale nga Wikipedia dhe faqja

Ideja e algoritmeve gjenetike (GA) u shfaq shumë kohë më parë (1950-1975), por ato janë bërë objekt studimi vetëm në dekadat e fundit. Pionier në këtë fushë konsiderohet D. Holland, i cili huazoi shumë nga gjenetika dhe e përshtati për kompjuterë. GA-të përdoren gjerësisht në sistemet e inteligjencës artificiale, rrjetet nervore dhe problemet e optimizimit.

kërkimi evolucionar

Modelet e algoritmeve gjenetike u krijuan në bazë të evolucionit në jetën e egër dhe metodave të kërkimit të rastësishëm. Në këtë rast, kërkimi i rastësishëm është zbatimi i funksionit më të thjeshtë të evolucionit - mutacionet e rastësishme dhe përzgjedhja pasuese.

Kërkimi evolucionar nga pikëpamja matematikore nuk do të thotë asgjë më shumë se transformimi i një grupi zgjidhjesh të fundme ekzistuese në një të re. Funksioni përgjegjës për këtë proces është kërkimi gjenetik. Dallimi kryesor midis një algoritmi të tillë dhe një kërkimi të rastësishëm është përdorimi aktiv i informacionit të grumbulluar gjatë përsëritjeve (përsëritjeve).

Pse nevojiten algoritmet gjenetike

GA ka këto objektiva:

  • të shpjegojë mekanizmat e përshtatjes si në mjedisin natyror ashtu edhe në sistemin intelektual-kërkimor (artificial);
  • modelimi i funksioneve evolucionare dhe aplikimi i tyre për kërkim efikas të zgjidhjeve për probleme të ndryshme, kryesisht ato optimizuese.

Për momentin, thelbi i algoritmeve gjenetike dhe versionet e tyre të modifikuara mund të quhet kërkimi i zgjidhjeve efektive, duke marrë parasysh cilësinë e rezultatit. Me fjalë të tjera, gjetja e ekuilibrit më të mirë midis performancës dhe saktësisë. Kjo ndodh për shkak të paradigmës së njohur "mbijetesa e individit më të fortë" në kushte të pasigurta dhe të paqarta.

Karakteristikat e GA

Ne listojmë ndryshimet kryesore midis GA dhe shumicës së metodave të tjera për gjetjen e zgjidhjes optimale.

  • punoni me parametrat e detyrave të koduara në një mënyrë të caktuar, dhe jo drejtpërdrejt me to;
  • kërkimi i një zgjidhjeje nuk ndodh duke rafinuar përafrimin fillestar, por në grupin e zgjidhjeve të mundshme;
  • duke përdorur vetëm funksionin objektiv pa përdorur derivatet dhe modifikimet e tij;
  • aplikimi i një qasjeje probabiliste ndaj analizës, në vend të një qasjeje rreptësisht përcaktuese.

Kriteret e punës

Algoritmet gjenetike kryejnë llogaritjet bazuar në dy kushte:

  1. Ekzekutimi i numrit të specifikuar të përsëritjeve.
  2. Cilësia e zgjidhjes së gjetur plotëson kërkesat.

Nëse një nga këto kushte plotësohet, algoritmi gjenetik do të ndalojë kryerjen e përsëritjeve të mëtejshme. Përveç kësaj, përdorimi i GA-ve në zona të ndryshme të hapësirës së zgjidhjes i lejon ata të jenë shumë më të mirë në gjetjen e zgjidhjeve të reja që kanë vlera më të përshtatshme të funksionit objektiv.

Terminologjia bazë

Për shkak të faktit se GA-të bazohen në gjenetikë, shumica e terminologjisë korrespondon me të. Çdo algoritëm gjenetik funksionon në bazë të informacionit fillestar. Grupi i vlerave fillestare është popullata Pt = (n1, p2, ..., pn), ku pi = (r1, ..., gv). Le të hedhim një vështrim më të afërt:

  • t është numri i përsëritjes. t1, ..., tk - nënkupton përsëritjet e algoritmit nga numri 1 në k, dhe në çdo përsëritje krijohet një popullatë e re zgjidhjesh.
  • n është madhësia e popullsisë Pt.
  • n1, ..., pi - kromozom, individ ose organizëm. Një kromozom ose zinxhir është një sekuencë e koduar gjenesh, secila prej të cilave ka një numër serial. Duhet pasur parasysh se kromozomi mund të jetë një rast i veçantë i një individi (organizmi).
  • rv janë gjenet që janë pjesë e zgjidhjes së koduar.
  • Locus është numri serial i një gjeni në një kromozom. Alele - vlera e një gjeni, i cili mund të jetë ose numerik ose funksional.

Çfarë do të thotë "i koduar" në një kontekst GA? Zakonisht çdo vlerë është e koduar bazuar në ndonjë alfabet. Shembulli më i thjeshtë është shndërrimi i numrave nga sistemi i numrave dhjetorë në paraqitje binar. Kështu, alfabeti përfaqësohet si një grup (0, 1), dhe numri 15710 do të kodohet nga kromozomi 100111012, i përbërë nga tetë gjene.

Prindërit dhe pasardhësit

Prindërit janë elementë që përzgjidhen në përputhje me një kusht të caktuar. Për shembull, shpesh një kusht i tillë është rastësi. Elementët e përzgjedhur, për shkak të operacioneve të kryqëzimit dhe mutacionit, gjenerojnë të reja, të cilat quhen pasardhës. Kështu, gjatë zbatimit të një përsëritjeje të algoritmit gjenetik, prindërit krijojnë një brez të ri.


Së fundi, evolucioni në këtë kontekst do të jetë ndërrimi i brezave, secila e re prej të cilave ndryshon në një grup kromozomesh për hir të përshtatshmërisë më të mirë, domethënë një përshtatje më të përshtatshme për kushtet e dhëna. Sfondi i përgjithshëm gjenetik në procesin e evolucionit quhet gjenotip, dhe formimi i lidhjes së organizmit me mjedisin e jashtëm quhet fenotip.

funksioni i fitnesit

Magjia e algoritmit gjenetik në funksionin e fitnesit. Çdo individ ka vlerën e vet, e cila mund të mësohet përmes funksionit të përshtatjes. Detyra e tij kryesore është të vlerësojë këto vlera për zgjidhje të ndryshme alternative dhe të zgjedhë më të mirën. Me fjalë të tjera, më i forti.

Në problemet e optimizimit, funksioni i fitnesit quhet funksioni i synuar, në teorinë e kontrollit quhet gabim, në teorinë e lojës është funksioni i kostos, etj. Çfarë saktësisht do të përfaqësohet si funksion i përshtatjes varet nga problemi që zgjidhet.

Në fund, mund të konkludojmë se algoritmet gjenetike analizojnë një popullatë individësh, organizmash ose kromozomesh, secila prej të cilave përfaqësohet nga një kombinim gjenesh (një grup vlerash) dhe kërkojnë zgjidhjen optimale, duke transformuar individët e popullsisë përmes evolucioni artificial mes tyre.

Devijimet në një drejtim ose në një tjetër të elementeve individuale në rastin e përgjithshëm janë në përputhje me ligjin normal të shpërndarjes së sasive. Në të njëjtën kohë, GA siguron trashëgiminë e tipareve, më të përshtaturat prej të cilave janë fikse, duke siguruar kështu një popullsi më të mirë.

Algoritmi bazë gjenetik

Le të zbërthejmë GA-në më të thjeshtë (klasike) në hapa.

  1. Inicializimi i vlerave fillestare, pra përcaktimi i popullatës parësore, grupi i individëve me të cilët do të ndodhë evolucioni.
  2. Vendosja e përshtatshmërisë parësore të çdo individi në një popullatë.
  3. Kontrollimi i kushteve të përfundimit për përsëritjet e algoritmit.
  4. Duke përdorur funksionin e përzgjedhjes.
  5. Aplikimi i operatorëve gjenetikë.
  6. Krijimi i një popullsie të re.
  7. Hapat 2-6 përsëriten në një cikël derisa të plotësohet kushti i nevojshëm, pas së cilës zgjidhet individi më i aftë.

Le të kalojmë nëpër pjesët më pak të dukshme të algoritmit. Mund të ketë dy kushte përfundimi:

  1. Numri i përsëritjeve.
  2. Cilësia e zgjidhjes.

Operatorët gjenetikë janë operatori i mutacionit dhe operatori i kryqëzimit. Një mutacion ndryshon gjenet e rastësishme me një probabilitet të caktuar. Si rregull, probabiliteti i mutacionit ka një vlerë të ulët numerike. Le të flasim më në detaje për procedurën e algoritmit gjenetik "kryqëzimi". Kjo ndodh sipas parimit të mëposhtëm:

  1. Për çdo çift prindërish që përmbajnë gjenet L, një pikë kalimi Tski zgjidhet rastësisht.
  2. Pasardhësit e parë formohen duke u bashkuar me gjenet e prindit të parë [Tski+1; L] gjenet e prindit të dytë.
  3. Pasardhësi i dytë përpilohet në mënyrë të kundërt. Tani gjenet e prindit të parë i shtohen gjeneve të prindit të dytë në pozicionet [Тсi+1; L].

Shembull i parëndësishëm

Le ta zgjidhim problemin me një algoritëm gjenetik duke përdorur shembullin e gjetjes së një individi me numrin maksimal të njësheve. Lëreni një individ të përbëhet nga 10 gjene. Le të vendosim popullsinë parësore në shumën prej tetë individësh. Natyrisht, individi më i mirë duhet të jetë 1111111111. Le të kompensojmë zgjidhjen GA.

  • Inicializimi. Le të zgjedhim 8 individë të rastësishëm:

Nga tabela shihet se individët 3 dhe 7 kanë numrin më të madh të njësive, që do të thotë se ata janë anëtarët më të përshtatshëm të popullatës për zgjidhjen e problemit. Meqenëse për momentin nuk ka zgjidhje të cilësisë së kërkuar, algoritmi vazhdon të funksionojë. Është e nevojshme të kryhet përzgjedhja e individëve. Për lehtësi shpjegimi, lëreni përzgjedhjen të ndodhë në mënyrë të rastësishme dhe marrim një mostër individësh (n7, n3, n1, n7, n3, n7, n4, n2) - këta janë prindërit për popullatën e re.

  • Përdorimi i operatorëve gjenetikë. Përsëri, për thjeshtësi, supozojmë se probabiliteti i mutacioneve është 0. Me fjalë të tjera, të 8 individët i kalojnë gjenet e tyre ashtu siç janë. Për të kryer kryqëzimin, ne do të bëjmë çifte individësh në mënyrë të rastësishme: (n2, n7), (n1, n7), (n3, n4) dhe (n3, n7). Pikat e kryqëzimit për çdo çift zgjidhen gjithashtu rastësisht:
  • Përpilimi i një popullsie të re të përbërë nga pasardhës:

Hapat e ardhshëm janë të qartë. Gjëja më interesante rreth GA zbulohet nëse vlerësojmë numrin mesatar të njësive në çdo popullatë. Në popullsinë e parë, mesatarisht, kishte 5.375 njësi për individ, në popullsinë e pasardhësve - 6.25 njësi për individ. Dhe një veçori e tillë do të vërehet edhe nëse, gjatë rrjedhës së mutacioneve dhe kryqëzimeve, humbet individi me numrin më të madh të njësive në popullatën e parë.

Plani i zbatimit

Krijimi i një algoritmi gjenetik është një detyrë mjaft e vështirë. Së pari, ne rendisim planin në formën e hapave, pas së cilës do të analizojmë secilën prej tyre në më shumë detaje.

  1. Përkufizimi i përfaqësimit (alfabetit).
  2. Përkufizimi i operatorëve të ndryshimit të rastësishëm.
  3. Përcaktimi i mbijetesës së individëve.
  4. Gjenerimi i popullsisë parësore.

Faza e parë thotë se alfabeti në të cilin do të kodohen të gjithë elementët e grupit të vendimeve ose popullatës duhet të jetë mjaft fleksibël për të lejuar njëkohësisht operacionet e nevojshme të permutacioneve të rastësishme dhe për të vlerësuar përshtatshmërinë e elementeve, si parësorë ashtu edhe atyre që kanë pësuar ndryshime. Është vërtetuar matematikisht se është e pamundur të krijohet një alfabet ideal për këto qëllime, prandaj përpilimi i tij është një nga fazat më të vështira dhe më të përgjegjshme për të siguruar funksionimin e qëndrueshëm të GA.


Po aq i vështirë është përcaktimi i operatorëve të modifikimit dhe krijimit të fëmijëve. Ka shumë operatorë që janë të aftë të kryejnë veprimet e kërkuara. Për shembull, nga biologjia dihet se çdo specie mund të riprodhohet në dy mënyra: seksuale (të kryqëzuara) dhe aseksuale (mutacione). Në rastin e parë, prindërit shkëmbejnë materialin gjenetik, në të dytën ndodhin mutacione, të përcaktuara nga mekanizmat e brendshëm të trupit dhe ndikimet e jashtme. Përveç kësaj, mund të përdoren modele riprodhimi që nuk ekzistojnë në natyrë. Për shembull, përdorni gjenet e tre ose më shumë prindërve. Ngjashëm me kryqëzimin, një shumëllojshmëri mekanizmash mund të përfshihen në algoritmin gjenetik të mutacionit.

Zgjedhja se si të mbijetosh mund të jetë jashtëzakonisht mashtruese. Ka shumë mënyra në algoritmin gjenetik për përzgjedhje. Dhe, siç tregon praktika, rregulli "mbijetesa e më të fortit" nuk është gjithmonë më i miri. Kur zgjidhni probleme komplekse teknike, shpesh rezulton se zgjidhja më e mirë del nga shumë mesatare ose edhe më të këqija. Prandaj, shpesh është zakon të përdoret një qasje probabiliste, e cila thotë se zgjidhja më e mirë ka një shans më të mirë për të mbijetuar.


Faza e fundit siguron fleksibilitetin e algoritmit, të cilin askush tjetër nuk e ka. Popullata primare e zgjidhjeve mund të vendoset si në bazë të disa të dhënave të njohura, ashtu edhe në mënyrë krejtësisht të rastësishme, thjesht duke riorganizuar gjenet brenda individëve dhe duke krijuar individë të rastësishëm. Sidoqoftë, ia vlen të kujtohet gjithmonë se efikasiteti i algoritmit varet kryesisht nga popullsia fillestare.

Efikasiteti

Efektiviteti i algoritmit gjenetik varet tërësisht nga zbatimi i saktë i fazave të përshkruara në plan. Një pikë veçanërisht me ndikim këtu është krijimi i një popullsie parësore. Ka shumë qasje për këtë. Le të përshkruajmë disa:

  1. Krijimi i një popullate të plotë, e cila do të përfshijë të gjitha variantet e mundshme të individëve në një zonë të caktuar.
  2. Krijimi i rastësishëm i individëve bazuar në të gjitha vlerat e vlefshme.
  3. Pika e krijimit të rastësishëm të individëve, kur një interval për gjenerim zgjidhet midis vlerave të vlefshme.
  4. Kombinimi i tre mënyrave të para për të krijuar një popullsi.

Kështu, mund të konkludojmë se efektiviteti i algoritmeve gjenetike varet kryesisht nga përvoja e programuesit në këtë çështje. Ky është edhe një disavantazh i algoritmeve gjenetike dhe avantazh i tyre.



Artikulli i mëparshëm: Artikulli vijues:

© 2015 .
Rreth sajtit | Kontaktet
| harta e faqes