První série třicátého druhého ročníku KSP

Právě se k vám dostává první číslo jubilejního ročníku KSP – ano, KSP letos slaví 25 let své existence a toto kulaté číslo si určitě zaslouží pozornost.

Letos se můžete těšit v každé z pěti sérií hlavní kategorie na: 5 normálních úloh, z toho alespoň jedna praktická opendatová, seriál o zpracování dat jako 6. úlohu a kuchařku na nějaké zajímavé informatické téma hodící se k úlohám dané série.

Do celkového bodového hodnocení se z každé série stále započítává 5 nejlépe vyřešených úloh (tedy nemusíte vyřešit úplně všechny a i tak můžete dosáhnout na plný počet bodů). Také se vám body za úlohy přepočítávají podle vašeho služebního stáří – na přesnou definici se podívejte do pravidel na našem webu.

Také budeme zveřejňovat autorská řešení hned po skončení série – pokud nás pak při opravování napadnou nějaké komentáře k řešením od vás, tak je zveřejníme dodatečně.

Odměny & Na Matfyz bez přijímaček

Za úspěšné řešení KSP můžete být přijati na MFF UK bez přijímacích zkoušek. Úspěšným řešitelem se stává ten, kdo získá za celý ročník (této kategorie) alespoň 50% bodů. Za letošní rok půjde získat maximálně 300 bodů, takže hranice pro úspěšné řešitele je 150. Maturanti pozor, pokud chcete prominutí využít letos, musíte to stihnout do konce čtvrté série, pátá už bude moc pozdě. Také každému řešiteli, který v tomto ročníku z každé série dostane alespoň 5 bodů, darujeme KSP propisku, blok, placku a možná i další překvapení.

Termín odeslání Vašich řešení této série jest určen na 21. října 2019 v 8:00. Řešení můžete odevzdávat jak elektronicky, tak klasickou poštou na známou adresu.

Dotazy ohledně zadání můžete posílat na adresu ksp@mff.cuni.cz, nebo se ptát přímo na diskusním fóru KSP.

Odměna série: Každému, kdo vyřeší 4 úlohy alespoň na polovinu bodů, pošleme sladkou odměnu.

Zadání úloh

Hlídková loď se po dvou týdnech letu vyloupla z hyperprostoru a její výkonné senzory začaly zkoumat tuhle zapadlou hvězdnou soustavu, mezitím co jí z cívek motorů postupně vyzařovala zbytková energie přechodu do normálního prostoru. Na palubě neměla moc velkou posádku – pouhých deset členů – ale to by mělo na tuto misi bohatě stačit.

Místní kolonie se před šestnácti dny přestala ozývat, poslední zachycená zpráva hovořila o nějakých technických problémech. Proto taky z Antaraxu, nejbližší velké lidské základny, vyslali Hefaista jako rychlou servisní a hlídkovou loď, aby zjistila, co se děje.

Kapitánka Laren se otočila na svého komunikačního specialistu, jediné nepozemšťana v posádce: „Zaxi, vysílá základna něco alespoň na podsvětelné komunikaci?“ „Zkoumám skippere… moment, něco jsem zachytil… automatická zpráva, ale je nějaká zkomolená, zkusím ji vyfiltrovat.“


Praktická opendata úloha32-1-1 Zkomolené vysílání (9 bodů)


Hlídková loď Hefaistos zachytila několik zpráv od lidské základny v místní hvězdné soustavě. Vypadá to jako automatické zprávy, kde každá z nich byla vyslána dvakrát po sobě, ale závadou na vysílači obsahuje nějaký signál navíc.

Přesněji řečeno základna chtěla vyslat zprávu X (sestávají se jen z velkých písmen anglické abecedy), a to tak, že ji vyslala dvakrát zopakovanou za sebou, ale do tohoto řetězce se na náhodnou pozici vmísilo jedno písmenko navíc. Příkladem může být původní zpráva ABC a vysílání ABCAWBC.

Vaším úkolem bude samozřejmě co nejrychleji získat původní zprávu X, případně rozhodnout, že to nelze, či že to není jednoznačné.

Toto je praktická open-data úloha. V odevzdávacím systému si necháte vygenerovat vstupy a odevzdáte příslušné výstupy. Záleží jen na vás, jak výstupy vyrobíte.

Formát vstupu: Na prvním řádku vstupu bude číslo Z udávající počet zachycených zpráv. Pak bude následovat Z řádků, kde na každém z nich bude vždy uvedené nejprve číslo K udávající délku zachycené zprávy, pak mezera a poté samotná zpráva sestávající se z K velkých písmen anglické abecedy.

Formát výstupu: Na výstup vypište pro každou zachycenou zprávu (tedy celkově na Z řádků) text původní zprávy, případně text [chyba], pokud se zpráva nedá zrekonstruovat, nebo [neunikatni], pokud existuje více možných řešení.

Ukázkový vstup:
3
7 ABCAWBC
6 UVWXYZ
9 ABABABABA
Ukázkový výstup:
ABC
[chyba]
[neunikatni]

Řešení

„Mám to!“ zvolal náhle Zax a celá čtyřčlenná posádka můstku se mu nahrnula za konzoli, na které svítil nápis:

SELHANI STITU BEHEM IONTOVE BOURE, DUVOD
NEZNAMY. VETSINA KOLONISTU UKRYTA VE SKLADU 3.
ZADAME O POMOC.

