Autoři zadání | Radoslav Sabol Matej Focko Martin Krebs |
---|---|
Úprava | David Štorek |
Odevzdávané soubory |
src/main.c
src/*.c
src/*.h
|
Začátek odevzdávání | viz diskusní fórum |
Další odevzdání navíc do | neurčeno |
Konec odevzdání | 2024-06-16 24:00 |
Vzorová implementace |
/home/kontr/pb071/hw06/pandemic
|
Predstavenie úlohy
Modelovanie a simulácie sú veľmi efektívny nástroj, ako pomocou vhodnej úrovne abstrakcie modelovať a skúmať aj veľmi zložité systémy. Jednou z najpoužívanejších oblastí je takzvaný Agent-based modeling.
Ide o výpočetný model, ktorý sleduje akcie a interakcie jednotlivých agentov. Na to, aby sme mohli nejaký jav skúmať pomocou takejto simulácie, si však musíme najprv vytvoriť vhodné prostredie.
Mnohí z vás určite poznajú hru Plague Inc., v ktorej hráte na strane vírusu a snažíte sa vyhubiť ľudstvo. My si v tejto domácej úlohe naprogramujeme zjednodušenú verziu a viac, ako koniec ľudstva, nás bude zaujímať spôsob, akým sa vírus šíri a čo všetko ovplyvňuje jeho nákazlivosť.
Zadanie
Napíšte program, ktorý z príkazového riadka a súborov načíta informácie o víruse, agentoch a svete, v ktorom bude simulácia prebiehať. Následne simuláciu spustite a na textový výstup vypíšte informácie o jej priebehu.
Použitie výsledného programu bude vyzerať takto:
./pandemic [OPTIONS] agents.csv world.csv
Kde [OPTIONS]
sú voliteľné prepínače programu, world.csv
je súbor popisujúci
svet a agents.csv
je súbor s agentmi
(Detailný popis v príslušnom odstavci).
Prepínače
--lethality <float>
-
Prepínač popisujúci smrteľnosť vírusu, používa sa vo vzorci na výpočet úmrtí agentov. Ak prepínač nie je špecifikovaný,
lethality
bude nastavené na hodnotu0.5
. Hodnota musí byť z rozsahu[0, 1]
. --infectivity <float>
-
Infekčnosť vírusu, používa sa vo vzorci na výpočet prenášania vírusu medzi agentmi. V prípade, že prepínač nie je špecifikovaný, nastavte hodnotu na
0.5
. Hodnota musí byť z rozsahu[0, 1]
. --duration <float>
-
Doba infekčnosti, používa sa vo vzorci na výpočet, či sa daný agent vylieči alebo nie. Ak nie je špecifikovaná, očakávaná hodnota je
0.5
. Hodnota musí byť z rozsahu[0, 1]
. --vaccine-modifier <float>
-
Reálne nezáporné číslo, ktoré reprezentuje účinnosť vakcíny, ktorou sú všetci agenti zaočkovaní. Predvolná hodnota je
1.2
. --max-steps <int>
-
Nezáporné celé číslo popisujúce počet kôl simulácie. Ak nie toto číslo špecifikované, očakáva sa, že vaša simulácia bude bežať až do chvíle, kým nie sú všetci agenti zdraví alebo mŕtvi.
--random-seed <int>
-
Seed, ktorý potrebujeme byť schopní nastaviť pre účely testovania. V prípade, že prepínač nie je špecifikovaný, predvolená hodnota je
time(NULL)
. Nezabudnite tento seed nastaviť pomocousrand(3)
pred samotným spustením simulácie.V prípade, že porovnávate správanie referenčnej implementácie voči tej vašej, nezabudnite tento prepínač nastaviť na rovnakú hodnotu pre oba programy.
Následujúce prepínače ovplyvňujú správanie výpisu. Jeho detailný formát nájdete v časti o vyhodnotení priebehu.
--summary
-
Zadanie tohoto prepínača vynechá výpis podrobného priebehu simulácie, a vypíše len finálnu štatistiku. Takéto správanie môže byť užitočné v prípadoch, kde nás podrobnejší výpis nezaujíma, a to napríklad pri porovnaní rôznych nastavení simulácie.
--verbose
-
V prípade, že je zvolený tento prepínač, požaduje sa, aby váš program rozšíril podrobný výstup o hodnoty „náhodných hodov“ (angl. _rolls“). Takýto výstup prispieva k lepšej interpretácii simulácie, a môže vám pomôcť napríklad pri ladení.
Všimnite si, že posledné dva prepínače sa navzájom vylučujú, a váš program by mal zareagovať vypísaním vhodnej hlášky na štandardný chybový výstup a ukončiť svoj beh. To isté platí pre ľubovovolný neplatný alebo chybne zadaný prepínač.
Vírus
Rovnako ako občas v skutočnom svete, aj v tejto úlohe bude pre nás vírus akousi záhadnou entitou, o ktorej toho veľa nevieme. Všetky informácie týkajúce sa vírusu sa zadávajú ako prepínače na príkazovom riadku. Pre vírus sú relevantné
-
Lethality
--lethality <float>
-
Infectivity
--infectivity <float>
-
Duration
--duration <float>
Ako ovplyvňujú priebeh samotnej simulácie sa dočítate v časti o jej priebehu.
Svet
Svet budeme reprezentovať ako úplný graf, ktorého vrcholy predstavujú miesta, v ktorých sa združujú agenti.
Súbor bude vo formáte CSV, kde každý riadok bude reprezentovať jeden vrchol nášho grafu. Každý validný riadok bude mať nasledujúce stĺpce:
id;name;exposure
id <int>
-
Nezáporný celočíselný unikátny identifikátor daného miesta.
name <reťazec>
-
Názov daného miesta, používať ho budeme pri výpise informácií o simulácii. Implementácia musí podporovať reťazec s dĺžkou aspoň 16 ASCII znakov.
exposure <float>
-
Nezáporné reálne číslo, ktoré ovplyvňuje šírenie vírusu v danom vrchole grafu.
Príklad súboru so svetom:
$ cat Bratislava.csv
1;Robota;0.7
2;Kostol;0.0
3;Krčma;1.0
4;Cintorín;0.0
5;Domov;0.4
Formát CSV nie je úplne štandardizovaný, vo väčšine prípadov obsahuje prvý riadok názvy jednotlivých stĺpcov. V celom zadaní predpokladáme, že vstupný súbor takýto riadok neobsahuje. |
V prípade, že vášmu programu bude dodaná cesta k súboru so svetom, bude to vždy posledný argument volania programu.
V prípade, že vás článok o úplnom grafe viac zmiatol než obohatil, stačí, ak rozumiete, že medzi každým vrcholom vedie hrana. V praxi to znamená, že agenti sa môžu (a budú) pohybovať medzi ľubovoľnými dvoma vrcholmi, podľa toho, ako to majú špecifikované vo svojom správaní.
Overte, že pre každý riadok kontrolujete správny počet stĺpcov. Predovšetkým
id;;hocičo alebo id;name;exposure;eyecolor nie sú validné riadky.
|
Pri načítaní súboru by sa vám mohla zísť funkcia strtok(3) . Ak ste zabudli,
ako sa s ňou pracuje, pripomenúť si to môžete v
cvičení 5.
|
Agenti
Podobne ako svet, aj súbor s agentmi bude vo formáte CSV. Jeden riadok zodpovedá jednému agentovi, význam jednotlivých stĺpcov je nasledujúci:
id;route;is_vaccinated;immunity;is_infected
id <int>
-
Nezáporný celočíselný unikátny identifikátor agenta.
route <reťazec>
-
Agentova cesta svetom, čísla zodpovedajú identifikátorom jednotlivých miest v grafe. Z posledného vrcholu sa agent vracia na prvý. Cesta je zadaná ako postupnosť identifikátorov miest oddelených znakom
-
. Všetky vrcholy cesty musia vo svete existovať. Implementácia musí podporovať cesty s aspoň 256 vrcholmi. is_vaccinated <bool>
-
Reprezentuje zaočkovanosť agenta, používa sa v priebehu simulácie. Akceptované hodnoty sú
0
pre nezaočkovaného agenta a1
pre zaočkovaného. immunity <float>
-
Agentova prirodzená imunita, rovnako ju budeme využívať pri výpočtoch v jednotlivých kolách simulácie. Akceptované sú hodnoty z intervalu
[0, 1]
. is_infected <bool>
-
Číslo udávajúce počiatočný stav agenta, 0 znamená, že agent je zdravý, 1 značí, že u neho bola zistená prítomnosť vírusu.
Príklad súboru s agentmi:
$ cat agents.txt
1;4-1-3;1;0.5;0
2;5-1-3;1;0.5;0
3;5;1;0.2;0
4;4;0;0.2;1
5;5-2-3-1-3;0;0.5;1
Tak ako v prípade súboru so svetom si dajte pozor, aby bol dodržaný správny počet stĺpcov.
Priebeh simulácie
Naša simulácia bude pozostávať z jednotlivých iterácií a končí jedným z možných scenárov:
-
Neostal žiadny živý agent
-
Vírus už nemá žiadneho hostiteľa, teda sú všetci agenti vyliečení
-
Počet iterácií presiahne vopred stanovené číslo dodané prepínačom
--max-steps
.
Vo všetkých prípadoch je simulácia ukončená a od vášho programu sa očakáva, že vypíše výslednú štatistiku.
Priebeh iterácie
Fáza presunu
Agenti sa presúvajú z miesta na miesto určené ich cestou zo vstupného súboru. V tomto prípade je jedno, aké poradie presunu agentov zvolíte. Od vášho programu sa očákava, že po skončení tejto fázy sú všetci agenti na mieste, do ktorého sa podľa svojej cesty mali presunúť.
Fáza pokroku ochorenia
Priebeh nákazy u jednotlivca - jednotlivec zomrie, vylieči sa, alebo ostane nakazený.
Vzorec, podľa ktorého sa určuje, či daný agent zomrie:
roll = (double) rand() / RAND_MAX;
dead = roll - lethality < EPS;
V prípade, že je agent zaočkovaný, tak sa hodnota roll
násobí príslušnou
hodnotou vaccine_modifier
. EPS
(teda epsilon) je konštanta, ktorá vám pomôže sa vysporiadať s
nepresnosťou floating-point operácii. V prípade tejto úlohy bude nastavená na 0.01.
Vzorec pre vyliečenie agenta
roll = (double) rand() / RAND_MAX;
cured = roll - duration > EPS;
Najprv vyhodnocujeme, či agent prežil, až potom, či sa vyliečil.
roll pre úmrtie a roll pre uzdravenie sú dve nezávislé hodnoty.
|
Táto fáza prebieha postupne v jednotlivých miestach podľa ich číselného
identifikátora vzostupne od toho najnižšieho. V jednom mieste sa rovnakým
spôsobom vyhodnocujú jednotliví agenti, t.j. vzostupne od agenta s najnižším
id
. V prípade, že agent v tejto fáze zomrie, tak sa v ďalšej fáze neberie do
úvahy.
Fáza šírenia nákazy
Šírenie nákazy v aktuálnom mieste pobytu agentov, nákaza sa šíri spôsobom každý s každým - t.j. ak agenta nakazí iný agent, agent je nakazený a ďalej do priebehu nákazy nevstupuje. V prípade, že agenta nenakazí ani jeden zo zvyšných agentov, tak agent ostáva zdravý. Medzi agentmi, ktorí do tejto fázy prišli už nakazení, sa nákaza ďalej nešíri. Vírus sa šíri v prípade, že
roll = (double) rand() / RAND_MAX;
infected = exposure * roll * infectivity - immunity > EPS;
Ak je agent zaočkovaný, tak sa immunity
násobí príslušnou hodnotou
vaccine_modifier
.
Aby sme vedeli vašu implementáciu otestovať, je dôležité, aby sa táto fáza vyhodnocovala rovnako, ako v referenčnej implementácii. Šírenie začína v mieste s najnižším číselným identifikátorom a pokračuje vzostupne, rovnako ako v predošlej fáze. |
V jednotlivých miestach je poradie agentov jasne dané ich identifikátormi, iteruje sa vzostupne od agenta s najnižším identifikátorom.
Agenta môže nakaziť len agent, ktorý je sám nakazený. Nákaza sa šíri atomicky, takže v prípade, že sa agent nakazí v tomto kole a predtým bol zdravý, tak v tomto kole nákazu nešíri. Rovnako ho po nakazení už neskúšajú nakaziť ostatní infikovaní agenti.
V prípade, že sa v jednom mieste nachádzajú agenti s identifikátormi 1
, 5
,
12
, 42
a 1337
, a agenti 5
a 1337
sú nakazení, poradie vzájomnej výmeny
vírusu je nasledovné.
5 -> 1
5 -> 12 // infected
5 -> 42
1337 -> 1
1337 -> 42
Vyhodnotenie
Po skončení simulácie (jedným z troch vyššie uvedených spôsobov) váš program na štandardný výstup vypíšte nasledujúce informácie:
-
Seed, ktorý bol použitý počas behu programu
-
Informáciu o každom kroku, ktorý začal
-
Výsledok simulácie
-
Kumulatívnu štatistiku o prebehnutej simulácii:
-
celkový počet prenosov vírusu
-
počet obetí vírusu
-
počet živých ľudí po skončení simulácie
-
-
Miesto s najviac prenosmi vírusu
-
Celkový počet krokov simulácie
Formát je nasledujúci:
Random seed: 1337
<DETAILED INFO>
<RESULT>
Statistics:
Total infections: A
Total deaths: B
Number of survivors: C
Most infectious location:
<LOCATION>
Simulation terminated after N steps.
V prípade odsadenia vždy odsadzujte jedným znakom tabulátora. |
Kde <RESULT>
je jeden z možných scenárov:
-
Step limit expired.
- v prípade, že simulácia neskončila do zadaného počtu krokov -
Population is extinct.
- všetci agenti zomreli -
Virus is extinct.
- aspoň jeden agent je živý a žiaden agent nie je nakazený
A <LOCATION>
je:
-
- <PLACE_NAME>: <NUMBER_OF_INFECTED> infections
- ak existuje práve jedno mesto s najväčším počtom novo-nakazených agentov počas celého behu simulácie, t.j. miesto kde sa nákaza najviac šírila. -
Multiple
: v prípade, že najväčší počet nakazených zďieľajú aspoň dve miesta
V prípade, že nie je špecifikovaný prepínač --summary
, od vašej implementácie sa
očakáva, že bude v každom kole vypisovať nasledujúce informácie v mieste
<DETAILED INFO>
:
-
Zmenu stavu agenta, t.j. nakazený agent zomrel, alebo sa nakazený agent vyliečil
-
Informáciu, ktorý agent koho nakazil.
Pre iterácie S
a S + 1
vyzerá výstup nasledovne:
*** STEP S ***
Agent 1 has died at Hospital.
Agent 3 has recovered at Bar.
Agent 2 has infected agent 4 at School.
Agent 2 has infected agent 3 at School.
Agent 8 has infected agent 6 at Office.
*** STEP S + 1 ***
Agent 8 has infected agent 17 at Office.
V prípade, že váš program bol spustený s prepínačom --summary
, nevypisujte na
mieste <DETAILED INFO>
nič.
Prítomnosť prepínača --verbose
navyše do <DETAILED INFO>
pridá podrobné informácie
o náhodných hodoch, ktoré prebehli počas simulácie. Týmto sa rozumie:
-
v prípade vyliečenia nakazeného agenta sa ku výpisu pridá hodnota hodu a porovnanie s dobou infekčnosti
-
Agent 1 has recovered at Bar. (0.69 > 0.23)
-
-
v prípade úmrtia nakazeného agenta sa navyše pridá hodnota hodu a porovnanie so smrtelnosťou vírusu
-
Agent 1 (V) has died at Hospital. (0.69 < 0.80)
-
(V)
vynechávame v prípadoch, kde agent nie je zaočkovaný -
v prípade zaočkovania predstavuje
0.69
hod po aplikovaní efektu vakcíny
-
-
v prípade úspešného prenosu nákazy z agenta A na agenta B sa vypíše hodnota hodu, imunita agenta B, údaj o tom, či je agent B zaočkovaný, a lokácie v ktorej sa nachádzajú, ako aj porovnanie rollu s výsledkom
-
Agent A (R: 0.50) has infected Agent B (I: 0.15, V) at FI (E: 0.43). (0.19 > 0.18)
-
príklad predpokladá infectivity
0.9
-
hodnota immunity v nerovnosti je ovplyvnená silou vakcíny
-
v prípade, že agent B nie je zaočkovaný, sa V z výpisu vynecháva
-
Agent A (R: 0.50) has infected Agent B (I: 0.15) at FI (E: 0.43). (0.19 > 0.15)
-
R
predstavuje surový hod pred akýmkolvek násobením modifikátormi, medzitým čo hodnota v porovnaní predstavuje finálny hod
-
Všetky hodnoty zaokrúhľujte na 2 desatinné miesta nahor.
Požiadavky
Od vášho programu sa očakáva, že v prípade chyby korektne uvoľní všetky alokované zdroje a skončí s nenulovým návratovým kódom a príslušnou chybovou hláškou.
V prípade, že simulácia prebehne v poriadku, na konci vypíše súhrnnú štatistiku
o jej priebehu a skončí s nulovým návratovým kódom. Kontrolovať sa bude aj korektné
správanie prepínačov --summary
a --verbose
.
Váš program vypisuje všetky informácie na štandardný textový (prípadne chybový)
výstup. V prípade, že si chcete správanie otestovať proti referenčnej
implementácii, odporúčame si výstupy presmerovať do súborov, a tieto súbory
potom porovnať pomocou príkazu diff(1)
.