Hefaistos byl na misi vybrán, protože jako jediná z lodí u Antaraxu byl uzpůsoben pro přistání na planetách bez jakékoliv pozemní podpory a navigace. Nebylo tedy o čem přemýšlet a kapitánka vydala rozkaz k navedení lodě na nejkratší přibližovací kurz k planetě a k přistání bez předchozího přechodu na orbitu.

Hefaistos se řítil k planetě akcelerovaný svým iontovým motorem, něco za polovinou své cesty se obrátil motory vzad a začal stejnou silou decelerovat tak, aby do atmosféry planety vstoupil přesně vypočtenou vstupní rychlostí.

Ve správný moment se zasunula většina vnějších aparatur na trupu, okna a trysky iontových motorů zakryly rozměrné tepelné štíty a manévrovací trysky otočily loď břichem dolů, aby začala brzdit třením o atmosféru. Byla to drsná jízda, ale na takovéto zacházení byla devadesátimetrová hlídková loď konstruovaná.

Během několika minut klesla rychlost natolik, aby mohly být tepelné štíty opět zataženy a pomocí atmosférických motorů zbrzděn zbylý pohyb. Pilot zručně zakroužil s lodí okolo základny a skrz velká panoramatická okna můstku se naskytl pohled na několik budov – byly vidět větší škody od iontové bouře, ale většina budov stále stála.

Hefaistos se pomalu snesl na plochu vedle jedné z větších budov. Přistávací vzpěry se vysunuly ze stále rozpáleného trupu a jejich masivní tlumiče zbrzdily dosednutí devítiset tun váhy lodě.

Vzduch na planetě byl podobný pozemskému, jen s velkou koncentrací pro člověka jedovatých sloučenin a s roční průměrnou teplotou okolo nuly. Výsadek s kapitánkou v čele se tak mohl vydat prozkoumat základnu jen v teplém oblečení a s dýchacími maskami – těžké nepohodlné skafandry tentokrát nebyly potřeba.

U vstupu do hangáru skladu číslo tři zjistili, že základna je bez hlavního zdroje energie. Bez něj se jim nepovede odemknout vnitřní dveře hangáru, aby se dostali dál dovnitř. Sklad tři měl sice nahoře u stropu záložní zdroj energie, ale očividně již vyčerpal své palivové články a nikdo asi nepřemýšlel, jak do něj dopravit nové palivové články, když byl hangárový jeřáb bez energie.

Kompatibilních palivových článků měl naštěstí Hefaistos jako servisní loď dost a dokonce vezl na palubě i malý pásový manipulátor. Výsadek se tedy rozhodl postavit si z různých krabic, palet a kontejnerů ve skladu jakousi rampu, po které by zvládli dopravit palivové články až nahoru.

Ilustrace: Hroch s jeřábem

Teoretická úloha32-1-2 Stavba rampy (12 bodů)


Technici by potřebovali postavit rampu z několika kusů krabic, které se nalézají vyskládané podél jedné ze stěn hangáru. Mají k tomu k dispozici pásový manipulátor, kterým vždycky mohou nějaké dvě krabice vysunout z řady a prohodit je. Ale čím vyšší a těžší krabice (váha krabice je přímo úměrná její výšce), tím náročnější je s ní manipulace a tím více energie na to manipulátor spotřebuje.

A jak má vypadat taková rampa, kterou chtějí postavit? Podobně jako schody – musí to být řada krabic, která na jedné straně bude začínat tou nejnižší z nich a na té druhé bude končit tou nejvyšší z nich.

Formálněji řečeno dostanete na vstupu zadané krabice tak, jak na počátku stojí v řadě, každá krabice bude zadaná svou výškou. Vaším úkolem bude krabice seřadit od nejmenší po největší tak, že jedinou povolenou operací bude prohození dvou libovolných krabic. Toto prohození bude stát tolik energie, jaký je součet výšek obou přesouvaných krabic. Vymyslete algoritmus, který najde postup, jak krabice prohazovat, aby na konci byly správně seřazené a celková potřebná energie byla co nejmenší.

Příklad: Mějme krabice výšek 1,4,2,3,5. Ty umíme seřadit se spotřebováním 11 jednotek energie: Nejprve prohodíme krabice 2 a 3 (to nás stojí 5 jednotek energie) a pak prohodíme krabice 4 a 2 (za 6 jednotek energie).

Upozornění: Důležitou součástí tohoto řešení je i důkaz, že váš postup skutečně vrací optimální strategii prohození.

Řešení

Komentáře

Palivové články zapadly na své místo a hlavní inženýr McCormack, balancuje na vršku improvizované rampy, zatáhl za páku. Záložní zdroj naskočil, ale v hangáru se rozsvítila pouze nouzová světla. Během několika sekund naskočil i řídicí panel vedle přetlakových dveří dál do útrob skladu, avšak jen v nouzovém režimu místního ovládání.

„Zůstaňte zatím tady, já a Drake…,“ kývla kapitánka na jednoho ze dvou mariňáků přidělených k posádce, „… se podíváme dovnitř a zkusíme najít kolonisty.“

Za přechodovou komorou následovala dlouhá chodba lemovaná po obou stranách menšími sklady. Na konci chodby se nalézal výtah a schodiště pokračující níž. Podzemní patro vypadalo obdobně, jenom na místě, kde se ve vrchním patře nacházel hangár, byly velké těžké tlakové dveře. Došli až k nim a kapitánka je zkusila otevřít. Ovládání zobrazilo jen sérii chyb a pak se restartovalo, ale vzápětí se z interkomu ozval lidský hlas: „Kdo jste a co tu děláte?“

„Jsem kapitánka Laren La Boy, servisní a hlídková loď Hefaistos, přiletěli jsme z Antaraxu po ztrátě spojení s vámi před šestnácti dny.“ „Tak rychle?“ podivil se hlas. „No, Hefaistos má hyperprostorový pohon čtvrtého stupně, proto taky vyslali nás, byli jsme u Antaraxu nejrychlejší loď.“

To hlasu asi stačilo a dveře se pomalu otevřely. Naší dvojici se naskytl pohled na místnost plnou nepořádku, přikrývek a hromady prázdných kontejnerů nouzových zásob. Mezi tím vším polehávalo odhadem tak třicet lidí.

„Nemáte něco k jídlu?“ přišoural se malý kluk. „Jo tady, berte,“ sáhl Drake do svého batohu a vytáhl několik balení energetických tyčinek s čokoládou, které tam měl v očekávání něčeho podobného. Jenom trochu podcenil počet.

Kapitánka si šla promluvit s ředitelem kolonie stranou a Drake mezitím pozoroval, jak se kolonisté pustili do konzumace tyčinek – vycházela tak jedna tyčinka na dva kolonisty…


Teoretická úloha32-1-3 Čokoládová tyčka (11 bodů)


Dva hladoví kolonisté mají dohromady jednu čokoládovou tyčku a každý by z ní chtěl sníst co možná nejvíce. Tyčka je rozdělená na různě velké dílky a každý dílek lze ohodnotit nějakou jeho energetickou hodnotou. Oba kolonisté se postupně střídají v ulamování dílků, ale vždy mohou ulomit jenom jeden krajní dílek (takže, s výjimkou posledního tahu, mají vždy právě dva dílky na výběr).

Tyčinka je zadaná jako seznam energetických hodnot jednotlivých dílků. Spočítejte pro zadanou tyčinku s D dílky strategii pro prvního kolonistu tak, aby získal dílky dohromady s co největší energetickou hodnotou. Předpokládejte, že druhý kolonista bude vždy hrát optimálně.

Váš algoritmus počítající strategii by zároveň měl doběhnout v rozumně krátkém čase (exponenciální čas vzhledem k D už je určitě příliš pomalý).

Příklad: Pro tyčinku s hodnotami 5,15,3,1 je pro prvního kolonistu nejlepší vzít v prvním tahu dílek s hodnotou 1, i když by mohl vzít i dílek s hodnotou 5 – pokud vezme při prvním tahu dílek s hodnotou 1, tak získá celkově 16, pokud by ale v prvním tahu vzal dílek s hodnotou 5, tak při optimálních tazích druhého kolonisty by odešel nejvýše s dílky v hodnotě 8.

Ilustrace: Hroch pojídající kostičky

Řešení

Komentáře

Během následující hodiny distribuovali mezi kolonisty několik beden nouzových zásob a mezitím se dozvěděli o událostech, které se zde staly – vše začalo nebývale silnou iontovou bouří, během které vysadila komunikace. To by ještě nebylo nic divného, jenže pak začaly jeden po druhém selhávat spolu vůbec nesouvisející systémy základny, a nakonec selhal i několikrát zálohovaný magnetický štít. Kolonisté se uchýlili do bezpečí krytu pod skladem číslo tři, ale ze sedmačtyřiceti kolonistů jich třináct během bouře zmizelo neznámo kam. Po týdnu vysadil i záložní zdroj budovy (i když podle jejich odhadů měly články vydržet přinejmenším tři měsíce) a nakonec je objevil až výsadek z Hefaista.

Kapitánka nařídili oběma mariňákům zahájit průzkum celého areálu základny a spolu s hlavním inženýrem a několika techniky z řad kolonistů se vydala k hlavní budově základny. Po připojení energetického vedení z Hefaista sice budova oživla, ale jen v nouzovém režimu – zjistili, že centrální počítačové jádro je vymazané. Naštěstí na základně byla na holografických médiích uskladněna i kopie operačního systému základny. Jenom její instalace chvíli zabere.


Teoretická úloha32-1-4 Instalace OS (9 bodů)


Operační systém pro hlavní počítač základny se sestává z velkého počtu instalačních balíčků, které jsou nějakým způsobem rozdělené na dvou holografických médiích.

Cílem je instalovat všechny balíčky, ale některé balíčky se nedají instalovat, dokud nejsou nainstalované nějaké jiné (například program pro ovládání dveří potřebuje knihovnu pro ovládání servomotorů). Obecně každý balíček může mít závislost na libovolném (i nulovém) počtu jiných balíčků. Navíc je slíbeno, že závislosti nikdy netvoří cyklus (tedy vždy existuje způsob, jak se dá operační systém nainstalovat).

Máme zadaná čísla k1 a k2, která značí počty instalačních balíčků na jednotlivých médiích. Instalační balíčky jsou rozděleny hezky popořadě, tedy na prvním médiu jsou balíčky s čísly 1, 2, …, k1 a na druhém balíčky s čísly k1+1, k1+2, …, k1+k2. Celkový počet instalačních balíčků je tedy k1+k2. Dále známe Z závislostí, tedy např. že balíček 15 závisí na balíčku 38, a ten tedy musí být nainstalován dříve.

V mechanice pro čtení holografických médií může být v jednu chvíli pouze jedno médium. Z něj můžeme nainstalovat jakékoliv balíčky, které na ničem nezávisí nebo závisí pouze na balíčcích, které už máme instalované. Pak musíme médium vyměnit za druhé, abychom mohli pokračovat v instalaci.

Pro zadané závislosti balíčků a jejich rozdělení na instalační média najděte nejmenší nutný počet prohození instalačních médií, aby se nám povedlo instalovat všechny balíčky.

Příklad: Zaveďme si značení a→b znamenající, že balíček a závisí na balíčku b (tedy balíček b musí být instalovaný první). Pak pro holografická média s počty balíčků 33 (tedy média {1,2,3}{4,5,6}) a pro závislosti 2→6, 3→55→2 potřebujeme 4 kroky: Nejdříve vložíme druhé médium a nainstalujeme balík 6, poté vložíme první médium a nainstalujeme balíky 1 a 2, poté opět vložíme druhé médium a nainstalujeme balíky 4 a 5 a nakonec vložíme opět první médium a nainstalujeme poslední balík 3.

Řešení

Po úmorném procesu instalace se povedlo hlavní počítač základny opět nahodit. Postupně se začaly připojovat i jednotlivé budovy a po další hodině snahy se rozběhl i fúzní reaktor a základna tak přestala být závislá na „pupeční šnůře“ od Hefaista. Poškození základny od bouře bylo značné, ale nic neopravitelného. Nic však nevysvětlovalo to množství poruch, které se vyskytly současně s bouří.

Například hlavní komunikační anténa se prostě propadla do země a zbortila se jako věž ze sirek, generátor magnetického štítu vybuchl i s půlkou budovy a třeba záložní generátor v hlavní budově zmizel úplně.

V troskách budov se povedlo nalézt čtyři oběti bouře, ale po zbylých devíti kolonistech nebylo ani vidu ani slechu. Mariňáci se tedy rozhodli vystoupat do blízkých vrcholků táhnoucích se okolo základny, aby získali větší rozhled.


Teoretická úloha32-1-5 Výhled z vrcholků (10 bodů)


Dvojice mariňáků vystoupala na jeden vrcholek, aby měla co nejlepší rozhled do krajiny. Současný výhled jim ale nestačí a rádi by vystoupali na nějaký vyšší vrcholek – nechtějí však přitom sejít moc nízko.

Můžeme si představit mapu vrcholků jako čtvercovou síť obsahující na každém políčku výšku v metrech. Mezi sousedními políčky se můžeme pohybovat do všech 8 směrů. Máme označené políčko, na kterém jsme, a chceme si naplánovat cestu na nějaké políčko s větší výškou.

Během cesty budeme muset asi projít přes nějaká další políčka, ale chceme, aby minimální výška, ve které se vyskytneme, byla co možná nejvyšší (neboli chceme maximalizovat minimální výšku, ve které se cestou ocitneme). Pokud takových vyšších míst se stejnou minimální výškou během cesty existuje víc, chtěli bychom najít to nejvyšší možné.

Vymyslete algoritmus, který něčeho takového dosáhne.

Příklad: Mějme výšky vrcholků jako v tabulce níže. Nechť stojíme na vrcholku s výškou 5. Na vrcholek 9 bychom se uměli dostat tak, že bychom naklesali do výšky 2, ale na vrcholky 7 a 8 se umíme dostat tak, že naklesáme jenom do výšky 4 a přejdeme po hřebeni. Žádná lepší možnost tu neexistuje, takže naše zadání splňuje nejlépe vrcholek s výškou 8, do kterého cestou projdeme přes nejnižší výšku 4. Jedna z možných cest je vyznačena.

  2 2 1 2 1
  2[5]3 7 2
  2 1[4]4 1
  9 1 1[8]1

Řešení

„Skippere, tady Drake… našli jsme něco zajímavého. Směrem na jih od základny jsou v písku vidět stopy terénního pásového transportéru. Nejsou vůbec zafoukané bouří, takže budou maximálně čtyři dny staré.“

Kapitánka Laren se podívala tázavě na ředitele základny. „My jsme to určitě nebyli, od výpadku nouzového zdroje jsme byli všichni uvězněni v tom krytu pod skladem číslo tři,“ odpověděl ředitel.

Kapitánka se zamyslela a pak vydala rozkaz…

* * *

Letos experimentujeme s příběhem k úlohám, který můžete sami ovlivnit. Co by podle vás měla kapitánka Laren La Boy udělat? Zahlasujte do 7. říjnaanketě.

První díl příběhu pro vás sepsal

Jirka Setnička


Seriálová úloha32-1-6 Data na OSMou (16 bodů)


Pokud vám připadá už trochu nuda, že v KSP máme jenom úlohy s umělými daty bez nějakého reálného významu, tak jsme právě pro vás připravili tento seriál. Letošní seriál se totiž bude pokoušet ukázat vám práci s různými zajímavými zdroji velkých dat. Zaměříme se taky na různé nástrahy – co když se vám data nevejdou do paměti, co když se vám odzipovaná data nevejdou ani na disk, jaké je to spustit si program přes noc, abyste ráno zjistili, že spočítal výsledek, ale spadl na posledním řádku, … a podobně.

Opravdové mapy

V prvním dílu se naučíme pracovat s mapami z projektu OpenStreetMap, na což navážeme ještě v dílu druhém. V dalších dílech se pak podíváme na nějaké další zajímavé zdroje dat.

Projekt OpenStreetMap je taková mapová Wikipedie – je to online mapa podobná mapám od Google a nebo Seznamu, akorát jí může editovat každý. Reálně je (narozdíl od Wikipedie) značná část dat převzatá z jiných zdrojů, ale pořád jsou volně dostupné a můžete tam zanést své oblíbené zkratky přes les :)

OSM můžeme využívat jako běžný uživatel a hledat si na https://osm.org/ třeba kde bude další soustředění. Ale narozdíl od Google nebo Seznam map si můžeme stáhnout i strojově zpracovatelná zdrojová data a něco si nad nimi spočítat.

To je přesně to, co teď uděláme, protože si přeci chceme něco naprogramovat. Budeme používat data ve formátu XML, která se dají z OSM získat. Tady se pokusíme vysvětlit strukturu a smysl dat a ukázat nějaké obecné principy. Detailnější technické informace o tom, kde si data stáhnout a jak je načítat, se pak můžete dočíst na webové stránce seriálu.

Formát dat

Pokud očekáváte, že se nám popis vstupního formátu pro úlohu vejde na jeden odstavec, tak je na čase si odvyknout. V praxi tomu tak moc často nebude a OSM data nejsou výjimkou.

Nicméně nebude to nic hrozně komplikovaného. V principu datový soubor obsahuje jen tři typu objektů: vrcholy, cesty a relace.

1. Vrcholy

Vrcholy (node) jsou nejzákladnější objekty v OSM a jenom ony nesou informace o poloze. Vrchol je zkrátka nějaký bod na Zemi zadaný pomocí zeměpisných souřadnic (šířka a délka), ze kterého můžeme konstruovat jiné složitější objekty, například cesty.

Nejdůležitější vlastnosti vrcholu jsou poloha a identifikátor. Polohu najdete jako souřadnice v atributech lat a lon, identifikátor je číslo v atributu id. Upozorňujeme, že vrcholů je na světě přes 5 miliard, takže nestačí 32-bitové celé číslo. Polohu je pro dobrou přesnost také lepší ukládat do 64-bitového desetinného čísla.

Ale vrcholy nemusíme používat jenom pro stavbu složitějších objektů – i on samotný může být něčím významný. Proto můžou mít vrcholy tagy – další informace, které se k nim vážou. Tag je dvojice klíče a hodnoty a může v něm být skoro cokoliv.

Tagy tu opravdu nemáme prostor vysvětlit všechny. Proto ty, kterým váš program nebude rozumět, můžete tiše ignorovat. Jejich význam ale bývá poměrně intuitivní, uvedeme několik příkladů:

  • Tag name je jméno objektu (třeba jméno vesnice nebo jméno restaurace).
  • Tag source značí, odkud se data vzala.
  • Skupina tagů addr:street, addr:postcode, addr:city a addr:housenumber nám říká adresu bodu.

Ukázka reálného bodu z OSM:

<node id="2578544869" visible="true" version="4"
 changeset="71085651"
 timestamp="2019-06-10T03:14:47Z"
 user="itamas80" uid="1719518"
 lat="50.0435083" lon="14.4031207">
    <tag k="bus" v="yes"/>
    <tag k="highway" v="bus_stop"/>
    <tag k="name" v="Pod Žvahovem"/>
    <tag k="name:de" v="Schwahower Grund"/>
    <tag k="public_transport" v="platform"/>
</node>

2. Cesty

Cesty (way) jsou skupiny bodů. Dalo by říci, že vlastně tvoří hrany grafu, ale v OSM se cesty používají třeba i na vyznačení ploch, vodních toků nebo hranic obcí (pak často mluvíme o polygonech namísto o cestách). Cesta tedy není vždy něco, po čem se dá chodit, ale něco co se skládá z více bodů. Body jsou naše známé vrcholy, cesta se na ně odkazuje pomocí elementu <nd>.

Cesty někdy značí plochy a v takovém případě začínají a končí stejným bodem.

Jak ale poznáme reálný význam cesty? Podobně jako vrcholy můžou mít cesty libovolné tagy. Například tag name bude obsahovat pravděpodobně jméno ulice a tag highway nám již svou přítomností říká, že se jedná o nějakou cestu, a jako svoji hodnotu bude mít typ této cesty (tedy jestli je to pěšina nebo dálnice – třeba highway=footway je chodník pro pěší a highway=residential je normální ulice vedoucí k domkům).

Ukázka cesty tvořící uzavřený polygon (v tomto případě nějakou garáž):

<way id="59584456" visible="true" version="2"
 changeset="38311484"
 timestamp="2016-04-05T08:39:44Z"
 user="JandaM" uid="2169558">
    <nd ref="739135731"/>
    <nd ref="739135841"/>
    <nd ref="739135871"/>
    <nd ref="739135899"/>
    <nd ref="739135731"/>
    <tag k="building" v="garage"/>
    <tag k="building:ruian:type" v="18"/>
    <tag k="ref:ruian:building" v="49847236"/>
    <tag k="source" v="cuzk:ruian"/>
</way>

3. Relace

Posledním typem dat v OSM je relace (relation). Relace se nevyužívají tak moc jako cesty a vrcholy, ale často také nesou užitečné informace. Relace je vlastně skupina jiných objektů – cest, vrcholů a nebo dalších relací. Například když se podíváme na tramvajovou trať, můžeme si všimnout, že koleje jsou v relacích podle toho, jaké linky na nich pravidelně jezdí. Existuje tedy relace pro pravidelné linky hromadné dopravy. Drobný problém je, že se linky mění docela často a v mapách jsou tak často neaktuální nebo nepřesné informace.

Další použití relací jsou velké oblasti, které jsou složeny z mnoha cest – těm říkáme multipolygony. Tímto způsobem najdete například zakódované hranice obcí nebo městských částí, některé lesy a vodní plochy. Hlavní výhodou oproti cestě je, že oblasti můžou být tvořeny několika mnohoúhelníky, případně v sobě můžou mít díry – vodní plochy v sobě můžou mít ostrovy, politické oblasti nejsou vždy souvislé.

Detailněji si multipolygony můžete nastudovat na OSM Wiki. Aby to nebylo tak komplikované, tak se budeme zabývat jen těmi relacemi, které jsou souvislé a nemají díry. Pak stačí z relace vytáhnout všechny cesty, uspořádat je do „kruhu“ a máme mnohoúhelník. Pozor na to, že typicky nebude konvexní a může mít všechny možné divné tvary.

* * *

Význam všech tagů používaných v mapách si můžete najít na OSM Wiki, například si lze najít všechny možné hodnoty pro tag highway.

Pokud si chcete prohlédnout kus mapy trochu vizuálněji, než prohlížením XML souboru v textovém editoru, můžete tak učinit na webu https://osm.org/: Přibližte si kus mapy, který vás zajímá, a nahoře se přepněte do „Edit Edit with iD“. Tím se dostanete do editoru mapy, ve kterém se dají rozkliknout všechny objekty. Když kliknete na cestu nebo vrchol, v levém panelu se dole zobrazí seznam všech tagů.

Úlohy obecně

Úlohy budeme počítat nad několik různými výřezy z OSM. Data z OSM se dají volně stáhnout v různých formátech, nejčastěji jako gzipovaný XML soubor s příponou .osm.gz, bzipovaný XML soubor s příponou .osm.bz2 nebo jako PBF binární soubor s příponou .pbf. Servery, ze kterých se dají stáhnout, i nějaké detaily všech formátů a jejich parsování jsme shrnuli na webové stránce seriálu.

My v úlohách budeme pracovat s gzipovanými XML soubory, protože práce s XML nám přišla pro účely seriálu výhodnější a protože knihovny pro gzip jsou v programovacích jazycích na lepší úrovni, než knihovny pro práci s bzip2.

Normálně byste si při práci s OSM asi stáhli nějaký poslední týdenní export z nějakého z veřejných serverů, ale abychom si byli jistí, že pracujeme nad stejnými daty (a že zrovna třeba cesta s nějakým ID náhodou nezmizela), tak jsme pro vás vystavili na našem webu konkrétní výřezy tří oblastí:

  • Evropa – velká testovací data, asi 43 GB zkomprimovaného XML (392 GB v nekomprimované verzi).
  • Brno – malá testovací data, asi 20 MB zkomprimovaného XML (186 MB v nekomprimované verzi).
  • Hrochův Týnec – velmi malá data pro ověření vašeho řešení, prozradíme vám u nich výstup našeho řešení.

Doporučujeme si nejdříve řešení otestovat na menším vstupu, protože nad celou Evropu to nedoběhne rychle. Také doporučujeme nenechávat řešení na poslední neděli, protože by některá řešení nemusela doběhnout (naše odladěné řešení třetího úkolu pro celou Evropu běží přes 9 hodin).

Každý úkol od vás budeme chtít vyřešit na malých (Brno) i velkých (Evropa) datech. Za vyřešení na malých i velkých datech získáte za úkol plný počet bodů, za vyřešení jenom na malých datech získáte polovinu bodů.

A co nám máte vlastně odevzdat jako řešení? Odevzdávete prosím zip archiv, který bude obsahovat:

  • Krátký slovní popis, jakým způsobem jste přistupovali ke které úloze a třeba jak vám to přišlo těžké.
  • Výsledek pro každou úlohu pro malá i velká data (pokud je to jedno číslo, tak se dá klidně napsat do slovního popisu; jestli je to seznam IDček nalezených objektů, tak raději do samostatného textového souboru; obrázek jako obrázek).
  • Zdrojový kód programu, který jste použili výpočet pro řešení.
  • Popis jak dlouho trvalo úlohy spočítat a na jak výkonném hardware (typ, počet jader a frekvence procesoru, množství paměti) – čas se dá změřit třeba vypsáním času na začátku a na konci programu, případně na Linuxu třeba příkazem time.

A nyní už k samotným úkolům a k několika principům velkých dat okolo nich…

Streamové parsování

Občas se nám načtená data nevejdou do paměti (třeba v případě našeho velkého výřezu Evropy – pochybujeme, že někdo z vás má v roce 2019 doma stroj s 390 GB operační paměti na nekomprimovaná data… a ani 45 GB ve zkomprimované variantě asi většina z vás do paměti také nenacpe). To při zpracování velkých dat není vůbec nevšední věc a potkáme se s ní docela často.

Jak si s tím poradit? Nejlepší bude skrz data jenom projít a cestou zpracovat těch několik věcí, které nás zajímají. Takovému způsobu procházení se říká streamové a třeba na spočítání počtu vrcholů v celé mapě nepotřebujeme skoro žádnou paměť – do paměti vždy načteme jenom jeden XML tag, podíváme se, jestli je to node, a pokud ano, tak přičteme k nějakému počítadlu plus jedna.

Nejlepší je, že se ve většině programovacích jazyků dá lehce vrstvit několik streamových zpracování za sebou. To využijeme právě u našich dat, kde za sebe budeme potřebovat navrstvit streamový „odzipovávač“ a streamové parsovátko XMLka. Pak můžeme našemu programu předhodit přímo .osm.gz soubor a když v programu zavoláme funkci na naparsování dalšího XML tagu, tak to může pod kapotou vypadat třeba takto:

  • Zavoláme funkci getNextTag()
  • Funkce getNextTag() má u sebe buffer, do kterého postupně plní byty. Dokud buffer neobsahuje celý validní XML tag, tak v cyklu volá funkci gzip.getNextByte() a postupně připisuje do bufferu další a další znaky. Ve chvíli, kdy je tag načtený celý, tak ho vrátí a odmaže si ho z bufferu.
  • Funkce gzip.getNextByte() má u sebe buffer odzipovaných dat, které vrací po jednotlivých bytech. Ve chvíli, kdy je buffer prázdný, tak načte ze souboru na disku další chunk, který může „odzipovat“ a opět si tím naplnit buffer.

Ukázka tohoto postupu je v ukázkových programech na stránce s technickými detaily na webu.

Úkol 1 [3b]

Pojďme si nabyté znalosti zkusit na něčem jednoduchém. Zajímalo by nás, kolik je na mapě unikátních názvů ulic.

Přesněji řečeno, najděte si v Brně a nebo v Evropě všechny cesty, které mají (neprázdné) tagy highway a name. Pak spočítejte, kolik unikátních hodnot name se tam vyskytuje (názvy lišící se jenom ve velikosti písmen nechť jsou pro naše účely různé názvy). Toto číslo je řešením úkolu.

Pro Hrochův Týnec naše řešení našlo 16 různých názvů ulic (včetně názvu „lávka (zákaz vstupu)“, což je sice chybný název podle OSM – zákaz vstupu by se měl vyjadřovat jinak – ale v datech je, a tak ho počítáme).

Možná si říkáte, jestli bychom nemohli spočítat, kolik je na mapě ulic (včetně těch duplicitních názvů). Samozřejmě mohli, ale není to tak jednoduché – ulice totiž často nejsou jedna cesta, ale je to několik cest se stejným jménem, které jsou akorát spojené v nějakých vrcholech. Někdy jsou ulice rozdělené na více cest bez závažného důvodu, ale někdy se dokonce větví a cyklí a pak už by jednou cestou reprezentovat ani nešly. Proto je potřeba před počítáním nejdříve seskupit rozštěpené ulice a to není tak jednoduché. Ale rozhodně to není nemožné, tak to klidně zkuste :)

Více průchodů

Občas nám jeden průchod daty nestačí. Typickým příkladem v OSM je, když potřebujete získat vrcholy cest s nějakým tagem. Dokud ale nemáte nalezené ony cesty, ani nevíte, které vrcholy vás budou zajímat. A pamatovat si všechny vrcholy v paměti také nelze. Jak si poradíme s tímto?

Nejjednodušší přístup je asi zdrojový soubor projít vícekrát. Při prvním průchodu si poznamenáme IDčka všech objektů, které by nás zajímaly (mohou to být právě vrcholy nějaké cesty), a pak se vrátíme na začátek souboru. Této operaci se většinou říká seek, ale ne všechny vrstvy našeho streamového zpracování musí tuhle operaci podporovat (typicky archivační vrstvy mají se seekem problémy kvůli svému vnitřnímu stavu). Ale postup zavřít původní soubor, otevřít ho a znovu ho obalit gzip streamerem a XML parserem bude fungovat asi ve všech jazycích.

Při druhém průchodu už poté při na načítání objektů můžeme kontrolovat, jestli jsou to pro nás zajímavé objekty a kdyžtak si je uložit do paměti (když těch zajímavých objektů není miliarda) nebo je nějak jinak zpracovat.

Vizualizace

Občas nejlepší způsob, jak se podívat na mapová data, není číst hromadu čísel ze standardního výstupu, ale nakreslit si nějaký obrázek. Ostatně když se díváte třeba na OSM na webu jako uživatel, tak právě vidíte nějaké vyrenderované výsledky. To už je ale docela komplexní úloha a jak vykreslit mapu, aby byla dobře použitelná, je už více otázka kartografická, než programátorská.

Ale i nějaké mnohem jednodušší vizualizace nám mohou hodně pomoci při zkoumání nějakého aspektu – mnohdy jeden obrázek vydá za tisíce slov. Pojďme si zkusit nakreslit třeba nějakou heatmapu.

Heatmapa je obecně znázornění velikosti nějakého jevu v nějaké oblasti (například množství tepla, odtud i ten název). Nejčastěji se vyrábí tak, že si určíte oblast (pro nás to bude vždy celý datový soubor), ten si rozsekáte na stejně velké čtverečky a pak procházíte data a poznamenáváte si, kolik je ve kterém čtverečku věcí, které vás zajímají. Nakonec každý čtvereček bude prezentovat jeden pixel na výsledném obrázku a čím více věcí v odpovídajícím čtverečku, tím tmavší pixel bude.

Při skládání bodů do pixelů obrázku se pravděpodobně chytnete do drobé pasti – Země není placka a souřadnice bodů v OSM jsou souřadnice na elipsoidu. Když je přepočítáme na rovinu tím naivním způsobem, že s nimi počítáme jako se souřadnicemi v rovině, tak dostaneme nějakým způsobem nepřesnou mapu. Dokud kreslíme jednoduchý diagram pro Českou Republiku, tak je to jedno, ale v rámci celé Evropy už je to docela rozdíl.

Ale pro naše použití se teď s touto primitivní projekcí spokojíme – náš program nebude první, který nebude řešit nějaké komplikované projekce, a aspoň něco by ve výsledném obrázku poznat být mělo i tak. Ale je dobré počítat s tím, že čím severnější oblasti mapa obsahuje, tím je zkreslení touto projekcí horší.

Úkol 2 [5b]

Co tak si nakreslit hustotu zástavby? Definice „hustoty zástavby“ bude sice trochu sporná, ale pojďme prostě spočítat počet domů na území a vykreslit to jako obrázek.

Jak na to? Dům je typicky cesta s tagem building. Občas v mapách sice nějaké domky chybí, nebo je místo nich jenom jeden bod s adresou, ale tak ty prostě nebudeme počítat. Podle toho jak budeme chtít velké rozlišení si mapu rozdělíme na čtverečkovou mřížku a pro každý čtvereček napočítáme počet domů, které jsou uvnitř.

Protože cesta ohraničující dům je tvořena více vrcholy, budeme jako polohu domu pro zjednodušení brát polohu jeho prvního vrcholu. To nám sice může občas dům těsně na hranici jednoho čtverce přesunout do vedlejšího, ale ve větším měřítku se takové chyby vyprůměrují.

Pro Brno vyrobte obrázek široký 1000 pixelů, pro Evropu vyrobte obrázek široký 4000 px, výšku určete proporcionálně. Barevnost si určete sami (škála ani nemusí být lineární, pokud se vám tak heatmapa bude líbit více, jenom nám v případě nějaké netriviální barevnosti přibalte legendu s vysvětlením, co které odstíny znamenají).

Ještě by se vám mohlo hodit vědět, že v Evropě je na naší mapě OSM zhruba 170 milionů domů – takže si spočítejte, kolik informací o každém domě si můžete pamatovat, abyste se ještě vešli do paměti svého počítače.

Heatmapa Hrochova Týnce by nebyla příliš zajímavá a heatmapu Brna máte za úkol spočítat vy, takže tady máte pro ukázku heatmapu ČR – od černé přes červenou až po žlutozelenou roste hustota budov (a všimněte si také deformace způsobené tím, když bereme zeměpisnou šířku jako souřadnicové osy bez jakéhokoliv přepočtu).

Heatmapa počtu budov v ČR

Pokud si právě říkáte, že nemáte tušení, jak pomocí svého oblíbeného jazyka vyrobit obrázek, tak nezoufejte, pravděpodobně to bude docela jednoduché. Nejlepší možnost je popsat svůj problém do Googlu a najít na obrázky vhodnou knihovnu (nebo zjistit, že je k dispozici ve standardní knihovně). Pak bude asi jenom potřeba zavolat funkci „vyrob obrázek“ nějaké velikosti a pak mu nastavovat barvy jednotlivých pixelů (a pozor na to, v jakém rohu je počátek souřadnic). Pokud by to nijak rozumně nešlo, tak můžeš zkusil využít textový formát PGM. Sice bude obrázek obludně velký, ale jde otevřít například v GIMPu a pak uložit jako normální PNG.

Trocha geometrie

Občas je dobrý nápad umět vybrat mapy jenom body, které leží v nějakém zajímavém území (v řeči OSM řekněme v polygonu), třeba na území nějakého státu (třeba když vyrábíme OSM export tohoto státu).

Jak jsme již napsali výše, dokud jsou oblasti malé, jdou popsat jedinou cestou (kde poslední a první bod jsou stejné). Ale v případě větších oblastí už není praktické mít cestu s milionem bodů, ale spíše chceme říct, že je oblast ohraničená těmito padesáti cestami.

Takovéto větší polygony jsou v OSM popsané relacemi, které právě obsahují ony cesty (a občas i nějaký bod, například administrativní bod té oblasti, když jde třeba o město). Pozor na to, že cesty na sobě po obvodu nemusí navazovat (mohou být náhodně pomíchané), OSM to nijak nezakazuje a je na programech, aby si s tím pak poradily.

V OSM může relace představovat také takzvaný multipolygon, který může mít i díry – například rybník s ostrovem. V takovém případě je to relace mnoha cest, kde některé mají roli outer (to jsou normální hranice) a inner (to jsou „díry“). Ještě se můžete setkat se superrelacemi, což jsou relace obsahující relace, které teprve obsahují cesty. Ale oběma těmto složitějším případům se zatím vyhneme.

V momentě, kdy se nám povede načíst polygon (na což může být potřeba více průchodů), už můžeme aplikovat například kuchařku o geometrii, případně článek z Wikipedie a můžeme dělat zajímavé věci.

Úkol 3 [8b]

Pojďme si zkusit najít pítka v následujících oblastech:

Obě oblasti jsou „slušné“ polygony určené relací, která obsahuje přímo cesty a neobsahuje žádné díry.

Zdroj pitné vody se pozná tak, že má nastavený tag amenity=drinking_water (tedy „toto je pítko“) a nebo má nastaveno drinking_water=yes (což může být například i na veřejném WC, kde mají pitnou vodu). Odevzdejte nám seznam pítek v daných oblastech jako seznam identifikátorů vrcholů, kde se můžeme napít, na každém řádku jedno číslo.

A to je prozatím vše. Budeme se těšit na vaše řešení a mezitím si pro vás nachystáme další zajímavé věci o OSM do druhé série :-)

Jirka Setnička & Standa Lukeš

Řešení

Komentáře