This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Žilinskaacute univerzita v Žiline Stredoeuroacutepsky technologickyacute inštituacutet
je relaacutecia nad premennyacutemiSj = rozsah(Cj)[1] Inyacutemi slovami možno povedať žeRSj
je podmnožina karteziaacutenskeho suacutečinu deničnyacutech obo-
rov premennyacutech z Sj [1]1
Riešeniacutem probleacutemu P je n-tica A = 〈a1 a2 an〉 takaacute že platiacute ai isin Di a každeacute ohraničenie
Cj je splneneacute tj pre projekciu A do rozsahu Sj platiacute relaacutecia RSj
1Ku relaacuteciaacutem a karteziaacutenskemu suacutečinu možno pozrieť viac v priacutelohe A
middot 1 middot
Obr 21 Hra Sudoku Obr 22 Hra Sudoku ndash riešenie
21 Formulaacutecia hry Sudoku ako CSP
Hra Sudoku je dobryacutem priacutekladom probleacutemu spĺňania ohraničeniacute Pozostaacuteva z hracieho poľa ur-
čityacutech rozmerov ndash najčastejšie 9times 9 Pole je navyše rozdeleneacute na 9 štvorcov rozmerov 3times 3 (viď
Obr 23) Každeacute poliacutečko mocircže obsahovať čiacuteslo od 1 po 9 Na začiatku hry suacute niektoreacute poliacutečka už
vyplneneacute ndash ostatneacute treba doplniť tak aby boli splneneacute predpiacutesaneacute podmienky
bull Dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9
bull Žiadne čiacuteslo v raacutemci toho isteacuteho stĺpca sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho riadku sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho štvorca sa nesmie opakovať viackraacutet
Ilustraacutecia hracieho poľa je na Obr 21 Vyplneneacute hracie pole je na Obr 22
Ak maacuteme Sudoku opiacutesať ako probleacutem spĺňania ohraničeniacute premenneacute X buduacute tvoriť hodnoty
jednotlivyacutech poliacutečok (dokopy ich bude 9times 9) Deničnyacute obor každej z nich je D = 1 2 9Ak jednotliveacute premenneacute usporiadame do matice mocircžeme ich preindexovať ako xmk kde m
je čiacuteslo riadku a k je čiacuteslo stĺpca Ak potom uvažujeme napriacuteklad ohraničenie pre prvyacute riadok
vieme že pre jeho rozsah platiacute Sr1 = x11 x12 x19 tj ohraničenie zahŕňa praacuteve premenneacute
z prveacuteho riadku
Relaacuteciu pre prvyacute riadok mocircžeme denovať nasledovne
RSr1 = x isin D9|x1i 6= x1j forall 1 le i j 6= 9 i 6= j (21)
middot 2 middot
Obr 23 Hra Sudoku ndash rozdelenie na štvorce
Zo všetkyacutech kombinaacuteciiacute hodnocirct premennyacutech (D9) vyberaacuteme teda len takeacute dosadenia x pri ktoryacutech
platiacute že z hodnocirct v riadku 1 ani dve nie suacute rovnakeacute
Obmedzenie (21) možno zovšeobecniť pre ľubovoľnyacute riadok a obdobne možno denovať os-
tatneacute obmedzenia Keďže tento typ obmedzeniacute sa vyskytuje často existuje preň osobitneacute kľuacutečoveacute
slovo alldierent ndash tj všetky uvedeneacute premenneacute sa musia odlišovať Ako možno toto kľuacutečoveacute
slovo a ineacute kľuacutečoveacute slovaacute použiť v praxi uvidiacuteme na priacutekladoch neskocircr
22 Probleacutem SAT
Za špeciaacutelny priacutepad CSP možno považovať probleacutem spĺňania logickyacutech formuacutel (angl boolean satis-
ability problem SAT) V jeho priacutepade sa deničneacute oboryDi jednotlivyacutech premennyacutech redukujuacute
na Di = true false [1]
3 | Logickeacute programovanie ohraničeniacuteSysteacutemy na programovanie ohraničeniacute typicky integrujuacute koncepty z CP do nejakeacuteho už existu-
juacuteceho programovacieho jazyka Existuje veľkyacute počet implementaacuteciiacute pre mnoho rocircznych jazy-
kov Ako priacuteklady implementaacutecie v klasickyacutech imperatiacutevnych jazykoch možno uviesť knižnicu
Gecode pre C++ knižnicu or-tools ktoruacute možno použiacutevať z C++ Python-u Javy a NET alebo
javoveacute knižnice CHOCO a JaCoP
Osobitnuacute vetvu však tvoria logickeacute deklaratiacutevne jazyky ndash napriacuteklad Prolog ndash ktoreacute sa osobitne
hodia na integraacuteciu CP keďže s niacutem už mnoheacute koncepty zdieľajuacute Prolog napriacuteklad už obsahuje
koncept prehľadaacutevania s naacutevratom ktoryacute (ako uvidiacuteme) sa využiacuteva aj v CP [2]
middot 3 middot
Obr 41 Deničneacute obory premennyacutech v hracom poli Sudoku
Preto aj vyacutevoj v oblasti CP bol historicky do značnej miery spojenyacute praacuteve s jazykom Prolog
a s jeho rocircznymi nadstavbami ndash napr s jazykom CHIP ktoryacute zaviedol programovanie ohraničeniacute
na konečnyacutech deničnyacutech oboroch resp CLP(R) ktoreacute zaviedlo podporu pre ohraničenia na
reaacutelnych čiacuteslach [2] Ďalej ide o rocirczne prologoveacute systeacutemy ako napr ECLiPS
ea SICStus Prolog
[2] Knižnice pre programovanie ohraničeniacute existujuacute aj v inyacutech prologoch (napr clpfd pre SWI-
Prolog) V suacutevislosti s tyacutem sa hovoriacute o tzv logickom programovaniacute ohraničeniacute čiacutem sa mysliacute praacuteve
programovanie ohraničeniacute v raacutemci logickyacutech jazykov ako je Prolog
4 | Programovanie ohraničeniacute ako riešenie SudokuV tejto časti ilustrujeme zaacutekladneacute koncepty programovania ohraničeniacute na hre Sudoku čiacutem si
vybudujeme intuiacuteciu potrebnuacute pre nasledujuacuteci formaacutelnejšiacute vyacuteklad Vyššie sme ukaacutezali že hru
Sudoku možno veľmi prirodzenyacutem spocircsobom reprezentovať ako probleacutem spĺňania ohraničeniacute
(CSP)
Ak maacuteme Sudoku rozmeru 9 times 9 a F poliacutečok už maacute stanoveneacute hodnoty maacuteme 9 times 9 minusF premennyacutech ktoryacutech hodnoty musiacuteme stanoviť Deničnyacute obor každej z nich bude Di =1 2 9 Počiatočnyacute stav mocircžeme ilustrovať tak že do každeacuteho praacutezdneho poliacutečka vpiacutešeme
všetky hodnoty ktoreacute daneacute premennaacute mocircže nadobuacutedať Priacuteklad je na Obr 41
Ako vidno v hracom poli Obr 41 je preddenovanyacutech 31 poliacutečok Doplniť teda treba zvyš-
nyacutech 50 poliacutečok z ktoryacutech každeacute mocircže obsahovať hodnoty od 1 po 9 tak aby boli splneneacute všetky
ohraničenia
middot 4 middot
(a) (b) (c)
Obr 42 Postup pre ľavyacute hornyacute štvorcovyacute vyacutesek
41 Aplikaacutecia ohraničeniacute hry Sudoku
O ohraničeniach hry Sudoku sme hovorili vyššie teraz ich budeme ilustrovať na priacuteklade Ako
prveacute ohraničenie sme uviedli že dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9 Toto ohraničenie
sme už zahrnuli pri určeniacute deničneacuteho oboru premennyacutech ďalej ho teda uvažovať nemusiacuteme
Prejdeme teda postupne len ostatneacute ohraničenia
411 Štvorcoveacute ohraničenia
Začnime štvorcovyacutemi ohraničeniami Princiacutep budeme ilustrovať na štvorcovom vyacuteseku z ľaveacuteho
horneacuteho rohu ktoryacute je na Obr 42a Ako vidno tri poliacutečka už majuacute preddenovaneacute hodnoty
x22 = 5 x31 = 3 a x33 = 4 Keďže tie isteacute hodnoty sa v raacutemci štvorca nesmuacute opakovať viackraacutet
je jasneacute že z deničnyacutech oborov ostatnyacutech premennyacutech mocircžeme čiacutesla 3 4 a 5 vyluacutečiť ako to
ilustrujuacute Obr 42b a 42c
Aplikujme teda obdobnyacutem spocircsobom štvorcoveacute ohraničenia na všetky štvorce a pokračujme
ďalej riadkovyacutemi a stĺpcovyacutemi ohraničeniami
412 Riadkoveacute a stĺpcoveacute ohraničenia
Priacuteklad aplikaacutecie riadkoveacuteho ohraničenia pre prvyacute riadok je na Obr 43a Ako vidno v riadku sa
vyskytuje jedna preddenovanaacute hodnota ndash čiacuteslo 9 ktoruacute je potrebneacute vyluacutečiť z deničnyacutech oborov
všetkyacutech ostatnyacutech premennyacutech v danom riadku
Ak naacutesledne budeme ilustrovať priacuteklad stĺpcoveacuteho ohraničenia na ocircsmom stĺpci ziacuteskame
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
je relaacutecia nad premennyacutemiSj = rozsah(Cj)[1] Inyacutemi slovami možno povedať žeRSj
je podmnožina karteziaacutenskeho suacutečinu deničnyacutech obo-
rov premennyacutech z Sj [1]1
Riešeniacutem probleacutemu P je n-tica A = 〈a1 a2 an〉 takaacute že platiacute ai isin Di a každeacute ohraničenie
Cj je splneneacute tj pre projekciu A do rozsahu Sj platiacute relaacutecia RSj
1Ku relaacuteciaacutem a karteziaacutenskemu suacutečinu možno pozrieť viac v priacutelohe A
middot 1 middot
Obr 21 Hra Sudoku Obr 22 Hra Sudoku ndash riešenie
21 Formulaacutecia hry Sudoku ako CSP
Hra Sudoku je dobryacutem priacutekladom probleacutemu spĺňania ohraničeniacute Pozostaacuteva z hracieho poľa ur-
čityacutech rozmerov ndash najčastejšie 9times 9 Pole je navyše rozdeleneacute na 9 štvorcov rozmerov 3times 3 (viď
Obr 23) Každeacute poliacutečko mocircže obsahovať čiacuteslo od 1 po 9 Na začiatku hry suacute niektoreacute poliacutečka už
vyplneneacute ndash ostatneacute treba doplniť tak aby boli splneneacute predpiacutesaneacute podmienky
bull Dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9
bull Žiadne čiacuteslo v raacutemci toho isteacuteho stĺpca sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho riadku sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho štvorca sa nesmie opakovať viackraacutet
Ilustraacutecia hracieho poľa je na Obr 21 Vyplneneacute hracie pole je na Obr 22
Ak maacuteme Sudoku opiacutesať ako probleacutem spĺňania ohraničeniacute premenneacute X buduacute tvoriť hodnoty
jednotlivyacutech poliacutečok (dokopy ich bude 9times 9) Deničnyacute obor každej z nich je D = 1 2 9Ak jednotliveacute premenneacute usporiadame do matice mocircžeme ich preindexovať ako xmk kde m
je čiacuteslo riadku a k je čiacuteslo stĺpca Ak potom uvažujeme napriacuteklad ohraničenie pre prvyacute riadok
vieme že pre jeho rozsah platiacute Sr1 = x11 x12 x19 tj ohraničenie zahŕňa praacuteve premenneacute
z prveacuteho riadku
Relaacuteciu pre prvyacute riadok mocircžeme denovať nasledovne
RSr1 = x isin D9|x1i 6= x1j forall 1 le i j 6= 9 i 6= j (21)
middot 2 middot
Obr 23 Hra Sudoku ndash rozdelenie na štvorce
Zo všetkyacutech kombinaacuteciiacute hodnocirct premennyacutech (D9) vyberaacuteme teda len takeacute dosadenia x pri ktoryacutech
platiacute že z hodnocirct v riadku 1 ani dve nie suacute rovnakeacute
Obmedzenie (21) možno zovšeobecniť pre ľubovoľnyacute riadok a obdobne možno denovať os-
tatneacute obmedzenia Keďže tento typ obmedzeniacute sa vyskytuje často existuje preň osobitneacute kľuacutečoveacute
slovo alldierent ndash tj všetky uvedeneacute premenneacute sa musia odlišovať Ako možno toto kľuacutečoveacute
slovo a ineacute kľuacutečoveacute slovaacute použiť v praxi uvidiacuteme na priacutekladoch neskocircr
22 Probleacutem SAT
Za špeciaacutelny priacutepad CSP možno považovať probleacutem spĺňania logickyacutech formuacutel (angl boolean satis-
ability problem SAT) V jeho priacutepade sa deničneacute oboryDi jednotlivyacutech premennyacutech redukujuacute
na Di = true false [1]
3 | Logickeacute programovanie ohraničeniacuteSysteacutemy na programovanie ohraničeniacute typicky integrujuacute koncepty z CP do nejakeacuteho už existu-
juacuteceho programovacieho jazyka Existuje veľkyacute počet implementaacuteciiacute pre mnoho rocircznych jazy-
kov Ako priacuteklady implementaacutecie v klasickyacutech imperatiacutevnych jazykoch možno uviesť knižnicu
Gecode pre C++ knižnicu or-tools ktoruacute možno použiacutevať z C++ Python-u Javy a NET alebo
javoveacute knižnice CHOCO a JaCoP
Osobitnuacute vetvu však tvoria logickeacute deklaratiacutevne jazyky ndash napriacuteklad Prolog ndash ktoreacute sa osobitne
hodia na integraacuteciu CP keďže s niacutem už mnoheacute koncepty zdieľajuacute Prolog napriacuteklad už obsahuje
koncept prehľadaacutevania s naacutevratom ktoryacute (ako uvidiacuteme) sa využiacuteva aj v CP [2]
middot 3 middot
Obr 41 Deničneacute obory premennyacutech v hracom poli Sudoku
Preto aj vyacutevoj v oblasti CP bol historicky do značnej miery spojenyacute praacuteve s jazykom Prolog
a s jeho rocircznymi nadstavbami ndash napr s jazykom CHIP ktoryacute zaviedol programovanie ohraničeniacute
na konečnyacutech deničnyacutech oboroch resp CLP(R) ktoreacute zaviedlo podporu pre ohraničenia na
reaacutelnych čiacuteslach [2] Ďalej ide o rocirczne prologoveacute systeacutemy ako napr ECLiPS
ea SICStus Prolog
[2] Knižnice pre programovanie ohraničeniacute existujuacute aj v inyacutech prologoch (napr clpfd pre SWI-
Prolog) V suacutevislosti s tyacutem sa hovoriacute o tzv logickom programovaniacute ohraničeniacute čiacutem sa mysliacute praacuteve
programovanie ohraničeniacute v raacutemci logickyacutech jazykov ako je Prolog
4 | Programovanie ohraničeniacute ako riešenie SudokuV tejto časti ilustrujeme zaacutekladneacute koncepty programovania ohraničeniacute na hre Sudoku čiacutem si
vybudujeme intuiacuteciu potrebnuacute pre nasledujuacuteci formaacutelnejšiacute vyacuteklad Vyššie sme ukaacutezali že hru
Sudoku možno veľmi prirodzenyacutem spocircsobom reprezentovať ako probleacutem spĺňania ohraničeniacute
(CSP)
Ak maacuteme Sudoku rozmeru 9 times 9 a F poliacutečok už maacute stanoveneacute hodnoty maacuteme 9 times 9 minusF premennyacutech ktoryacutech hodnoty musiacuteme stanoviť Deničnyacute obor každej z nich bude Di =1 2 9 Počiatočnyacute stav mocircžeme ilustrovať tak že do každeacuteho praacutezdneho poliacutečka vpiacutešeme
všetky hodnoty ktoreacute daneacute premennaacute mocircže nadobuacutedať Priacuteklad je na Obr 41
Ako vidno v hracom poli Obr 41 je preddenovanyacutech 31 poliacutečok Doplniť teda treba zvyš-
nyacutech 50 poliacutečok z ktoryacutech každeacute mocircže obsahovať hodnoty od 1 po 9 tak aby boli splneneacute všetky
ohraničenia
middot 4 middot
(a) (b) (c)
Obr 42 Postup pre ľavyacute hornyacute štvorcovyacute vyacutesek
41 Aplikaacutecia ohraničeniacute hry Sudoku
O ohraničeniach hry Sudoku sme hovorili vyššie teraz ich budeme ilustrovať na priacuteklade Ako
prveacute ohraničenie sme uviedli že dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9 Toto ohraničenie
sme už zahrnuli pri určeniacute deničneacuteho oboru premennyacutech ďalej ho teda uvažovať nemusiacuteme
Prejdeme teda postupne len ostatneacute ohraničenia
411 Štvorcoveacute ohraničenia
Začnime štvorcovyacutemi ohraničeniami Princiacutep budeme ilustrovať na štvorcovom vyacuteseku z ľaveacuteho
horneacuteho rohu ktoryacute je na Obr 42a Ako vidno tri poliacutečka už majuacute preddenovaneacute hodnoty
x22 = 5 x31 = 3 a x33 = 4 Keďže tie isteacute hodnoty sa v raacutemci štvorca nesmuacute opakovať viackraacutet
je jasneacute že z deničnyacutech oborov ostatnyacutech premennyacutech mocircžeme čiacutesla 3 4 a 5 vyluacutečiť ako to
ilustrujuacute Obr 42b a 42c
Aplikujme teda obdobnyacutem spocircsobom štvorcoveacute ohraničenia na všetky štvorce a pokračujme
ďalej riadkovyacutemi a stĺpcovyacutemi ohraničeniami
412 Riadkoveacute a stĺpcoveacute ohraničenia
Priacuteklad aplikaacutecie riadkoveacuteho ohraničenia pre prvyacute riadok je na Obr 43a Ako vidno v riadku sa
vyskytuje jedna preddenovanaacute hodnota ndash čiacuteslo 9 ktoruacute je potrebneacute vyluacutečiť z deničnyacutech oborov
všetkyacutech ostatnyacutech premennyacutech v danom riadku
Ak naacutesledne budeme ilustrovať priacuteklad stĺpcoveacuteho ohraničenia na ocircsmom stĺpci ziacuteskame
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Obsah
1 Uacutevod 1
2 Probleacutem spĺňania ohraničeniacute 121 Formulaacutecia hry Sudoku ako CSP 2
22 Probleacutem SAT 3
3 Logickeacute programovanie ohraničeniacute 3
4 Programovanie ohraničeniacute ako riešenie Sudoku 441 Aplikaacutecia ohraničeniacute hry Sudoku 5
411 Štvorcoveacute ohraničenia 5
412 Riadkoveacute a stĺpcoveacute ohraničenia 5
42 Ohraničenia aplikujeme opakovane 6
43 Vetvenie 7
431 Naacutevrat 7
432 Strateacutegie vetvenia 9
5 Zaacutekladneacute koncepty v CP 951 Sklad ohraničeniacute 10
511 Interakcia prehľadaacutevania a skladu ohraničeniacute 10
512 Propagaacutecia ohraničeniacute 11
52 Arita ohraničeniacute 11
53 Globaacutelne ohraničenia 12
54 Ciele CP a optimalizaacutecia na baacuteze CP 12
6 Konzistenčneacute techniky 1261 Vrcholovaacute konzistentnosť 13
62 Hranovaacute konzistentnosť 13
621 Ako dosiahnuť hranovuacute konzistentnosť 14
63 Konzistentnosť po ceste 16
7 Riešenie predeterminovanyacutech CSP 1671 Maumlkkeacute ohraničenia 16
72 Max-CSP 17
73 Vaacuteženeacute CSP 17
74 Fuzzy CSP 17
middot 1 middot
75 Ďalšie priacutestupy 17
8 Reikaacutecia 1881 Využitie reikaacutecie pri modelovaniacute 18
je relaacutecia nad premennyacutemiSj = rozsah(Cj)[1] Inyacutemi slovami možno povedať žeRSj
je podmnožina karteziaacutenskeho suacutečinu deničnyacutech obo-
rov premennyacutech z Sj [1]1
Riešeniacutem probleacutemu P je n-tica A = 〈a1 a2 an〉 takaacute že platiacute ai isin Di a každeacute ohraničenie
Cj je splneneacute tj pre projekciu A do rozsahu Sj platiacute relaacutecia RSj
1Ku relaacuteciaacutem a karteziaacutenskemu suacutečinu možno pozrieť viac v priacutelohe A
middot 1 middot
Obr 21 Hra Sudoku Obr 22 Hra Sudoku ndash riešenie
21 Formulaacutecia hry Sudoku ako CSP
Hra Sudoku je dobryacutem priacutekladom probleacutemu spĺňania ohraničeniacute Pozostaacuteva z hracieho poľa ur-
čityacutech rozmerov ndash najčastejšie 9times 9 Pole je navyše rozdeleneacute na 9 štvorcov rozmerov 3times 3 (viď
Obr 23) Každeacute poliacutečko mocircže obsahovať čiacuteslo od 1 po 9 Na začiatku hry suacute niektoreacute poliacutečka už
vyplneneacute ndash ostatneacute treba doplniť tak aby boli splneneacute predpiacutesaneacute podmienky
bull Dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9
bull Žiadne čiacuteslo v raacutemci toho isteacuteho stĺpca sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho riadku sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho štvorca sa nesmie opakovať viackraacutet
Ilustraacutecia hracieho poľa je na Obr 21 Vyplneneacute hracie pole je na Obr 22
Ak maacuteme Sudoku opiacutesať ako probleacutem spĺňania ohraničeniacute premenneacute X buduacute tvoriť hodnoty
jednotlivyacutech poliacutečok (dokopy ich bude 9times 9) Deničnyacute obor každej z nich je D = 1 2 9Ak jednotliveacute premenneacute usporiadame do matice mocircžeme ich preindexovať ako xmk kde m
je čiacuteslo riadku a k je čiacuteslo stĺpca Ak potom uvažujeme napriacuteklad ohraničenie pre prvyacute riadok
vieme že pre jeho rozsah platiacute Sr1 = x11 x12 x19 tj ohraničenie zahŕňa praacuteve premenneacute
z prveacuteho riadku
Relaacuteciu pre prvyacute riadok mocircžeme denovať nasledovne
RSr1 = x isin D9|x1i 6= x1j forall 1 le i j 6= 9 i 6= j (21)
middot 2 middot
Obr 23 Hra Sudoku ndash rozdelenie na štvorce
Zo všetkyacutech kombinaacuteciiacute hodnocirct premennyacutech (D9) vyberaacuteme teda len takeacute dosadenia x pri ktoryacutech
platiacute že z hodnocirct v riadku 1 ani dve nie suacute rovnakeacute
Obmedzenie (21) možno zovšeobecniť pre ľubovoľnyacute riadok a obdobne možno denovať os-
tatneacute obmedzenia Keďže tento typ obmedzeniacute sa vyskytuje často existuje preň osobitneacute kľuacutečoveacute
slovo alldierent ndash tj všetky uvedeneacute premenneacute sa musia odlišovať Ako možno toto kľuacutečoveacute
slovo a ineacute kľuacutečoveacute slovaacute použiť v praxi uvidiacuteme na priacutekladoch neskocircr
22 Probleacutem SAT
Za špeciaacutelny priacutepad CSP možno považovať probleacutem spĺňania logickyacutech formuacutel (angl boolean satis-
ability problem SAT) V jeho priacutepade sa deničneacute oboryDi jednotlivyacutech premennyacutech redukujuacute
na Di = true false [1]
3 | Logickeacute programovanie ohraničeniacuteSysteacutemy na programovanie ohraničeniacute typicky integrujuacute koncepty z CP do nejakeacuteho už existu-
juacuteceho programovacieho jazyka Existuje veľkyacute počet implementaacuteciiacute pre mnoho rocircznych jazy-
kov Ako priacuteklady implementaacutecie v klasickyacutech imperatiacutevnych jazykoch možno uviesť knižnicu
Gecode pre C++ knižnicu or-tools ktoruacute možno použiacutevať z C++ Python-u Javy a NET alebo
javoveacute knižnice CHOCO a JaCoP
Osobitnuacute vetvu však tvoria logickeacute deklaratiacutevne jazyky ndash napriacuteklad Prolog ndash ktoreacute sa osobitne
hodia na integraacuteciu CP keďže s niacutem už mnoheacute koncepty zdieľajuacute Prolog napriacuteklad už obsahuje
koncept prehľadaacutevania s naacutevratom ktoryacute (ako uvidiacuteme) sa využiacuteva aj v CP [2]
middot 3 middot
Obr 41 Deničneacute obory premennyacutech v hracom poli Sudoku
Preto aj vyacutevoj v oblasti CP bol historicky do značnej miery spojenyacute praacuteve s jazykom Prolog
a s jeho rocircznymi nadstavbami ndash napr s jazykom CHIP ktoryacute zaviedol programovanie ohraničeniacute
na konečnyacutech deničnyacutech oboroch resp CLP(R) ktoreacute zaviedlo podporu pre ohraničenia na
reaacutelnych čiacuteslach [2] Ďalej ide o rocirczne prologoveacute systeacutemy ako napr ECLiPS
ea SICStus Prolog
[2] Knižnice pre programovanie ohraničeniacute existujuacute aj v inyacutech prologoch (napr clpfd pre SWI-
Prolog) V suacutevislosti s tyacutem sa hovoriacute o tzv logickom programovaniacute ohraničeniacute čiacutem sa mysliacute praacuteve
programovanie ohraničeniacute v raacutemci logickyacutech jazykov ako je Prolog
4 | Programovanie ohraničeniacute ako riešenie SudokuV tejto časti ilustrujeme zaacutekladneacute koncepty programovania ohraničeniacute na hre Sudoku čiacutem si
vybudujeme intuiacuteciu potrebnuacute pre nasledujuacuteci formaacutelnejšiacute vyacuteklad Vyššie sme ukaacutezali že hru
Sudoku možno veľmi prirodzenyacutem spocircsobom reprezentovať ako probleacutem spĺňania ohraničeniacute
(CSP)
Ak maacuteme Sudoku rozmeru 9 times 9 a F poliacutečok už maacute stanoveneacute hodnoty maacuteme 9 times 9 minusF premennyacutech ktoryacutech hodnoty musiacuteme stanoviť Deničnyacute obor každej z nich bude Di =1 2 9 Počiatočnyacute stav mocircžeme ilustrovať tak že do každeacuteho praacutezdneho poliacutečka vpiacutešeme
všetky hodnoty ktoreacute daneacute premennaacute mocircže nadobuacutedať Priacuteklad je na Obr 41
Ako vidno v hracom poli Obr 41 je preddenovanyacutech 31 poliacutečok Doplniť teda treba zvyš-
nyacutech 50 poliacutečok z ktoryacutech každeacute mocircže obsahovať hodnoty od 1 po 9 tak aby boli splneneacute všetky
ohraničenia
middot 4 middot
(a) (b) (c)
Obr 42 Postup pre ľavyacute hornyacute štvorcovyacute vyacutesek
41 Aplikaacutecia ohraničeniacute hry Sudoku
O ohraničeniach hry Sudoku sme hovorili vyššie teraz ich budeme ilustrovať na priacuteklade Ako
prveacute ohraničenie sme uviedli že dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9 Toto ohraničenie
sme už zahrnuli pri určeniacute deničneacuteho oboru premennyacutech ďalej ho teda uvažovať nemusiacuteme
Prejdeme teda postupne len ostatneacute ohraničenia
411 Štvorcoveacute ohraničenia
Začnime štvorcovyacutemi ohraničeniami Princiacutep budeme ilustrovať na štvorcovom vyacuteseku z ľaveacuteho
horneacuteho rohu ktoryacute je na Obr 42a Ako vidno tri poliacutečka už majuacute preddenovaneacute hodnoty
x22 = 5 x31 = 3 a x33 = 4 Keďže tie isteacute hodnoty sa v raacutemci štvorca nesmuacute opakovať viackraacutet
je jasneacute že z deničnyacutech oborov ostatnyacutech premennyacutech mocircžeme čiacutesla 3 4 a 5 vyluacutečiť ako to
ilustrujuacute Obr 42b a 42c
Aplikujme teda obdobnyacutem spocircsobom štvorcoveacute ohraničenia na všetky štvorce a pokračujme
ďalej riadkovyacutemi a stĺpcovyacutemi ohraničeniami
412 Riadkoveacute a stĺpcoveacute ohraničenia
Priacuteklad aplikaacutecie riadkoveacuteho ohraničenia pre prvyacute riadok je na Obr 43a Ako vidno v riadku sa
vyskytuje jedna preddenovanaacute hodnota ndash čiacuteslo 9 ktoruacute je potrebneacute vyluacutečiť z deničnyacutech oborov
všetkyacutech ostatnyacutech premennyacutech v danom riadku
Ak naacutesledne budeme ilustrovať priacuteklad stĺpcoveacuteho ohraničenia na ocircsmom stĺpci ziacuteskame
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
75 Ďalšie priacutestupy 17
8 Reikaacutecia 1881 Využitie reikaacutecie pri modelovaniacute 18
je relaacutecia nad premennyacutemiSj = rozsah(Cj)[1] Inyacutemi slovami možno povedať žeRSj
je podmnožina karteziaacutenskeho suacutečinu deničnyacutech obo-
rov premennyacutech z Sj [1]1
Riešeniacutem probleacutemu P je n-tica A = 〈a1 a2 an〉 takaacute že platiacute ai isin Di a každeacute ohraničenie
Cj je splneneacute tj pre projekciu A do rozsahu Sj platiacute relaacutecia RSj
1Ku relaacuteciaacutem a karteziaacutenskemu suacutečinu možno pozrieť viac v priacutelohe A
middot 1 middot
Obr 21 Hra Sudoku Obr 22 Hra Sudoku ndash riešenie
21 Formulaacutecia hry Sudoku ako CSP
Hra Sudoku je dobryacutem priacutekladom probleacutemu spĺňania ohraničeniacute Pozostaacuteva z hracieho poľa ur-
čityacutech rozmerov ndash najčastejšie 9times 9 Pole je navyše rozdeleneacute na 9 štvorcov rozmerov 3times 3 (viď
Obr 23) Každeacute poliacutečko mocircže obsahovať čiacuteslo od 1 po 9 Na začiatku hry suacute niektoreacute poliacutečka už
vyplneneacute ndash ostatneacute treba doplniť tak aby boli splneneacute predpiacutesaneacute podmienky
bull Dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9
bull Žiadne čiacuteslo v raacutemci toho isteacuteho stĺpca sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho riadku sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho štvorca sa nesmie opakovať viackraacutet
Ilustraacutecia hracieho poľa je na Obr 21 Vyplneneacute hracie pole je na Obr 22
Ak maacuteme Sudoku opiacutesať ako probleacutem spĺňania ohraničeniacute premenneacute X buduacute tvoriť hodnoty
jednotlivyacutech poliacutečok (dokopy ich bude 9times 9) Deničnyacute obor každej z nich je D = 1 2 9Ak jednotliveacute premenneacute usporiadame do matice mocircžeme ich preindexovať ako xmk kde m
je čiacuteslo riadku a k je čiacuteslo stĺpca Ak potom uvažujeme napriacuteklad ohraničenie pre prvyacute riadok
vieme že pre jeho rozsah platiacute Sr1 = x11 x12 x19 tj ohraničenie zahŕňa praacuteve premenneacute
z prveacuteho riadku
Relaacuteciu pre prvyacute riadok mocircžeme denovať nasledovne
RSr1 = x isin D9|x1i 6= x1j forall 1 le i j 6= 9 i 6= j (21)
middot 2 middot
Obr 23 Hra Sudoku ndash rozdelenie na štvorce
Zo všetkyacutech kombinaacuteciiacute hodnocirct premennyacutech (D9) vyberaacuteme teda len takeacute dosadenia x pri ktoryacutech
platiacute že z hodnocirct v riadku 1 ani dve nie suacute rovnakeacute
Obmedzenie (21) možno zovšeobecniť pre ľubovoľnyacute riadok a obdobne možno denovať os-
tatneacute obmedzenia Keďže tento typ obmedzeniacute sa vyskytuje často existuje preň osobitneacute kľuacutečoveacute
slovo alldierent ndash tj všetky uvedeneacute premenneacute sa musia odlišovať Ako možno toto kľuacutečoveacute
slovo a ineacute kľuacutečoveacute slovaacute použiť v praxi uvidiacuteme na priacutekladoch neskocircr
22 Probleacutem SAT
Za špeciaacutelny priacutepad CSP možno považovať probleacutem spĺňania logickyacutech formuacutel (angl boolean satis-
ability problem SAT) V jeho priacutepade sa deničneacute oboryDi jednotlivyacutech premennyacutech redukujuacute
na Di = true false [1]
3 | Logickeacute programovanie ohraničeniacuteSysteacutemy na programovanie ohraničeniacute typicky integrujuacute koncepty z CP do nejakeacuteho už existu-
juacuteceho programovacieho jazyka Existuje veľkyacute počet implementaacuteciiacute pre mnoho rocircznych jazy-
kov Ako priacuteklady implementaacutecie v klasickyacutech imperatiacutevnych jazykoch možno uviesť knižnicu
Gecode pre C++ knižnicu or-tools ktoruacute možno použiacutevať z C++ Python-u Javy a NET alebo
javoveacute knižnice CHOCO a JaCoP
Osobitnuacute vetvu však tvoria logickeacute deklaratiacutevne jazyky ndash napriacuteklad Prolog ndash ktoreacute sa osobitne
hodia na integraacuteciu CP keďže s niacutem už mnoheacute koncepty zdieľajuacute Prolog napriacuteklad už obsahuje
koncept prehľadaacutevania s naacutevratom ktoryacute (ako uvidiacuteme) sa využiacuteva aj v CP [2]
middot 3 middot
Obr 41 Deničneacute obory premennyacutech v hracom poli Sudoku
Preto aj vyacutevoj v oblasti CP bol historicky do značnej miery spojenyacute praacuteve s jazykom Prolog
a s jeho rocircznymi nadstavbami ndash napr s jazykom CHIP ktoryacute zaviedol programovanie ohraničeniacute
na konečnyacutech deničnyacutech oboroch resp CLP(R) ktoreacute zaviedlo podporu pre ohraničenia na
reaacutelnych čiacuteslach [2] Ďalej ide o rocirczne prologoveacute systeacutemy ako napr ECLiPS
ea SICStus Prolog
[2] Knižnice pre programovanie ohraničeniacute existujuacute aj v inyacutech prologoch (napr clpfd pre SWI-
Prolog) V suacutevislosti s tyacutem sa hovoriacute o tzv logickom programovaniacute ohraničeniacute čiacutem sa mysliacute praacuteve
programovanie ohraničeniacute v raacutemci logickyacutech jazykov ako je Prolog
4 | Programovanie ohraničeniacute ako riešenie SudokuV tejto časti ilustrujeme zaacutekladneacute koncepty programovania ohraničeniacute na hre Sudoku čiacutem si
vybudujeme intuiacuteciu potrebnuacute pre nasledujuacuteci formaacutelnejšiacute vyacuteklad Vyššie sme ukaacutezali že hru
Sudoku možno veľmi prirodzenyacutem spocircsobom reprezentovať ako probleacutem spĺňania ohraničeniacute
(CSP)
Ak maacuteme Sudoku rozmeru 9 times 9 a F poliacutečok už maacute stanoveneacute hodnoty maacuteme 9 times 9 minusF premennyacutech ktoryacutech hodnoty musiacuteme stanoviť Deničnyacute obor každej z nich bude Di =1 2 9 Počiatočnyacute stav mocircžeme ilustrovať tak že do každeacuteho praacutezdneho poliacutečka vpiacutešeme
všetky hodnoty ktoreacute daneacute premennaacute mocircže nadobuacutedať Priacuteklad je na Obr 41
Ako vidno v hracom poli Obr 41 je preddenovanyacutech 31 poliacutečok Doplniť teda treba zvyš-
nyacutech 50 poliacutečok z ktoryacutech každeacute mocircže obsahovať hodnoty od 1 po 9 tak aby boli splneneacute všetky
ohraničenia
middot 4 middot
(a) (b) (c)
Obr 42 Postup pre ľavyacute hornyacute štvorcovyacute vyacutesek
41 Aplikaacutecia ohraničeniacute hry Sudoku
O ohraničeniach hry Sudoku sme hovorili vyššie teraz ich budeme ilustrovať na priacuteklade Ako
prveacute ohraničenie sme uviedli že dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9 Toto ohraničenie
sme už zahrnuli pri určeniacute deničneacuteho oboru premennyacutech ďalej ho teda uvažovať nemusiacuteme
Prejdeme teda postupne len ostatneacute ohraničenia
411 Štvorcoveacute ohraničenia
Začnime štvorcovyacutemi ohraničeniami Princiacutep budeme ilustrovať na štvorcovom vyacuteseku z ľaveacuteho
horneacuteho rohu ktoryacute je na Obr 42a Ako vidno tri poliacutečka už majuacute preddenovaneacute hodnoty
x22 = 5 x31 = 3 a x33 = 4 Keďže tie isteacute hodnoty sa v raacutemci štvorca nesmuacute opakovať viackraacutet
je jasneacute že z deničnyacutech oborov ostatnyacutech premennyacutech mocircžeme čiacutesla 3 4 a 5 vyluacutečiť ako to
ilustrujuacute Obr 42b a 42c
Aplikujme teda obdobnyacutem spocircsobom štvorcoveacute ohraničenia na všetky štvorce a pokračujme
ďalej riadkovyacutemi a stĺpcovyacutemi ohraničeniami
412 Riadkoveacute a stĺpcoveacute ohraničenia
Priacuteklad aplikaacutecie riadkoveacuteho ohraničenia pre prvyacute riadok je na Obr 43a Ako vidno v riadku sa
vyskytuje jedna preddenovanaacute hodnota ndash čiacuteslo 9 ktoruacute je potrebneacute vyluacutečiť z deničnyacutech oborov
všetkyacutech ostatnyacutech premennyacutech v danom riadku
Ak naacutesledne budeme ilustrovať priacuteklad stĺpcoveacuteho ohraničenia na ocircsmom stĺpci ziacuteskame
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
SkratkyAC hranovo konzistentnyacute (angl arc consistent) p 13
COP probleacutem optimalizaacutecie ohraničeniacute (angl constraint optimization problem) p 12
je relaacutecia nad premennyacutemiSj = rozsah(Cj)[1] Inyacutemi slovami možno povedať žeRSj
je podmnožina karteziaacutenskeho suacutečinu deničnyacutech obo-
rov premennyacutech z Sj [1]1
Riešeniacutem probleacutemu P je n-tica A = 〈a1 a2 an〉 takaacute že platiacute ai isin Di a každeacute ohraničenie
Cj je splneneacute tj pre projekciu A do rozsahu Sj platiacute relaacutecia RSj
1Ku relaacuteciaacutem a karteziaacutenskemu suacutečinu možno pozrieť viac v priacutelohe A
middot 1 middot
Obr 21 Hra Sudoku Obr 22 Hra Sudoku ndash riešenie
21 Formulaacutecia hry Sudoku ako CSP
Hra Sudoku je dobryacutem priacutekladom probleacutemu spĺňania ohraničeniacute Pozostaacuteva z hracieho poľa ur-
čityacutech rozmerov ndash najčastejšie 9times 9 Pole je navyše rozdeleneacute na 9 štvorcov rozmerov 3times 3 (viď
Obr 23) Každeacute poliacutečko mocircže obsahovať čiacuteslo od 1 po 9 Na začiatku hry suacute niektoreacute poliacutečka už
vyplneneacute ndash ostatneacute treba doplniť tak aby boli splneneacute predpiacutesaneacute podmienky
bull Dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9
bull Žiadne čiacuteslo v raacutemci toho isteacuteho stĺpca sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho riadku sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho štvorca sa nesmie opakovať viackraacutet
Ilustraacutecia hracieho poľa je na Obr 21 Vyplneneacute hracie pole je na Obr 22
Ak maacuteme Sudoku opiacutesať ako probleacutem spĺňania ohraničeniacute premenneacute X buduacute tvoriť hodnoty
jednotlivyacutech poliacutečok (dokopy ich bude 9times 9) Deničnyacute obor každej z nich je D = 1 2 9Ak jednotliveacute premenneacute usporiadame do matice mocircžeme ich preindexovať ako xmk kde m
je čiacuteslo riadku a k je čiacuteslo stĺpca Ak potom uvažujeme napriacuteklad ohraničenie pre prvyacute riadok
vieme že pre jeho rozsah platiacute Sr1 = x11 x12 x19 tj ohraničenie zahŕňa praacuteve premenneacute
z prveacuteho riadku
Relaacuteciu pre prvyacute riadok mocircžeme denovať nasledovne
RSr1 = x isin D9|x1i 6= x1j forall 1 le i j 6= 9 i 6= j (21)
middot 2 middot
Obr 23 Hra Sudoku ndash rozdelenie na štvorce
Zo všetkyacutech kombinaacuteciiacute hodnocirct premennyacutech (D9) vyberaacuteme teda len takeacute dosadenia x pri ktoryacutech
platiacute že z hodnocirct v riadku 1 ani dve nie suacute rovnakeacute
Obmedzenie (21) možno zovšeobecniť pre ľubovoľnyacute riadok a obdobne možno denovať os-
tatneacute obmedzenia Keďže tento typ obmedzeniacute sa vyskytuje často existuje preň osobitneacute kľuacutečoveacute
slovo alldierent ndash tj všetky uvedeneacute premenneacute sa musia odlišovať Ako možno toto kľuacutečoveacute
slovo a ineacute kľuacutečoveacute slovaacute použiť v praxi uvidiacuteme na priacutekladoch neskocircr
22 Probleacutem SAT
Za špeciaacutelny priacutepad CSP možno považovať probleacutem spĺňania logickyacutech formuacutel (angl boolean satis-
ability problem SAT) V jeho priacutepade sa deničneacute oboryDi jednotlivyacutech premennyacutech redukujuacute
na Di = true false [1]
3 | Logickeacute programovanie ohraničeniacuteSysteacutemy na programovanie ohraničeniacute typicky integrujuacute koncepty z CP do nejakeacuteho už existu-
juacuteceho programovacieho jazyka Existuje veľkyacute počet implementaacuteciiacute pre mnoho rocircznych jazy-
kov Ako priacuteklady implementaacutecie v klasickyacutech imperatiacutevnych jazykoch možno uviesť knižnicu
Gecode pre C++ knižnicu or-tools ktoruacute možno použiacutevať z C++ Python-u Javy a NET alebo
javoveacute knižnice CHOCO a JaCoP
Osobitnuacute vetvu však tvoria logickeacute deklaratiacutevne jazyky ndash napriacuteklad Prolog ndash ktoreacute sa osobitne
hodia na integraacuteciu CP keďže s niacutem už mnoheacute koncepty zdieľajuacute Prolog napriacuteklad už obsahuje
koncept prehľadaacutevania s naacutevratom ktoryacute (ako uvidiacuteme) sa využiacuteva aj v CP [2]
middot 3 middot
Obr 41 Deničneacute obory premennyacutech v hracom poli Sudoku
Preto aj vyacutevoj v oblasti CP bol historicky do značnej miery spojenyacute praacuteve s jazykom Prolog
a s jeho rocircznymi nadstavbami ndash napr s jazykom CHIP ktoryacute zaviedol programovanie ohraničeniacute
na konečnyacutech deničnyacutech oboroch resp CLP(R) ktoreacute zaviedlo podporu pre ohraničenia na
reaacutelnych čiacuteslach [2] Ďalej ide o rocirczne prologoveacute systeacutemy ako napr ECLiPS
ea SICStus Prolog
[2] Knižnice pre programovanie ohraničeniacute existujuacute aj v inyacutech prologoch (napr clpfd pre SWI-
Prolog) V suacutevislosti s tyacutem sa hovoriacute o tzv logickom programovaniacute ohraničeniacute čiacutem sa mysliacute praacuteve
programovanie ohraničeniacute v raacutemci logickyacutech jazykov ako je Prolog
4 | Programovanie ohraničeniacute ako riešenie SudokuV tejto časti ilustrujeme zaacutekladneacute koncepty programovania ohraničeniacute na hre Sudoku čiacutem si
vybudujeme intuiacuteciu potrebnuacute pre nasledujuacuteci formaacutelnejšiacute vyacuteklad Vyššie sme ukaacutezali že hru
Sudoku možno veľmi prirodzenyacutem spocircsobom reprezentovať ako probleacutem spĺňania ohraničeniacute
(CSP)
Ak maacuteme Sudoku rozmeru 9 times 9 a F poliacutečok už maacute stanoveneacute hodnoty maacuteme 9 times 9 minusF premennyacutech ktoryacutech hodnoty musiacuteme stanoviť Deničnyacute obor každej z nich bude Di =1 2 9 Počiatočnyacute stav mocircžeme ilustrovať tak že do každeacuteho praacutezdneho poliacutečka vpiacutešeme
všetky hodnoty ktoreacute daneacute premennaacute mocircže nadobuacutedať Priacuteklad je na Obr 41
Ako vidno v hracom poli Obr 41 je preddenovanyacutech 31 poliacutečok Doplniť teda treba zvyš-
nyacutech 50 poliacutečok z ktoryacutech každeacute mocircže obsahovať hodnoty od 1 po 9 tak aby boli splneneacute všetky
ohraničenia
middot 4 middot
(a) (b) (c)
Obr 42 Postup pre ľavyacute hornyacute štvorcovyacute vyacutesek
41 Aplikaacutecia ohraničeniacute hry Sudoku
O ohraničeniach hry Sudoku sme hovorili vyššie teraz ich budeme ilustrovať na priacuteklade Ako
prveacute ohraničenie sme uviedli že dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9 Toto ohraničenie
sme už zahrnuli pri určeniacute deničneacuteho oboru premennyacutech ďalej ho teda uvažovať nemusiacuteme
Prejdeme teda postupne len ostatneacute ohraničenia
411 Štvorcoveacute ohraničenia
Začnime štvorcovyacutemi ohraničeniami Princiacutep budeme ilustrovať na štvorcovom vyacuteseku z ľaveacuteho
horneacuteho rohu ktoryacute je na Obr 42a Ako vidno tri poliacutečka už majuacute preddenovaneacute hodnoty
x22 = 5 x31 = 3 a x33 = 4 Keďže tie isteacute hodnoty sa v raacutemci štvorca nesmuacute opakovať viackraacutet
je jasneacute že z deničnyacutech oborov ostatnyacutech premennyacutech mocircžeme čiacutesla 3 4 a 5 vyluacutečiť ako to
ilustrujuacute Obr 42b a 42c
Aplikujme teda obdobnyacutem spocircsobom štvorcoveacute ohraničenia na všetky štvorce a pokračujme
ďalej riadkovyacutemi a stĺpcovyacutemi ohraničeniami
412 Riadkoveacute a stĺpcoveacute ohraničenia
Priacuteklad aplikaacutecie riadkoveacuteho ohraničenia pre prvyacute riadok je na Obr 43a Ako vidno v riadku sa
vyskytuje jedna preddenovanaacute hodnota ndash čiacuteslo 9 ktoruacute je potrebneacute vyluacutečiť z deničnyacutech oborov
všetkyacutech ostatnyacutech premennyacutech v danom riadku
Ak naacutesledne budeme ilustrovať priacuteklad stĺpcoveacuteho ohraničenia na ocircsmom stĺpci ziacuteskame
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
je relaacutecia nad premennyacutemiSj = rozsah(Cj)[1] Inyacutemi slovami možno povedať žeRSj
je podmnožina karteziaacutenskeho suacutečinu deničnyacutech obo-
rov premennyacutech z Sj [1]1
Riešeniacutem probleacutemu P je n-tica A = 〈a1 a2 an〉 takaacute že platiacute ai isin Di a každeacute ohraničenie
Cj je splneneacute tj pre projekciu A do rozsahu Sj platiacute relaacutecia RSj
1Ku relaacuteciaacutem a karteziaacutenskemu suacutečinu možno pozrieť viac v priacutelohe A
middot 1 middot
Obr 21 Hra Sudoku Obr 22 Hra Sudoku ndash riešenie
21 Formulaacutecia hry Sudoku ako CSP
Hra Sudoku je dobryacutem priacutekladom probleacutemu spĺňania ohraničeniacute Pozostaacuteva z hracieho poľa ur-
čityacutech rozmerov ndash najčastejšie 9times 9 Pole je navyše rozdeleneacute na 9 štvorcov rozmerov 3times 3 (viď
Obr 23) Každeacute poliacutečko mocircže obsahovať čiacuteslo od 1 po 9 Na začiatku hry suacute niektoreacute poliacutečka už
vyplneneacute ndash ostatneacute treba doplniť tak aby boli splneneacute predpiacutesaneacute podmienky
bull Dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9
bull Žiadne čiacuteslo v raacutemci toho isteacuteho stĺpca sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho riadku sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho štvorca sa nesmie opakovať viackraacutet
Ilustraacutecia hracieho poľa je na Obr 21 Vyplneneacute hracie pole je na Obr 22
Ak maacuteme Sudoku opiacutesať ako probleacutem spĺňania ohraničeniacute premenneacute X buduacute tvoriť hodnoty
jednotlivyacutech poliacutečok (dokopy ich bude 9times 9) Deničnyacute obor každej z nich je D = 1 2 9Ak jednotliveacute premenneacute usporiadame do matice mocircžeme ich preindexovať ako xmk kde m
je čiacuteslo riadku a k je čiacuteslo stĺpca Ak potom uvažujeme napriacuteklad ohraničenie pre prvyacute riadok
vieme že pre jeho rozsah platiacute Sr1 = x11 x12 x19 tj ohraničenie zahŕňa praacuteve premenneacute
z prveacuteho riadku
Relaacuteciu pre prvyacute riadok mocircžeme denovať nasledovne
RSr1 = x isin D9|x1i 6= x1j forall 1 le i j 6= 9 i 6= j (21)
middot 2 middot
Obr 23 Hra Sudoku ndash rozdelenie na štvorce
Zo všetkyacutech kombinaacuteciiacute hodnocirct premennyacutech (D9) vyberaacuteme teda len takeacute dosadenia x pri ktoryacutech
platiacute že z hodnocirct v riadku 1 ani dve nie suacute rovnakeacute
Obmedzenie (21) možno zovšeobecniť pre ľubovoľnyacute riadok a obdobne možno denovať os-
tatneacute obmedzenia Keďže tento typ obmedzeniacute sa vyskytuje často existuje preň osobitneacute kľuacutečoveacute
slovo alldierent ndash tj všetky uvedeneacute premenneacute sa musia odlišovať Ako možno toto kľuacutečoveacute
slovo a ineacute kľuacutečoveacute slovaacute použiť v praxi uvidiacuteme na priacutekladoch neskocircr
22 Probleacutem SAT
Za špeciaacutelny priacutepad CSP možno považovať probleacutem spĺňania logickyacutech formuacutel (angl boolean satis-
ability problem SAT) V jeho priacutepade sa deničneacute oboryDi jednotlivyacutech premennyacutech redukujuacute
na Di = true false [1]
3 | Logickeacute programovanie ohraničeniacuteSysteacutemy na programovanie ohraničeniacute typicky integrujuacute koncepty z CP do nejakeacuteho už existu-
juacuteceho programovacieho jazyka Existuje veľkyacute počet implementaacuteciiacute pre mnoho rocircznych jazy-
kov Ako priacuteklady implementaacutecie v klasickyacutech imperatiacutevnych jazykoch možno uviesť knižnicu
Gecode pre C++ knižnicu or-tools ktoruacute možno použiacutevať z C++ Python-u Javy a NET alebo
javoveacute knižnice CHOCO a JaCoP
Osobitnuacute vetvu však tvoria logickeacute deklaratiacutevne jazyky ndash napriacuteklad Prolog ndash ktoreacute sa osobitne
hodia na integraacuteciu CP keďže s niacutem už mnoheacute koncepty zdieľajuacute Prolog napriacuteklad už obsahuje
koncept prehľadaacutevania s naacutevratom ktoryacute (ako uvidiacuteme) sa využiacuteva aj v CP [2]
middot 3 middot
Obr 41 Deničneacute obory premennyacutech v hracom poli Sudoku
Preto aj vyacutevoj v oblasti CP bol historicky do značnej miery spojenyacute praacuteve s jazykom Prolog
a s jeho rocircznymi nadstavbami ndash napr s jazykom CHIP ktoryacute zaviedol programovanie ohraničeniacute
na konečnyacutech deničnyacutech oboroch resp CLP(R) ktoreacute zaviedlo podporu pre ohraničenia na
reaacutelnych čiacuteslach [2] Ďalej ide o rocirczne prologoveacute systeacutemy ako napr ECLiPS
ea SICStus Prolog
[2] Knižnice pre programovanie ohraničeniacute existujuacute aj v inyacutech prologoch (napr clpfd pre SWI-
Prolog) V suacutevislosti s tyacutem sa hovoriacute o tzv logickom programovaniacute ohraničeniacute čiacutem sa mysliacute praacuteve
programovanie ohraničeniacute v raacutemci logickyacutech jazykov ako je Prolog
4 | Programovanie ohraničeniacute ako riešenie SudokuV tejto časti ilustrujeme zaacutekladneacute koncepty programovania ohraničeniacute na hre Sudoku čiacutem si
vybudujeme intuiacuteciu potrebnuacute pre nasledujuacuteci formaacutelnejšiacute vyacuteklad Vyššie sme ukaacutezali že hru
Sudoku možno veľmi prirodzenyacutem spocircsobom reprezentovať ako probleacutem spĺňania ohraničeniacute
(CSP)
Ak maacuteme Sudoku rozmeru 9 times 9 a F poliacutečok už maacute stanoveneacute hodnoty maacuteme 9 times 9 minusF premennyacutech ktoryacutech hodnoty musiacuteme stanoviť Deničnyacute obor každej z nich bude Di =1 2 9 Počiatočnyacute stav mocircžeme ilustrovať tak že do každeacuteho praacutezdneho poliacutečka vpiacutešeme
všetky hodnoty ktoreacute daneacute premennaacute mocircže nadobuacutedať Priacuteklad je na Obr 41
Ako vidno v hracom poli Obr 41 je preddenovanyacutech 31 poliacutečok Doplniť teda treba zvyš-
nyacutech 50 poliacutečok z ktoryacutech každeacute mocircže obsahovať hodnoty od 1 po 9 tak aby boli splneneacute všetky
ohraničenia
middot 4 middot
(a) (b) (c)
Obr 42 Postup pre ľavyacute hornyacute štvorcovyacute vyacutesek
41 Aplikaacutecia ohraničeniacute hry Sudoku
O ohraničeniach hry Sudoku sme hovorili vyššie teraz ich budeme ilustrovať na priacuteklade Ako
prveacute ohraničenie sme uviedli že dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9 Toto ohraničenie
sme už zahrnuli pri určeniacute deničneacuteho oboru premennyacutech ďalej ho teda uvažovať nemusiacuteme
Prejdeme teda postupne len ostatneacute ohraničenia
411 Štvorcoveacute ohraničenia
Začnime štvorcovyacutemi ohraničeniami Princiacutep budeme ilustrovať na štvorcovom vyacuteseku z ľaveacuteho
horneacuteho rohu ktoryacute je na Obr 42a Ako vidno tri poliacutečka už majuacute preddenovaneacute hodnoty
x22 = 5 x31 = 3 a x33 = 4 Keďže tie isteacute hodnoty sa v raacutemci štvorca nesmuacute opakovať viackraacutet
je jasneacute že z deničnyacutech oborov ostatnyacutech premennyacutech mocircžeme čiacutesla 3 4 a 5 vyluacutečiť ako to
ilustrujuacute Obr 42b a 42c
Aplikujme teda obdobnyacutem spocircsobom štvorcoveacute ohraničenia na všetky štvorce a pokračujme
ďalej riadkovyacutemi a stĺpcovyacutemi ohraničeniami
412 Riadkoveacute a stĺpcoveacute ohraničenia
Priacuteklad aplikaacutecie riadkoveacuteho ohraničenia pre prvyacute riadok je na Obr 43a Ako vidno v riadku sa
vyskytuje jedna preddenovanaacute hodnota ndash čiacuteslo 9 ktoruacute je potrebneacute vyluacutečiť z deničnyacutech oborov
všetkyacutech ostatnyacutech premennyacutech v danom riadku
Ak naacutesledne budeme ilustrovať priacuteklad stĺpcoveacuteho ohraničenia na ocircsmom stĺpci ziacuteskame
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
1 | UacutevodV suacutečasnosti existuje veľkeacute množstvo uacuteloh v raacutemci prebiehajuacuteceho vyacuteskumu aj podnikovej praxe
ktoreacute si vyžadujuacute ryacutechle a efektiacutevne riešenie diskreacutetnych optimalizačnyacutech uacuteloh Možno sem zara-
diť napriacuteklad probleacutemy rozvrhovania plaacutenovacie uacutelohy logistickuacute optimalizaacuteciu a mnoheacute ďalšie
Značnuacute časť z tyacutechto uacuteloh možno formulovať prostredniacutectvom premennyacutech a ohraničeniacute ndash
tj podmienok ktoreacute musia hodnoty premennyacutech spĺňať aby uacutelohu bolo možneacute považovať za
vyriešenuacute Na ilustraacuteciu možno uviesť napriacuteklad dobre znaacutemy probleacutem N daacutem kde je uacutelohou
rozmiestniť N daacutem na šachovnici takyacutem spocircsobom aby sa navzaacutejom neohrozovali hru Sudoku
či probleacutem smerovania vozidiel (angl vehicle routing problem)
Jednou zo znaacutemych a naďalej perspektiacutevnych metoacuted riešiacich uacutelohy tohto typu je progra-
movanie ohraničeniacute (angl constraint programming CP) V nasledujuacutecej štuacutedii sa budeme proble-
matike programovania ohraničeniacute venovať podrobnejšie ndash najprv formaacutelne denujeme probleacutem
spĺňania ohraničeniacute Zmysel deniacutecie vzaacutepaumltiacute budeme ilustrovať na hre Sudoku na ktorej naacutesledne
ozrejmiacuteme aj zaacutekladneacute prvky a princiacutepy programovania ohraničeniacute
Naacutesledne poskytneme aj formaacutelnejšiacute vyacuteklad a podrobnejšiacute prehľad o jednotlivyacutech konceptoch
v CP ako suacute propagaacutecia ohraničeniacute sklad ohraničeniacute overenie korektnosti globaacutelne ohraničenia
konzistenčneacute techniky a pod Postupy budeme na zaacutever ilustrovať niekoľkyacutemi priacutekladmi praktic-
kej implementaacutecie na modelovyacutech uacutelohaacutech
2 | Probleacutem spĺňania ohraničeniacute
Probleacutem spĺňania ohraničeniacute (angl constraint satisfaction problem CSP) možno charakterizovať
trojicou P = 〈XDC〉 [1]
bull X je n-tica premennyacutech X = 〈x1 x2 xn〉
bull D je n-tica ich zodpovedajuacutecich deničnyacutech oborov D = 〈D1 D2 Dn〉 tj xi isin Di
je relaacutecia nad premennyacutemiSj = rozsah(Cj)[1] Inyacutemi slovami možno povedať žeRSj
je podmnožina karteziaacutenskeho suacutečinu deničnyacutech obo-
rov premennyacutech z Sj [1]1
Riešeniacutem probleacutemu P je n-tica A = 〈a1 a2 an〉 takaacute že platiacute ai isin Di a každeacute ohraničenie
Cj je splneneacute tj pre projekciu A do rozsahu Sj platiacute relaacutecia RSj
1Ku relaacuteciaacutem a karteziaacutenskemu suacutečinu možno pozrieť viac v priacutelohe A
middot 1 middot
Obr 21 Hra Sudoku Obr 22 Hra Sudoku ndash riešenie
21 Formulaacutecia hry Sudoku ako CSP
Hra Sudoku je dobryacutem priacutekladom probleacutemu spĺňania ohraničeniacute Pozostaacuteva z hracieho poľa ur-
čityacutech rozmerov ndash najčastejšie 9times 9 Pole je navyše rozdeleneacute na 9 štvorcov rozmerov 3times 3 (viď
Obr 23) Každeacute poliacutečko mocircže obsahovať čiacuteslo od 1 po 9 Na začiatku hry suacute niektoreacute poliacutečka už
vyplneneacute ndash ostatneacute treba doplniť tak aby boli splneneacute predpiacutesaneacute podmienky
bull Dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9
bull Žiadne čiacuteslo v raacutemci toho isteacuteho stĺpca sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho riadku sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho štvorca sa nesmie opakovať viackraacutet
Ilustraacutecia hracieho poľa je na Obr 21 Vyplneneacute hracie pole je na Obr 22
Ak maacuteme Sudoku opiacutesať ako probleacutem spĺňania ohraničeniacute premenneacute X buduacute tvoriť hodnoty
jednotlivyacutech poliacutečok (dokopy ich bude 9times 9) Deničnyacute obor každej z nich je D = 1 2 9Ak jednotliveacute premenneacute usporiadame do matice mocircžeme ich preindexovať ako xmk kde m
je čiacuteslo riadku a k je čiacuteslo stĺpca Ak potom uvažujeme napriacuteklad ohraničenie pre prvyacute riadok
vieme že pre jeho rozsah platiacute Sr1 = x11 x12 x19 tj ohraničenie zahŕňa praacuteve premenneacute
z prveacuteho riadku
Relaacuteciu pre prvyacute riadok mocircžeme denovať nasledovne
RSr1 = x isin D9|x1i 6= x1j forall 1 le i j 6= 9 i 6= j (21)
middot 2 middot
Obr 23 Hra Sudoku ndash rozdelenie na štvorce
Zo všetkyacutech kombinaacuteciiacute hodnocirct premennyacutech (D9) vyberaacuteme teda len takeacute dosadenia x pri ktoryacutech
platiacute že z hodnocirct v riadku 1 ani dve nie suacute rovnakeacute
Obmedzenie (21) možno zovšeobecniť pre ľubovoľnyacute riadok a obdobne možno denovať os-
tatneacute obmedzenia Keďže tento typ obmedzeniacute sa vyskytuje často existuje preň osobitneacute kľuacutečoveacute
slovo alldierent ndash tj všetky uvedeneacute premenneacute sa musia odlišovať Ako možno toto kľuacutečoveacute
slovo a ineacute kľuacutečoveacute slovaacute použiť v praxi uvidiacuteme na priacutekladoch neskocircr
22 Probleacutem SAT
Za špeciaacutelny priacutepad CSP možno považovať probleacutem spĺňania logickyacutech formuacutel (angl boolean satis-
ability problem SAT) V jeho priacutepade sa deničneacute oboryDi jednotlivyacutech premennyacutech redukujuacute
na Di = true false [1]
3 | Logickeacute programovanie ohraničeniacuteSysteacutemy na programovanie ohraničeniacute typicky integrujuacute koncepty z CP do nejakeacuteho už existu-
juacuteceho programovacieho jazyka Existuje veľkyacute počet implementaacuteciiacute pre mnoho rocircznych jazy-
kov Ako priacuteklady implementaacutecie v klasickyacutech imperatiacutevnych jazykoch možno uviesť knižnicu
Gecode pre C++ knižnicu or-tools ktoruacute možno použiacutevať z C++ Python-u Javy a NET alebo
javoveacute knižnice CHOCO a JaCoP
Osobitnuacute vetvu však tvoria logickeacute deklaratiacutevne jazyky ndash napriacuteklad Prolog ndash ktoreacute sa osobitne
hodia na integraacuteciu CP keďže s niacutem už mnoheacute koncepty zdieľajuacute Prolog napriacuteklad už obsahuje
koncept prehľadaacutevania s naacutevratom ktoryacute (ako uvidiacuteme) sa využiacuteva aj v CP [2]
middot 3 middot
Obr 41 Deničneacute obory premennyacutech v hracom poli Sudoku
Preto aj vyacutevoj v oblasti CP bol historicky do značnej miery spojenyacute praacuteve s jazykom Prolog
a s jeho rocircznymi nadstavbami ndash napr s jazykom CHIP ktoryacute zaviedol programovanie ohraničeniacute
na konečnyacutech deničnyacutech oboroch resp CLP(R) ktoreacute zaviedlo podporu pre ohraničenia na
reaacutelnych čiacuteslach [2] Ďalej ide o rocirczne prologoveacute systeacutemy ako napr ECLiPS
ea SICStus Prolog
[2] Knižnice pre programovanie ohraničeniacute existujuacute aj v inyacutech prologoch (napr clpfd pre SWI-
Prolog) V suacutevislosti s tyacutem sa hovoriacute o tzv logickom programovaniacute ohraničeniacute čiacutem sa mysliacute praacuteve
programovanie ohraničeniacute v raacutemci logickyacutech jazykov ako je Prolog
4 | Programovanie ohraničeniacute ako riešenie SudokuV tejto časti ilustrujeme zaacutekladneacute koncepty programovania ohraničeniacute na hre Sudoku čiacutem si
vybudujeme intuiacuteciu potrebnuacute pre nasledujuacuteci formaacutelnejšiacute vyacuteklad Vyššie sme ukaacutezali že hru
Sudoku možno veľmi prirodzenyacutem spocircsobom reprezentovať ako probleacutem spĺňania ohraničeniacute
(CSP)
Ak maacuteme Sudoku rozmeru 9 times 9 a F poliacutečok už maacute stanoveneacute hodnoty maacuteme 9 times 9 minusF premennyacutech ktoryacutech hodnoty musiacuteme stanoviť Deničnyacute obor každej z nich bude Di =1 2 9 Počiatočnyacute stav mocircžeme ilustrovať tak že do každeacuteho praacutezdneho poliacutečka vpiacutešeme
všetky hodnoty ktoreacute daneacute premennaacute mocircže nadobuacutedať Priacuteklad je na Obr 41
Ako vidno v hracom poli Obr 41 je preddenovanyacutech 31 poliacutečok Doplniť teda treba zvyš-
nyacutech 50 poliacutečok z ktoryacutech každeacute mocircže obsahovať hodnoty od 1 po 9 tak aby boli splneneacute všetky
ohraničenia
middot 4 middot
(a) (b) (c)
Obr 42 Postup pre ľavyacute hornyacute štvorcovyacute vyacutesek
41 Aplikaacutecia ohraničeniacute hry Sudoku
O ohraničeniach hry Sudoku sme hovorili vyššie teraz ich budeme ilustrovať na priacuteklade Ako
prveacute ohraničenie sme uviedli že dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9 Toto ohraničenie
sme už zahrnuli pri určeniacute deničneacuteho oboru premennyacutech ďalej ho teda uvažovať nemusiacuteme
Prejdeme teda postupne len ostatneacute ohraničenia
411 Štvorcoveacute ohraničenia
Začnime štvorcovyacutemi ohraničeniami Princiacutep budeme ilustrovať na štvorcovom vyacuteseku z ľaveacuteho
horneacuteho rohu ktoryacute je na Obr 42a Ako vidno tri poliacutečka už majuacute preddenovaneacute hodnoty
x22 = 5 x31 = 3 a x33 = 4 Keďže tie isteacute hodnoty sa v raacutemci štvorca nesmuacute opakovať viackraacutet
je jasneacute že z deničnyacutech oborov ostatnyacutech premennyacutech mocircžeme čiacutesla 3 4 a 5 vyluacutečiť ako to
ilustrujuacute Obr 42b a 42c
Aplikujme teda obdobnyacutem spocircsobom štvorcoveacute ohraničenia na všetky štvorce a pokračujme
ďalej riadkovyacutemi a stĺpcovyacutemi ohraničeniami
412 Riadkoveacute a stĺpcoveacute ohraničenia
Priacuteklad aplikaacutecie riadkoveacuteho ohraničenia pre prvyacute riadok je na Obr 43a Ako vidno v riadku sa
vyskytuje jedna preddenovanaacute hodnota ndash čiacuteslo 9 ktoruacute je potrebneacute vyluacutečiť z deničnyacutech oborov
všetkyacutech ostatnyacutech premennyacutech v danom riadku
Ak naacutesledne budeme ilustrovať priacuteklad stĺpcoveacuteho ohraničenia na ocircsmom stĺpci ziacuteskame
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Obr 21 Hra Sudoku Obr 22 Hra Sudoku ndash riešenie
21 Formulaacutecia hry Sudoku ako CSP
Hra Sudoku je dobryacutem priacutekladom probleacutemu spĺňania ohraničeniacute Pozostaacuteva z hracieho poľa ur-
čityacutech rozmerov ndash najčastejšie 9times 9 Pole je navyše rozdeleneacute na 9 štvorcov rozmerov 3times 3 (viď
Obr 23) Každeacute poliacutečko mocircže obsahovať čiacuteslo od 1 po 9 Na začiatku hry suacute niektoreacute poliacutečka už
vyplneneacute ndash ostatneacute treba doplniť tak aby boli splneneacute predpiacutesaneacute podmienky
bull Dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9
bull Žiadne čiacuteslo v raacutemci toho isteacuteho stĺpca sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho riadku sa nesmie opakovať viackraacutet
bull Žiadne čiacuteslo v raacutemci toho isteacuteho štvorca sa nesmie opakovať viackraacutet
Ilustraacutecia hracieho poľa je na Obr 21 Vyplneneacute hracie pole je na Obr 22
Ak maacuteme Sudoku opiacutesať ako probleacutem spĺňania ohraničeniacute premenneacute X buduacute tvoriť hodnoty
jednotlivyacutech poliacutečok (dokopy ich bude 9times 9) Deničnyacute obor každej z nich je D = 1 2 9Ak jednotliveacute premenneacute usporiadame do matice mocircžeme ich preindexovať ako xmk kde m
je čiacuteslo riadku a k je čiacuteslo stĺpca Ak potom uvažujeme napriacuteklad ohraničenie pre prvyacute riadok
vieme že pre jeho rozsah platiacute Sr1 = x11 x12 x19 tj ohraničenie zahŕňa praacuteve premenneacute
z prveacuteho riadku
Relaacuteciu pre prvyacute riadok mocircžeme denovať nasledovne
RSr1 = x isin D9|x1i 6= x1j forall 1 le i j 6= 9 i 6= j (21)
middot 2 middot
Obr 23 Hra Sudoku ndash rozdelenie na štvorce
Zo všetkyacutech kombinaacuteciiacute hodnocirct premennyacutech (D9) vyberaacuteme teda len takeacute dosadenia x pri ktoryacutech
platiacute že z hodnocirct v riadku 1 ani dve nie suacute rovnakeacute
Obmedzenie (21) možno zovšeobecniť pre ľubovoľnyacute riadok a obdobne možno denovať os-
tatneacute obmedzenia Keďže tento typ obmedzeniacute sa vyskytuje často existuje preň osobitneacute kľuacutečoveacute
slovo alldierent ndash tj všetky uvedeneacute premenneacute sa musia odlišovať Ako možno toto kľuacutečoveacute
slovo a ineacute kľuacutečoveacute slovaacute použiť v praxi uvidiacuteme na priacutekladoch neskocircr
22 Probleacutem SAT
Za špeciaacutelny priacutepad CSP možno považovať probleacutem spĺňania logickyacutech formuacutel (angl boolean satis-
ability problem SAT) V jeho priacutepade sa deničneacute oboryDi jednotlivyacutech premennyacutech redukujuacute
na Di = true false [1]
3 | Logickeacute programovanie ohraničeniacuteSysteacutemy na programovanie ohraničeniacute typicky integrujuacute koncepty z CP do nejakeacuteho už existu-
juacuteceho programovacieho jazyka Existuje veľkyacute počet implementaacuteciiacute pre mnoho rocircznych jazy-
kov Ako priacuteklady implementaacutecie v klasickyacutech imperatiacutevnych jazykoch možno uviesť knižnicu
Gecode pre C++ knižnicu or-tools ktoruacute možno použiacutevať z C++ Python-u Javy a NET alebo
javoveacute knižnice CHOCO a JaCoP
Osobitnuacute vetvu však tvoria logickeacute deklaratiacutevne jazyky ndash napriacuteklad Prolog ndash ktoreacute sa osobitne
hodia na integraacuteciu CP keďže s niacutem už mnoheacute koncepty zdieľajuacute Prolog napriacuteklad už obsahuje
koncept prehľadaacutevania s naacutevratom ktoryacute (ako uvidiacuteme) sa využiacuteva aj v CP [2]
middot 3 middot
Obr 41 Deničneacute obory premennyacutech v hracom poli Sudoku
Preto aj vyacutevoj v oblasti CP bol historicky do značnej miery spojenyacute praacuteve s jazykom Prolog
a s jeho rocircznymi nadstavbami ndash napr s jazykom CHIP ktoryacute zaviedol programovanie ohraničeniacute
na konečnyacutech deničnyacutech oboroch resp CLP(R) ktoreacute zaviedlo podporu pre ohraničenia na
reaacutelnych čiacuteslach [2] Ďalej ide o rocirczne prologoveacute systeacutemy ako napr ECLiPS
ea SICStus Prolog
[2] Knižnice pre programovanie ohraničeniacute existujuacute aj v inyacutech prologoch (napr clpfd pre SWI-
Prolog) V suacutevislosti s tyacutem sa hovoriacute o tzv logickom programovaniacute ohraničeniacute čiacutem sa mysliacute praacuteve
programovanie ohraničeniacute v raacutemci logickyacutech jazykov ako je Prolog
4 | Programovanie ohraničeniacute ako riešenie SudokuV tejto časti ilustrujeme zaacutekladneacute koncepty programovania ohraničeniacute na hre Sudoku čiacutem si
vybudujeme intuiacuteciu potrebnuacute pre nasledujuacuteci formaacutelnejšiacute vyacuteklad Vyššie sme ukaacutezali že hru
Sudoku možno veľmi prirodzenyacutem spocircsobom reprezentovať ako probleacutem spĺňania ohraničeniacute
(CSP)
Ak maacuteme Sudoku rozmeru 9 times 9 a F poliacutečok už maacute stanoveneacute hodnoty maacuteme 9 times 9 minusF premennyacutech ktoryacutech hodnoty musiacuteme stanoviť Deničnyacute obor každej z nich bude Di =1 2 9 Počiatočnyacute stav mocircžeme ilustrovať tak že do každeacuteho praacutezdneho poliacutečka vpiacutešeme
všetky hodnoty ktoreacute daneacute premennaacute mocircže nadobuacutedať Priacuteklad je na Obr 41
Ako vidno v hracom poli Obr 41 je preddenovanyacutech 31 poliacutečok Doplniť teda treba zvyš-
nyacutech 50 poliacutečok z ktoryacutech každeacute mocircže obsahovať hodnoty od 1 po 9 tak aby boli splneneacute všetky
ohraničenia
middot 4 middot
(a) (b) (c)
Obr 42 Postup pre ľavyacute hornyacute štvorcovyacute vyacutesek
41 Aplikaacutecia ohraničeniacute hry Sudoku
O ohraničeniach hry Sudoku sme hovorili vyššie teraz ich budeme ilustrovať na priacuteklade Ako
prveacute ohraničenie sme uviedli že dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9 Toto ohraničenie
sme už zahrnuli pri určeniacute deničneacuteho oboru premennyacutech ďalej ho teda uvažovať nemusiacuteme
Prejdeme teda postupne len ostatneacute ohraničenia
411 Štvorcoveacute ohraničenia
Začnime štvorcovyacutemi ohraničeniami Princiacutep budeme ilustrovať na štvorcovom vyacuteseku z ľaveacuteho
horneacuteho rohu ktoryacute je na Obr 42a Ako vidno tri poliacutečka už majuacute preddenovaneacute hodnoty
x22 = 5 x31 = 3 a x33 = 4 Keďže tie isteacute hodnoty sa v raacutemci štvorca nesmuacute opakovať viackraacutet
je jasneacute že z deničnyacutech oborov ostatnyacutech premennyacutech mocircžeme čiacutesla 3 4 a 5 vyluacutečiť ako to
ilustrujuacute Obr 42b a 42c
Aplikujme teda obdobnyacutem spocircsobom štvorcoveacute ohraničenia na všetky štvorce a pokračujme
ďalej riadkovyacutemi a stĺpcovyacutemi ohraničeniami
412 Riadkoveacute a stĺpcoveacute ohraničenia
Priacuteklad aplikaacutecie riadkoveacuteho ohraničenia pre prvyacute riadok je na Obr 43a Ako vidno v riadku sa
vyskytuje jedna preddenovanaacute hodnota ndash čiacuteslo 9 ktoruacute je potrebneacute vyluacutečiť z deničnyacutech oborov
všetkyacutech ostatnyacutech premennyacutech v danom riadku
Ak naacutesledne budeme ilustrovať priacuteklad stĺpcoveacuteho ohraničenia na ocircsmom stĺpci ziacuteskame
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Obr 23 Hra Sudoku ndash rozdelenie na štvorce
Zo všetkyacutech kombinaacuteciiacute hodnocirct premennyacutech (D9) vyberaacuteme teda len takeacute dosadenia x pri ktoryacutech
platiacute že z hodnocirct v riadku 1 ani dve nie suacute rovnakeacute
Obmedzenie (21) možno zovšeobecniť pre ľubovoľnyacute riadok a obdobne možno denovať os-
tatneacute obmedzenia Keďže tento typ obmedzeniacute sa vyskytuje často existuje preň osobitneacute kľuacutečoveacute
slovo alldierent ndash tj všetky uvedeneacute premenneacute sa musia odlišovať Ako možno toto kľuacutečoveacute
slovo a ineacute kľuacutečoveacute slovaacute použiť v praxi uvidiacuteme na priacutekladoch neskocircr
22 Probleacutem SAT
Za špeciaacutelny priacutepad CSP možno považovať probleacutem spĺňania logickyacutech formuacutel (angl boolean satis-
ability problem SAT) V jeho priacutepade sa deničneacute oboryDi jednotlivyacutech premennyacutech redukujuacute
na Di = true false [1]
3 | Logickeacute programovanie ohraničeniacuteSysteacutemy na programovanie ohraničeniacute typicky integrujuacute koncepty z CP do nejakeacuteho už existu-
juacuteceho programovacieho jazyka Existuje veľkyacute počet implementaacuteciiacute pre mnoho rocircznych jazy-
kov Ako priacuteklady implementaacutecie v klasickyacutech imperatiacutevnych jazykoch možno uviesť knižnicu
Gecode pre C++ knižnicu or-tools ktoruacute možno použiacutevať z C++ Python-u Javy a NET alebo
javoveacute knižnice CHOCO a JaCoP
Osobitnuacute vetvu však tvoria logickeacute deklaratiacutevne jazyky ndash napriacuteklad Prolog ndash ktoreacute sa osobitne
hodia na integraacuteciu CP keďže s niacutem už mnoheacute koncepty zdieľajuacute Prolog napriacuteklad už obsahuje
koncept prehľadaacutevania s naacutevratom ktoryacute (ako uvidiacuteme) sa využiacuteva aj v CP [2]
middot 3 middot
Obr 41 Deničneacute obory premennyacutech v hracom poli Sudoku
Preto aj vyacutevoj v oblasti CP bol historicky do značnej miery spojenyacute praacuteve s jazykom Prolog
a s jeho rocircznymi nadstavbami ndash napr s jazykom CHIP ktoryacute zaviedol programovanie ohraničeniacute
na konečnyacutech deničnyacutech oboroch resp CLP(R) ktoreacute zaviedlo podporu pre ohraničenia na
reaacutelnych čiacuteslach [2] Ďalej ide o rocirczne prologoveacute systeacutemy ako napr ECLiPS
ea SICStus Prolog
[2] Knižnice pre programovanie ohraničeniacute existujuacute aj v inyacutech prologoch (napr clpfd pre SWI-
Prolog) V suacutevislosti s tyacutem sa hovoriacute o tzv logickom programovaniacute ohraničeniacute čiacutem sa mysliacute praacuteve
programovanie ohraničeniacute v raacutemci logickyacutech jazykov ako je Prolog
4 | Programovanie ohraničeniacute ako riešenie SudokuV tejto časti ilustrujeme zaacutekladneacute koncepty programovania ohraničeniacute na hre Sudoku čiacutem si
vybudujeme intuiacuteciu potrebnuacute pre nasledujuacuteci formaacutelnejšiacute vyacuteklad Vyššie sme ukaacutezali že hru
Sudoku možno veľmi prirodzenyacutem spocircsobom reprezentovať ako probleacutem spĺňania ohraničeniacute
(CSP)
Ak maacuteme Sudoku rozmeru 9 times 9 a F poliacutečok už maacute stanoveneacute hodnoty maacuteme 9 times 9 minusF premennyacutech ktoryacutech hodnoty musiacuteme stanoviť Deničnyacute obor každej z nich bude Di =1 2 9 Počiatočnyacute stav mocircžeme ilustrovať tak že do každeacuteho praacutezdneho poliacutečka vpiacutešeme
všetky hodnoty ktoreacute daneacute premennaacute mocircže nadobuacutedať Priacuteklad je na Obr 41
Ako vidno v hracom poli Obr 41 je preddenovanyacutech 31 poliacutečok Doplniť teda treba zvyš-
nyacutech 50 poliacutečok z ktoryacutech každeacute mocircže obsahovať hodnoty od 1 po 9 tak aby boli splneneacute všetky
ohraničenia
middot 4 middot
(a) (b) (c)
Obr 42 Postup pre ľavyacute hornyacute štvorcovyacute vyacutesek
41 Aplikaacutecia ohraničeniacute hry Sudoku
O ohraničeniach hry Sudoku sme hovorili vyššie teraz ich budeme ilustrovať na priacuteklade Ako
prveacute ohraničenie sme uviedli že dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9 Toto ohraničenie
sme už zahrnuli pri určeniacute deničneacuteho oboru premennyacutech ďalej ho teda uvažovať nemusiacuteme
Prejdeme teda postupne len ostatneacute ohraničenia
411 Štvorcoveacute ohraničenia
Začnime štvorcovyacutemi ohraničeniami Princiacutep budeme ilustrovať na štvorcovom vyacuteseku z ľaveacuteho
horneacuteho rohu ktoryacute je na Obr 42a Ako vidno tri poliacutečka už majuacute preddenovaneacute hodnoty
x22 = 5 x31 = 3 a x33 = 4 Keďže tie isteacute hodnoty sa v raacutemci štvorca nesmuacute opakovať viackraacutet
je jasneacute že z deničnyacutech oborov ostatnyacutech premennyacutech mocircžeme čiacutesla 3 4 a 5 vyluacutečiť ako to
ilustrujuacute Obr 42b a 42c
Aplikujme teda obdobnyacutem spocircsobom štvorcoveacute ohraničenia na všetky štvorce a pokračujme
ďalej riadkovyacutemi a stĺpcovyacutemi ohraničeniami
412 Riadkoveacute a stĺpcoveacute ohraničenia
Priacuteklad aplikaacutecie riadkoveacuteho ohraničenia pre prvyacute riadok je na Obr 43a Ako vidno v riadku sa
vyskytuje jedna preddenovanaacute hodnota ndash čiacuteslo 9 ktoruacute je potrebneacute vyluacutečiť z deničnyacutech oborov
všetkyacutech ostatnyacutech premennyacutech v danom riadku
Ak naacutesledne budeme ilustrovať priacuteklad stĺpcoveacuteho ohraničenia na ocircsmom stĺpci ziacuteskame
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Obr 41 Deničneacute obory premennyacutech v hracom poli Sudoku
Preto aj vyacutevoj v oblasti CP bol historicky do značnej miery spojenyacute praacuteve s jazykom Prolog
a s jeho rocircznymi nadstavbami ndash napr s jazykom CHIP ktoryacute zaviedol programovanie ohraničeniacute
na konečnyacutech deničnyacutech oboroch resp CLP(R) ktoreacute zaviedlo podporu pre ohraničenia na
reaacutelnych čiacuteslach [2] Ďalej ide o rocirczne prologoveacute systeacutemy ako napr ECLiPS
ea SICStus Prolog
[2] Knižnice pre programovanie ohraničeniacute existujuacute aj v inyacutech prologoch (napr clpfd pre SWI-
Prolog) V suacutevislosti s tyacutem sa hovoriacute o tzv logickom programovaniacute ohraničeniacute čiacutem sa mysliacute praacuteve
programovanie ohraničeniacute v raacutemci logickyacutech jazykov ako je Prolog
4 | Programovanie ohraničeniacute ako riešenie SudokuV tejto časti ilustrujeme zaacutekladneacute koncepty programovania ohraničeniacute na hre Sudoku čiacutem si
vybudujeme intuiacuteciu potrebnuacute pre nasledujuacuteci formaacutelnejšiacute vyacuteklad Vyššie sme ukaacutezali že hru
Sudoku možno veľmi prirodzenyacutem spocircsobom reprezentovať ako probleacutem spĺňania ohraničeniacute
(CSP)
Ak maacuteme Sudoku rozmeru 9 times 9 a F poliacutečok už maacute stanoveneacute hodnoty maacuteme 9 times 9 minusF premennyacutech ktoryacutech hodnoty musiacuteme stanoviť Deničnyacute obor každej z nich bude Di =1 2 9 Počiatočnyacute stav mocircžeme ilustrovať tak že do každeacuteho praacutezdneho poliacutečka vpiacutešeme
všetky hodnoty ktoreacute daneacute premennaacute mocircže nadobuacutedať Priacuteklad je na Obr 41
Ako vidno v hracom poli Obr 41 je preddenovanyacutech 31 poliacutečok Doplniť teda treba zvyš-
nyacutech 50 poliacutečok z ktoryacutech každeacute mocircže obsahovať hodnoty od 1 po 9 tak aby boli splneneacute všetky
ohraničenia
middot 4 middot
(a) (b) (c)
Obr 42 Postup pre ľavyacute hornyacute štvorcovyacute vyacutesek
41 Aplikaacutecia ohraničeniacute hry Sudoku
O ohraničeniach hry Sudoku sme hovorili vyššie teraz ich budeme ilustrovať na priacuteklade Ako
prveacute ohraničenie sme uviedli že dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9 Toto ohraničenie
sme už zahrnuli pri určeniacute deničneacuteho oboru premennyacutech ďalej ho teda uvažovať nemusiacuteme
Prejdeme teda postupne len ostatneacute ohraničenia
411 Štvorcoveacute ohraničenia
Začnime štvorcovyacutemi ohraničeniami Princiacutep budeme ilustrovať na štvorcovom vyacuteseku z ľaveacuteho
horneacuteho rohu ktoryacute je na Obr 42a Ako vidno tri poliacutečka už majuacute preddenovaneacute hodnoty
x22 = 5 x31 = 3 a x33 = 4 Keďže tie isteacute hodnoty sa v raacutemci štvorca nesmuacute opakovať viackraacutet
je jasneacute že z deničnyacutech oborov ostatnyacutech premennyacutech mocircžeme čiacutesla 3 4 a 5 vyluacutečiť ako to
ilustrujuacute Obr 42b a 42c
Aplikujme teda obdobnyacutem spocircsobom štvorcoveacute ohraničenia na všetky štvorce a pokračujme
ďalej riadkovyacutemi a stĺpcovyacutemi ohraničeniami
412 Riadkoveacute a stĺpcoveacute ohraničenia
Priacuteklad aplikaacutecie riadkoveacuteho ohraničenia pre prvyacute riadok je na Obr 43a Ako vidno v riadku sa
vyskytuje jedna preddenovanaacute hodnota ndash čiacuteslo 9 ktoruacute je potrebneacute vyluacutečiť z deničnyacutech oborov
všetkyacutech ostatnyacutech premennyacutech v danom riadku
Ak naacutesledne budeme ilustrovať priacuteklad stĺpcoveacuteho ohraničenia na ocircsmom stĺpci ziacuteskame
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
(a) (b) (c)
Obr 42 Postup pre ľavyacute hornyacute štvorcovyacute vyacutesek
41 Aplikaacutecia ohraničeniacute hry Sudoku
O ohraničeniach hry Sudoku sme hovorili vyššie teraz ich budeme ilustrovať na priacuteklade Ako
prveacute ohraničenie sme uviedli že dopĺňaneacute čiacutesla musia byť z rozsahu 1 až 9 Toto ohraničenie
sme už zahrnuli pri určeniacute deničneacuteho oboru premennyacutech ďalej ho teda uvažovať nemusiacuteme
Prejdeme teda postupne len ostatneacute ohraničenia
411 Štvorcoveacute ohraničenia
Začnime štvorcovyacutemi ohraničeniami Princiacutep budeme ilustrovať na štvorcovom vyacuteseku z ľaveacuteho
horneacuteho rohu ktoryacute je na Obr 42a Ako vidno tri poliacutečka už majuacute preddenovaneacute hodnoty
x22 = 5 x31 = 3 a x33 = 4 Keďže tie isteacute hodnoty sa v raacutemci štvorca nesmuacute opakovať viackraacutet
je jasneacute že z deničnyacutech oborov ostatnyacutech premennyacutech mocircžeme čiacutesla 3 4 a 5 vyluacutečiť ako to
ilustrujuacute Obr 42b a 42c
Aplikujme teda obdobnyacutem spocircsobom štvorcoveacute ohraničenia na všetky štvorce a pokračujme
ďalej riadkovyacutemi a stĺpcovyacutemi ohraničeniami
412 Riadkoveacute a stĺpcoveacute ohraničenia
Priacuteklad aplikaacutecie riadkoveacuteho ohraničenia pre prvyacute riadok je na Obr 43a Ako vidno v riadku sa
vyskytuje jedna preddenovanaacute hodnota ndash čiacuteslo 9 ktoruacute je potrebneacute vyluacutečiť z deničnyacutech oborov
všetkyacutech ostatnyacutech premennyacutech v danom riadku
Ak naacutesledne budeme ilustrovať priacuteklad stĺpcoveacuteho ohraničenia na ocircsmom stĺpci ziacuteskame
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Obr 44 Po aplikaacutecii ohraničeniacute vieme určiť
niektoreacute hodnoty
Obr 45 Vyacutesledok po ďalšom kroku aplikaacutecie
ohraničeniacute
43 Vetvenie
Ak ďalej opakovane aplikujeme ohraničenia ziacuteskame napokon konguraacuteciu na Obr 46 z kto-
rej už nemožno vyluacutečiť ďalšie hodnoty Musiacuteme preto hodnotu niektorej premennej zvoliť Na
tomto mieste dochaacutedza k vetveniu keďže voliacuteme z viaceryacutech možnostiacute Postup je analogickyacute kla-
sickyacutem metoacutedam prehľadaacutevania stavoveacuteho priestoru s naacutevratom (angl backtracking) ndash naacutevrat sa
uskutočniacute ak zistiacuteme že pre zvoleneacute hodnoty probleacutem nemaacute riešenie Ak je uacutelohou naacutejsť všetky
riešenia preskuacutemajuacute sa alternatiacutevne možnosti v každej vetve aj vtedy ak sa už riešenie našlo
Pre premennuacute x11 sme zatiaľ nevyluacutečili hodnoty 1 a 6 Pokuacutesme sa teda zvoliť x11 = 1 a od
toho bodu znovu aplikovať ohraničenia Postup ilustruje Obr 47
Vetvenie ku ktoreacutemu tu dochaacutedza schmematicky zobrazuje Obr 48 Ako vidno voliacuteme hod-
notu 1 pre ktoruacute Ďalej pokračuje postup hľadania riešenia Hodnota 6 zostaacuteva zatiaľ bokom ndash
otvoriacute sa v priacutepade že docircjde k naacutevratu
431 Naacutevrat
Voľbou x11 = 1 sa naacutem opaumlť otvorila možnosť vyluacutečiť aplikaacuteciou ohraničeniacute niektoreacute hodnoty
z deničnyacutech oborov premennyacutech Takto ziacuteskame konguraacuteciu na Obr 411 Tu sa opaumlť dosta-
neme do situaacutecie kedy docircjde k vetveniu Tento raz voliacuteme hodnotu premennej x14 = 3 (vetvenie
na Obr 49)
Pri ďalšom riešeniacute vznikne novaacute situaacutecia ndash ako vidno na Obr 412 deničnyacute obor premennej
x46 sa celkom vypraacutezdnil ndash neviem teda pre tuacuteto premennuacute zvoliť takuacute hodnotu ktoraacute by bola
middot 7 middot
Obr 46 Stav po aplikaacutecii ohraničeniacute Obr 47 Voliacuteme hodnotu 1 pre x11
Obr 48 Vetvenie pre x11
Obr 49 Vetvenie pre x14 Obr 410 Vetvenie pre x14 ndash naacutevrat
middot 8 middot
Obr 411 Voliacuteme hodnotu 3 pre x14 Obr 412 Stav po aplikaacutecii ohraničeniacute ndash
praacutezdny deničnyacute obor
schopnaacute splniť obmedzenia Ako sme povedali v takomto priacutepade musiacuteme uskutočniť naacutevrat
k posledneacutemu vetveniu ndash hodnotu x14 = 3 teda zamietneme a namiesto nej voliacuteme x14 = 7 ako
to ilustruje Obr 410
Ďalej by sme postupovali obdobne v našom priacutepade už opakovanou aplikaacuteciou ohraničeniacute
dospejeme k riešeniu bez ďalšieho vetvenia
432 Strateacutegie vetvenia
Keďže pri vetveniacute maacuteme možnosť vybrať si premennuacute ktorej hodnotu budeme voliť vyvstaacuteva
otaacutezka ktoruacute premennuacute je najlepšie vybrať resp ktoruacute jej hodnotu zvoliť V tejto suacutevislosti je
priacutepustnyacutech viacero spocircsobov ndash existujuacute viacereacute strateacutegie vetvenia ndash mocircžeme sa napriacuteklad po-
kuacutešať voliť premenneacute s čo najmenšiacutem počtom zostaacutevajuacutecich hodnocirct aplikovať určituacute heuristiku
alebo jednoducho zvoliť povedzme prehľadaacutevanie do hĺbky
5 | Zaacutekladneacute koncepty v CPV tejto časti prejdeme zaacutekladneacute koncepty v programovaniacute ohraničeniacute Vaumlčšinu z nich sme už
ilustrovali na priacuteklade hry Sudoku vyššie Na tomto mieste teda budeme stavať na ziacuteskanej intuiacutecii
a poznatky len zovšeobecniacuteme a doplniacuteme
middot 9 middot
Prehľadaacutevanie Sklad ohraničeniacute
Obr 51 Sklad ohraničeniacute a prehľadaacutevanie
scheacutema interakcie [3]
Nesplniteľneacute
Prehľadaacutevanie Sklad ohraničeniacute
Splniteľneacute
1
2
Obr 52 Sklad ohraničeniacute a prehľadaacutevanie priacute-
klad interakcie [3]
51 Sklad ohraničeniacute
Blok CP systeacutemu ktoryacute spravuje ohraničenia a zabezpečuje ich aplikaacuteciu nazyacutevame sklad ohrani-
čeniacute (angl constraint store) Ako sme už videli vyššie v priacuteklade s hrou Sudoku v CP interagujuacute
spolu dva procesy ndash proces prehľadaacutevania (vetvenie) a proces aplikaacutecie ohraničeniacute
511 Interakcia prehľadaacutevania a skladu ohraničeniacute
Schematickeacute znaacutezornenie je na Obr 51 Ako vidno medzi blokom bdquoprehľadaacutevanieldquo a blokom
bdquosklad ohraničeniacuteldquo prebieha obojsmernaacute komunikaacutecia Sklad ohraničeniacute dostane na začiatku pre-
menneacute spolu s ich deničnyacutemi obormi a ohraničenia Naacutesledne ohraničenia aplikuje čo vedie
k dvom cieľom
1 Vyhodnotiť splniteľnosť (overenie korektnosti) či vocircbec existujuacute takeacute hodnoty pre-
mennyacutech pri ktoryacutech suacute splneneacute všetky ohraničenia
2 Vyluacutečiť niektoreacute hodnoty (propagaacutecia ohraničeniacute) z deničnyacutech oborov premennyacutech
sa odstraacutenia tie hodnoty pri ktoryacutech nemožno splniť niektoreacute ohraničenie
Po tejto prvej aplikaacutecii ohraničeniacute ndash keď sklad ohraničeniacute vyluacuteči čo najviac hodnocirct povie
bloku prehľadaacutevanie že uacuteloha je splniteľnaacute Blok prehľadaacutevanie naacutesledne zvoliacute pre niektoruacute pre-
mennuacute hodnotu (vetvenie) a navrhne skladu ohraničeniacute pridať ju ako ďalšie ohraničenie
Priacuteklad je na Obr 52 ndash prehľadaacutevanie navrhuje priradiť X = 5 Sklad ohraničeniacute znovu
s použitiacutem tohto noveacuteho ohraničenia vyluacuteči čo najviac hodnocirct a vyhodnotiacute splniteľnosť Odpovie
že uacuteloha je splniteľnaacute
Blok prehľadaacutevanie teda znovu navrhne hodnotu ndash v našom priacuteklade hodnotu Y 6= 2 (ako
vidno je priacutepustneacute voliť nielen konkreacutetne hodnoty ale sa dajuacute pridať aj ineacute typy ohraničeniacute) Sklad
ohraničeniacute aplikuje rovnakyacute postup Tento raz však zistiacute že ohraničenia už nie suacute splniteľneacute Tuacuteto
informaacuteciu komunikuje naspaumlť bloku prehľadaacutevanie ktoryacute sa navraacuteti k posledneacutemu vetveniu
a navrhne inuacute hodnotu
middot 10 middot
Prehľadaacutevanie
Sklad ohraničeniacute
Definičneacute obory
hellip
Ohraničenia
Obr 53 Scheacutema skladu ohraničeniacute [3]
512 Propagaacutecia ohraničeniacute
Ako sme už ukaacutezali sklad aplikaacuteciou ohraničeniacute zabezpečuje dve funkcie (a) propagaacuteciu ohra-
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Obr 46 Stav po aplikaacutecii ohraničeniacute Obr 47 Voliacuteme hodnotu 1 pre x11
Obr 48 Vetvenie pre x11
Obr 49 Vetvenie pre x14 Obr 410 Vetvenie pre x14 ndash naacutevrat
middot 8 middot
Obr 411 Voliacuteme hodnotu 3 pre x14 Obr 412 Stav po aplikaacutecii ohraničeniacute ndash
praacutezdny deničnyacute obor
schopnaacute splniť obmedzenia Ako sme povedali v takomto priacutepade musiacuteme uskutočniť naacutevrat
k posledneacutemu vetveniu ndash hodnotu x14 = 3 teda zamietneme a namiesto nej voliacuteme x14 = 7 ako
to ilustruje Obr 410
Ďalej by sme postupovali obdobne v našom priacutepade už opakovanou aplikaacuteciou ohraničeniacute
dospejeme k riešeniu bez ďalšieho vetvenia
432 Strateacutegie vetvenia
Keďže pri vetveniacute maacuteme možnosť vybrať si premennuacute ktorej hodnotu budeme voliť vyvstaacuteva
otaacutezka ktoruacute premennuacute je najlepšie vybrať resp ktoruacute jej hodnotu zvoliť V tejto suacutevislosti je
priacutepustnyacutech viacero spocircsobov ndash existujuacute viacereacute strateacutegie vetvenia ndash mocircžeme sa napriacuteklad po-
kuacutešať voliť premenneacute s čo najmenšiacutem počtom zostaacutevajuacutecich hodnocirct aplikovať určituacute heuristiku
alebo jednoducho zvoliť povedzme prehľadaacutevanie do hĺbky
5 | Zaacutekladneacute koncepty v CPV tejto časti prejdeme zaacutekladneacute koncepty v programovaniacute ohraničeniacute Vaumlčšinu z nich sme už
ilustrovali na priacuteklade hry Sudoku vyššie Na tomto mieste teda budeme stavať na ziacuteskanej intuiacutecii
a poznatky len zovšeobecniacuteme a doplniacuteme
middot 9 middot
Prehľadaacutevanie Sklad ohraničeniacute
Obr 51 Sklad ohraničeniacute a prehľadaacutevanie
scheacutema interakcie [3]
Nesplniteľneacute
Prehľadaacutevanie Sklad ohraničeniacute
Splniteľneacute
1
2
Obr 52 Sklad ohraničeniacute a prehľadaacutevanie priacute-
klad interakcie [3]
51 Sklad ohraničeniacute
Blok CP systeacutemu ktoryacute spravuje ohraničenia a zabezpečuje ich aplikaacuteciu nazyacutevame sklad ohrani-
čeniacute (angl constraint store) Ako sme už videli vyššie v priacuteklade s hrou Sudoku v CP interagujuacute
spolu dva procesy ndash proces prehľadaacutevania (vetvenie) a proces aplikaacutecie ohraničeniacute
511 Interakcia prehľadaacutevania a skladu ohraničeniacute
Schematickeacute znaacutezornenie je na Obr 51 Ako vidno medzi blokom bdquoprehľadaacutevanieldquo a blokom
bdquosklad ohraničeniacuteldquo prebieha obojsmernaacute komunikaacutecia Sklad ohraničeniacute dostane na začiatku pre-
menneacute spolu s ich deničnyacutemi obormi a ohraničenia Naacutesledne ohraničenia aplikuje čo vedie
k dvom cieľom
1 Vyhodnotiť splniteľnosť (overenie korektnosti) či vocircbec existujuacute takeacute hodnoty pre-
mennyacutech pri ktoryacutech suacute splneneacute všetky ohraničenia
2 Vyluacutečiť niektoreacute hodnoty (propagaacutecia ohraničeniacute) z deničnyacutech oborov premennyacutech
sa odstraacutenia tie hodnoty pri ktoryacutech nemožno splniť niektoreacute ohraničenie
Po tejto prvej aplikaacutecii ohraničeniacute ndash keď sklad ohraničeniacute vyluacuteči čo najviac hodnocirct povie
bloku prehľadaacutevanie že uacuteloha je splniteľnaacute Blok prehľadaacutevanie naacutesledne zvoliacute pre niektoruacute pre-
mennuacute hodnotu (vetvenie) a navrhne skladu ohraničeniacute pridať ju ako ďalšie ohraničenie
Priacuteklad je na Obr 52 ndash prehľadaacutevanie navrhuje priradiť X = 5 Sklad ohraničeniacute znovu
s použitiacutem tohto noveacuteho ohraničenia vyluacuteči čo najviac hodnocirct a vyhodnotiacute splniteľnosť Odpovie
že uacuteloha je splniteľnaacute
Blok prehľadaacutevanie teda znovu navrhne hodnotu ndash v našom priacuteklade hodnotu Y 6= 2 (ako
vidno je priacutepustneacute voliť nielen konkreacutetne hodnoty ale sa dajuacute pridať aj ineacute typy ohraničeniacute) Sklad
ohraničeniacute aplikuje rovnakyacute postup Tento raz však zistiacute že ohraničenia už nie suacute splniteľneacute Tuacuteto
informaacuteciu komunikuje naspaumlť bloku prehľadaacutevanie ktoryacute sa navraacuteti k posledneacutemu vetveniu
a navrhne inuacute hodnotu
middot 10 middot
Prehľadaacutevanie
Sklad ohraničeniacute
Definičneacute obory
hellip
Ohraničenia
Obr 53 Scheacutema skladu ohraničeniacute [3]
512 Propagaacutecia ohraničeniacute
Ako sme už ukaacutezali sklad aplikaacuteciou ohraničeniacute zabezpečuje dve funkcie (a) propagaacuteciu ohra-
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Obr 411 Voliacuteme hodnotu 3 pre x14 Obr 412 Stav po aplikaacutecii ohraničeniacute ndash
praacutezdny deničnyacute obor
schopnaacute splniť obmedzenia Ako sme povedali v takomto priacutepade musiacuteme uskutočniť naacutevrat
k posledneacutemu vetveniu ndash hodnotu x14 = 3 teda zamietneme a namiesto nej voliacuteme x14 = 7 ako
to ilustruje Obr 410
Ďalej by sme postupovali obdobne v našom priacutepade už opakovanou aplikaacuteciou ohraničeniacute
dospejeme k riešeniu bez ďalšieho vetvenia
432 Strateacutegie vetvenia
Keďže pri vetveniacute maacuteme možnosť vybrať si premennuacute ktorej hodnotu budeme voliť vyvstaacuteva
otaacutezka ktoruacute premennuacute je najlepšie vybrať resp ktoruacute jej hodnotu zvoliť V tejto suacutevislosti je
priacutepustnyacutech viacero spocircsobov ndash existujuacute viacereacute strateacutegie vetvenia ndash mocircžeme sa napriacuteklad po-
kuacutešať voliť premenneacute s čo najmenšiacutem počtom zostaacutevajuacutecich hodnocirct aplikovať určituacute heuristiku
alebo jednoducho zvoliť povedzme prehľadaacutevanie do hĺbky
5 | Zaacutekladneacute koncepty v CPV tejto časti prejdeme zaacutekladneacute koncepty v programovaniacute ohraničeniacute Vaumlčšinu z nich sme už
ilustrovali na priacuteklade hry Sudoku vyššie Na tomto mieste teda budeme stavať na ziacuteskanej intuiacutecii
a poznatky len zovšeobecniacuteme a doplniacuteme
middot 9 middot
Prehľadaacutevanie Sklad ohraničeniacute
Obr 51 Sklad ohraničeniacute a prehľadaacutevanie
scheacutema interakcie [3]
Nesplniteľneacute
Prehľadaacutevanie Sklad ohraničeniacute
Splniteľneacute
1
2
Obr 52 Sklad ohraničeniacute a prehľadaacutevanie priacute-
klad interakcie [3]
51 Sklad ohraničeniacute
Blok CP systeacutemu ktoryacute spravuje ohraničenia a zabezpečuje ich aplikaacuteciu nazyacutevame sklad ohrani-
čeniacute (angl constraint store) Ako sme už videli vyššie v priacuteklade s hrou Sudoku v CP interagujuacute
spolu dva procesy ndash proces prehľadaacutevania (vetvenie) a proces aplikaacutecie ohraničeniacute
511 Interakcia prehľadaacutevania a skladu ohraničeniacute
Schematickeacute znaacutezornenie je na Obr 51 Ako vidno medzi blokom bdquoprehľadaacutevanieldquo a blokom
bdquosklad ohraničeniacuteldquo prebieha obojsmernaacute komunikaacutecia Sklad ohraničeniacute dostane na začiatku pre-
menneacute spolu s ich deničnyacutemi obormi a ohraničenia Naacutesledne ohraničenia aplikuje čo vedie
k dvom cieľom
1 Vyhodnotiť splniteľnosť (overenie korektnosti) či vocircbec existujuacute takeacute hodnoty pre-
mennyacutech pri ktoryacutech suacute splneneacute všetky ohraničenia
2 Vyluacutečiť niektoreacute hodnoty (propagaacutecia ohraničeniacute) z deničnyacutech oborov premennyacutech
sa odstraacutenia tie hodnoty pri ktoryacutech nemožno splniť niektoreacute ohraničenie
Po tejto prvej aplikaacutecii ohraničeniacute ndash keď sklad ohraničeniacute vyluacuteči čo najviac hodnocirct povie
bloku prehľadaacutevanie že uacuteloha je splniteľnaacute Blok prehľadaacutevanie naacutesledne zvoliacute pre niektoruacute pre-
mennuacute hodnotu (vetvenie) a navrhne skladu ohraničeniacute pridať ju ako ďalšie ohraničenie
Priacuteklad je na Obr 52 ndash prehľadaacutevanie navrhuje priradiť X = 5 Sklad ohraničeniacute znovu
s použitiacutem tohto noveacuteho ohraničenia vyluacuteči čo najviac hodnocirct a vyhodnotiacute splniteľnosť Odpovie
že uacuteloha je splniteľnaacute
Blok prehľadaacutevanie teda znovu navrhne hodnotu ndash v našom priacuteklade hodnotu Y 6= 2 (ako
vidno je priacutepustneacute voliť nielen konkreacutetne hodnoty ale sa dajuacute pridať aj ineacute typy ohraničeniacute) Sklad
ohraničeniacute aplikuje rovnakyacute postup Tento raz však zistiacute že ohraničenia už nie suacute splniteľneacute Tuacuteto
informaacuteciu komunikuje naspaumlť bloku prehľadaacutevanie ktoryacute sa navraacuteti k posledneacutemu vetveniu
a navrhne inuacute hodnotu
middot 10 middot
Prehľadaacutevanie
Sklad ohraničeniacute
Definičneacute obory
hellip
Ohraničenia
Obr 53 Scheacutema skladu ohraničeniacute [3]
512 Propagaacutecia ohraničeniacute
Ako sme už ukaacutezali sklad aplikaacuteciou ohraničeniacute zabezpečuje dve funkcie (a) propagaacuteciu ohra-
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Prehľadaacutevanie Sklad ohraničeniacute
Obr 51 Sklad ohraničeniacute a prehľadaacutevanie
scheacutema interakcie [3]
Nesplniteľneacute
Prehľadaacutevanie Sklad ohraničeniacute
Splniteľneacute
1
2
Obr 52 Sklad ohraničeniacute a prehľadaacutevanie priacute-
klad interakcie [3]
51 Sklad ohraničeniacute
Blok CP systeacutemu ktoryacute spravuje ohraničenia a zabezpečuje ich aplikaacuteciu nazyacutevame sklad ohrani-
čeniacute (angl constraint store) Ako sme už videli vyššie v priacuteklade s hrou Sudoku v CP interagujuacute
spolu dva procesy ndash proces prehľadaacutevania (vetvenie) a proces aplikaacutecie ohraničeniacute
511 Interakcia prehľadaacutevania a skladu ohraničeniacute
Schematickeacute znaacutezornenie je na Obr 51 Ako vidno medzi blokom bdquoprehľadaacutevanieldquo a blokom
bdquosklad ohraničeniacuteldquo prebieha obojsmernaacute komunikaacutecia Sklad ohraničeniacute dostane na začiatku pre-
menneacute spolu s ich deničnyacutemi obormi a ohraničenia Naacutesledne ohraničenia aplikuje čo vedie
k dvom cieľom
1 Vyhodnotiť splniteľnosť (overenie korektnosti) či vocircbec existujuacute takeacute hodnoty pre-
mennyacutech pri ktoryacutech suacute splneneacute všetky ohraničenia
2 Vyluacutečiť niektoreacute hodnoty (propagaacutecia ohraničeniacute) z deničnyacutech oborov premennyacutech
sa odstraacutenia tie hodnoty pri ktoryacutech nemožno splniť niektoreacute ohraničenie
Po tejto prvej aplikaacutecii ohraničeniacute ndash keď sklad ohraničeniacute vyluacuteči čo najviac hodnocirct povie
bloku prehľadaacutevanie že uacuteloha je splniteľnaacute Blok prehľadaacutevanie naacutesledne zvoliacute pre niektoruacute pre-
mennuacute hodnotu (vetvenie) a navrhne skladu ohraničeniacute pridať ju ako ďalšie ohraničenie
Priacuteklad je na Obr 52 ndash prehľadaacutevanie navrhuje priradiť X = 5 Sklad ohraničeniacute znovu
s použitiacutem tohto noveacuteho ohraničenia vyluacuteči čo najviac hodnocirct a vyhodnotiacute splniteľnosť Odpovie
že uacuteloha je splniteľnaacute
Blok prehľadaacutevanie teda znovu navrhne hodnotu ndash v našom priacuteklade hodnotu Y 6= 2 (ako
vidno je priacutepustneacute voliť nielen konkreacutetne hodnoty ale sa dajuacute pridať aj ineacute typy ohraničeniacute) Sklad
ohraničeniacute aplikuje rovnakyacute postup Tento raz však zistiacute že ohraničenia už nie suacute splniteľneacute Tuacuteto
informaacuteciu komunikuje naspaumlť bloku prehľadaacutevanie ktoryacute sa navraacuteti k posledneacutemu vetveniu
a navrhne inuacute hodnotu
middot 10 middot
Prehľadaacutevanie
Sklad ohraničeniacute
Definičneacute obory
hellip
Ohraničenia
Obr 53 Scheacutema skladu ohraničeniacute [3]
512 Propagaacutecia ohraničeniacute
Ako sme už ukaacutezali sklad aplikaacuteciou ohraničeniacute zabezpečuje dve funkcie (a) propagaacuteciu ohra-
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Prehľadaacutevanie
Sklad ohraničeniacute
Definičneacute obory
hellip
Ohraničenia
Obr 53 Scheacutema skladu ohraničeniacute [3]
512 Propagaacutecia ohraničeniacute
Ako sme už ukaacutezali sklad aplikaacuteciou ohraničeniacute zabezpečuje dve funkcie (a) propagaacuteciu ohra-
je že ohraničenia suacute vzaacutejomne nezaacutevisleacute ndash medzi sebou neinteragujuacute čo zjednodušuje manipu-
laacuteciu s nimi Ak je nejakaacute miera interakcie predsa len žiaduca mocircže sa realizovať cez pomocnuacute
premennuacute ndash samotneacute ohraničenia aj potom ostaacutevajuacute nezaacutevisleacute a prepojenie sa realizuje cez de-
ničneacute obory O tom však viac v podkapitole o reikaacutecii (časť 8)
52 Arita ohraničeniacute
Z deniacutecie ohraničeniacute ktoruacute sme uviedli pri deniacutecii CSP v časti 2 nevyplyacutevajuacute žiadne obmedze-
nia pre aritu ohraničeniacute Osobitnyacutemi priacutepadmi z hľadiska arity suacute [2 4 5]
bull Unaacuterne ohraničenia Operujuacute na jednotlivyacutech premennyacutech napr X 6= 2
bull Binaacuterne ohraničenia Operujuacute na dvojiciach premennyacutech napr X = Y
bull Nebinaacuterne ohraničenia Operujuacute na viac než dvoch premennyacutech tj majuacute aritu n gt 2
Unaacuterne ohraničenia do tejto triedy teda nepatria hoci tiež nie suacute binaacuterne
Ako hovoriacute napr [4 5] ohraničenia vyššej arity (nebinaacuterne) možno rozložiť na binaacuterne ohra-
ničenia hoci v praxi to vaumlčšinou nemaacute zmysel Možno však vďaka tomu povedať že CSP s binaacuter-
nymi ohraničeniami zastupujuacute do istej miery aj ineacute typy CSP [4]
middot 11 middot
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
53 Globaacutelne ohraničenia
Osobitnyacutem typom ohraničeniacute suacute tzv globaacutelne ohraničenia Rozumieme nimi zložitejšie ohrani-
čenia ktoryacutech arita je často ľubovoľnaacute Propagaacutecia takyacutechto ohraničeniacute sa potom rieši osobitnyacutem
na to určenyacutem algoritmom Modelovať probleacutem pomocou globaacutelnych ohraničeniacute (tam kde to je
možneacute) je teda nielen jednoduchšie ale predovšetkyacutem to vedie k efektiacutevnejšej propagaacutecii ohra-
ničeniacute
Typickyacutem priacutekladom globaacutelneho ohraničenia je ohraničenie alldifferent (al distinct)
ktoreacute o ľubovoľnej množine premennyacutech hovoriacute že sa musia navzaacutejom liacutešiť Ako vidno ohra-
ničenie alldifferent maacute ľubovoľnuacute aritu keďže ho možno aplikovať na ľubovoľnuacute množinu
premennyacutech
54 Ciele CP a optimalizaacutecia na baacuteze CP
Pri aplikaacutecii CP na určityacute probleacutem spĺňania ohraničeniacute (CSP) naacutem ide o splnenie jedneacuteho z nasle-
dujuacutecich cieľov [6]
bull naacutejdenie jedneacuteho riešenia CSP
bull naacutejdenie všetkyacutech riešeniacute CSP
bull naacutejdenie riešenia ktoreacute je optimaacutelne (alebo aspoň dostatočne dobreacute) vzhľadom na určiteacute
kriteacuterium ndash v tomto priacutepade hovoriacuteme o tzv probleacuteme optimalizaacutecie ohraničeniacute (angl con-
straint optimization problem COP)
Pri riešeniacute probleacutemu optimalizaacutecie ohraničeniacute pomocou CP sa najčastejšie postupuje tak že
sa (rovnako ako pri bežnom CP) naacutejde prveacute riešenie spĺňajuacutece všetky ohraničenia Naacutesledne sa
pomocou zadaneacuteho kriteacuteria určiacute jeho cena Do skladu ohraničeniacute sa potom ako ďalšie ohraničenie
pridaacute že riešenie musiacute mať nižšiu cenu V priacutepade že chceme daneacute kriteacuterium maximalizovať
postupuje sa uacuteplne obdobne
6 | Konzistenčneacute technikyKonzistenčneacute techniky riadia aplikaacuteciu ohraničeniacute v raacutemci skladu ohraničeniacute ndash jednak v zmysle
šiacuterenia ohraničeniacute a jednak v zmysle overenia korektnosti resp konzistentnosti
Ak maacute CSP len binaacuterne ohraničenia (a ako sme povedali vyššie ľubovoľneacute nebinaacuterne ohra-
ničenia možno previesť na binaacuterne hoci to vaumlčšinou nemaacute praktickyacute zmysel) možno ho repre-
zentovať grafom ohraničeniacute Vrcholmi v grafe suacute jednotliveacute premenneacute a hrany existujuacute medzi
tyacutemi vrcholmi ktoryacutech premenneacute suacute previazaneacute ohraničeniacutem [4] Praacuteve z tejto grackej analoacutegie
middot 12 middot
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Obr 61 Priacuteklad CSP ktoreacute nie je konzistentneacute hoci je hranovo konzistentneacute [2]
čerpajuacute naacutezvy viaceryacutech zaacutekladnyacutech konzistenčnyacutech techniacutek V tejto časti sa pozrieme aspoň na
niektoreacute z nich ndash konkreacutetne na vrcholovuacute a hranovuacute konzistentnosť a na tzv konzistentnosť po
ceste Ďalšie konzistenčneacute techniky možno pozrieť napr v [5 6]
61 Vrcholovaacute konzistentnosť
Najjednoduchšou konzistenčnou technikou je tzv vrcholovaacute konzistentnosť (angl node consis-
tency) ndash taacute odstraňuje z deničneacuteho oboru jednej premennej hodnoty nevyhovujuacutece unaacuternym
ohraničeniam [5] Čo sa tyacuteka vrcholovej konzistentnosti stačiacute teda jednoducho iterovať cez jed-
notliveacute premenneacute a nad nimi denovaneacute unaacuterne ohraničenia a odstraňovať hodnoty Ak by všetky
ohraničenia boli unaacuterne stačila by dokonca na ich propagaacuteciu jedinaacute iteraacutecia
62 Hranovaacute konzistentnosť
Nech maacuteme binaacuterne ohraničenieCij na premennyacutech xi isin Di a xj isin Dj Platiacute tedaCij sube DitimesDj
Hovoriacuteme že ohraničenie Cij je hranovo konzistentneacute (AC angl arc consistent) ak platiacute [2]
bull foralla isin Di exist b isin Dj (a b) isin C
bull forallb isin Dj exist a isin Di (a b) isin C
Teda ak pre každuacute hodnotu a v deničnom obore Di existuje takyacute naacuteprotivok b v deničnom
obore Dj že priradenie xi = a xj = b spĺňa ohraničenie Cij [4]
Ak pre nejakuacute hodnotu a isin Di neexistuje hodnota b isin Dj ktoraacute toto spĺňa možno hodnotu a
z deničneacuteho oboruDi vyluacutečiť keďže už nemocircže byť suacutečasťou žiadneho konzistentneacuteho riešenia
[4]
Hovoriacuteme že CSP je hranovo konzistentneacute ak všetky jeho ohraničenia suacute hranovo konzis-
tentneacute [5] Ak je CSP hranovo konzistentneacute neznamenaacute to ešte že je konzistentneacute všeobecne
Hranovaacute konzistentnosť neimplikuje konzistentnosť ako takuacute
Priacuteklad CSP ktoreacute je nekonzistentneacute a zaacuteroveň je konzistentneacute hranovo vidno na Obr 61
Nevieme či bude xi nadobuacutedať hodnotu a alebo b preto nevieme zatiaľ vyluacutečiť ani jednu z hodnocirct
z deničneacuteho oboru pre xj Zaacuteroveň je však zrejmeacute že CSP je nekonzistentneacute keďže nie je možneacute
aby zaacuteroveň platilo xi = xj aj xi 6= xj
middot 13 middot
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
621 Ako dosiahnuť hranovuacute konzistentnosť
Najjednoduchšiacutem spocircsobom ako dosiahnuť hranovuacute konzistentnosť je iterovať cez všetky hrany
a postupne odstraňovať z deničnyacutech oborov premennyacutech hodnoty ktoreacute hranovej konzisten-
tnosti prekaacutežajuacute Tento postup treba ako vieme aplikovať opakovane až dovtedy kyacutem sa už
deničneacute obory nemenia
Proceduacuteru ktoraacute takto odstraňuje hodnoty z deničnyacutech oborov nazyacutevame reviacuteziou (orien-
tovanej) hrany Pseudokoacuted reviacutezie ukazuje Algoritmus 1 Keďže pre tuacute istuacute hranu (i j) mocircže
existovať aj viacero ohraničeniacute označiacuteme n-teacute ohraničenie Cnij Ako vidno proceduacutera navracia
hodnotu true alebo false podľa toho či bola z deničneacuteho oboru danej premennej vyluacutečenaacute nejakaacute
hodnota alebo nie
Algoritmus 1 Algoritmus proceduacutery reviacutezia hrany (podľa [6] s upravenyacutem značeniacutem)
3 foreach a isin Di do4 if b isin Dj (a b) isin Cn
ij foralln then5 odstraacuteniť a z Di
6 odstraacuteneneacutelarr true
7 end
8 end9 return odstraacuteneneacute
10 end
Ak teda reviacuteziu aplikujeme pre všetky hrany a opakovane dosiahneme napokon hranovuacute
konzistentnosť Algoritmus ktoryacute takto postupuje sa nazyacuteva AC-1 [6] Jeho pseudokoacuted ukazuje
Algoritmus 2
Nevyacutehodou AC-1 je že zbytočne opakuje niektoreacute reviacutezie Ak sa zmeniacute deničnyacute obor hoci len
jednej premennej automaticky sa revidujuacute všetky hrany ndash zmena maacute však v skutočnosti vplyv
len na tie hrany ktoreacute danuacute premennuacute obsahujuacute [5] To isteacute sme už vyššie ilustrovali na priacuteklade
so Sudoku (viď časť 42) ndash tiež bolo potrebneacute uvažovať len tie riadky stĺpce a štvorce kde nastala
zmena
Odpoveďou na tuacuteto vyacutehradu je algoritmus AC-2 [5] Ešte efektiacutevnejšou verziou tohto algo-
ritmu je však algoritmus AC-3 ktoryacute pri opakovanej reviacutezii pracuje s jednou frontou hraacuten Pse-
udokoacuted ukazuje Algoritmus 3
Existujuacute aj ďalšie vylepšeneacute verzie ndash prinajmenšom po AC-7 [4] Tyacutemto sa už nebudeme pod-
robnejšie venovať ndash viac možno pozrieť napr v [5 6]
middot 14 middot
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Algoritmus 2 Algoritmus AC-1 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-1(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 repeat4 zmeneneacutelarr false
5 foreach hrana (i j) isin Q do6 zmeneneacutelarr revise(i j) or zmeneneacute
7 end
8 until not(zmeneneacute)
9 end
Algoritmus 3 Algoritmus AC-3 (podľa [6] s upravenyacutem značeniacutem)
1 procedure AC-3(G) begin2 Qlarr (i j) isin hrany(G) i 6= j3 while not empty Q do4 foreach hrana (km) isin Q do5 zmazať (km) z Q
6 if revise(km) then7 Qlarr Q cup (i k) isin hrany(G) i 6= k i 6= m8 end
9 end
10 end
11 end
middot 15 middot
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
63 Konzistentnosť po ceste
Keďže ako sme vyššie ukaacutezali hranovaacute konzistentnosť neimplikuje celkovuacute konzistentnosť hľa-
dali sa pri vyacutevoji CP ešte ineacute konzistenčneacute techniky Jednou z tyacutechto je tzv konzistentnosť poceste (PC angl path consistency)
Hovoriacuteme že cesta (1 2 n) je konzistentnaacute ak pre každyacute paacuter (x1 xn) konzistentnyacutech hod-
nocirct (tj takyacutech že spĺňajuacute všetky binaacuterne ohraničenia medzi 1 a n) existujuacute hodnoty x2 xnminus1
takeacute že všetky ohraničenia i i+ 1 suacute splneneacute [5]
Stojiacute za zmienku že taacuteto deniacutecia nehovoriacute nič o ohraničeniach medzi i a j pre |i minus j| gt 1
Daacute sa však ukaacutezať že ak suacute všetky cesty dĺžky 2 konzistentneacute po ceste celyacute CSP je konzistentnyacute
po ceste Algoritmy zabezpečujuacutece konzistentnosť po ceste preto pracujuacute len s cestami dĺžky 2
a (podobne ako AC) zabezpečujuacute konzistentnosť po ceste opakovanou aplikaacuteciou reviacuteziiacute [5]
7 | Riešenie predeterminovanyacutech CSP
V praxi suacute probleacutemy spĺňania ohraničeniacute často predeterminovaneacute ndash tj ohraničeniacute je priveľa a ne-
možno ich všetky suacutečasne splniť Typickyacutem priacutekladom mocircže byť tvorba školskeacuteho rozvrhu kde
treba brať do uacutevahy kapacitneacute možnosti miestnostiacute ďalej že taacute istaacute trieda (a rovnako ten istyacute uči-
teľ) nesmie mať viacero hodiacuten suacutečasne a pod K tomu sa navyše pridaacutevajuacute ineacute požiadavky napr
mocircže byť snaha vyučovať podľa možnosti predovšetkyacutem dopoludnia priacutepade mocircžu požiadavky
denovať učitelia ktoriacute sa mocircžu dostaviť len v niektoreacute dni
71 Maumlkkeacute ohraničenia
Ak nemožno všetky požiadavky splniť suacutečasne je možneacute niektoreacute z nich relaxovať Z priacutekladu
s rozvrhom je zrejmeacute že možno relaxovať len niektoreacute ohraničenia ndash ak napr priradiacuteme tomu
isteacutemu učiteľovi v rovnakom čase dve vyučovacie hodiny nie je fyzicky možneacute aby ich obe odučil
Na druhej strane rocirczne doplňujuacutece požiadavky relaxovať možno ndash v priacutepade že to je potrebneacute
možno napriacuteklad vyučovať aj večer
Pri riešeniacute predeterminovanyacutech CSP sa teda pracuje s dvomi typmi ohraničeniacute ndash s ostryacutemi(klasickyacutemi angl crisp constraint) ohraničeniami a s tzv maumlkkyacutemi ohraničeniami (angl soft
constraints) ktoreacute možno relaxovať [2]
Pomocou maumlkkyacutech ohraničeniacute mocircžeme pocircvodnyacute predeterminovanyacute probleacutem previesť na prob-
leacutem kde sa snažiacuteme naacutejsť najlepšie riešenie spĺňajuacutece všetky ostreacute ohraničenia ndash tj na opti-
malizačnyacute probleacutem Kriteacuteriaacute možno voliť rocirczne (napr aby bolo splnenyacutech čo najviac maumlkkyacutech
ohraničeniacute aby boli splneneacute tie najdocircležitejšie maumlkkeacute ohraničenia a pod) Ak probleacutem je prob-
leacutem predeterminovanyacute a použiacutevame maumlkkeacute ohraničenia hovoriacuteme o tzv probleacuteme čiastočneacuteho
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
8 | ReikaacuteciaReikaacutecia je proces kedy sa validita ohraničenia premieta do boolovskej premennej [7] Mohli
by sme povedať že ohraničenie sa materializuje staacuteva sa reaacutelnym (odtiaľ reikaacutecia) Ako priacuteklad
možno uviesť reikovaneacute ohraničenie b = 1 hArr x = y kde b je boolovskaacute premennaacute a x = y je
ohraničenie Takeacuteto ohraničenie sa propaguje nasledujuacutecim spocircsobom [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
bull Ak platiacute x 6= y propaguje sa b = 0
81 Využitie reikaacutecie pri modelovaniacute
Reikaacutecia maacute pri modelovaniacute viacero využitiacute Ako priacuteklad ukaacutežeme ako ju možno použiť na zaacutepis
disjunktnyacutech ohraničeniacute a ako možno pomocou nej zapiacutesať že dve polia veľkosti n sa po prv-
koch nerovnajuacute Priacuteklady suacute len ilustratiacutevne ndash nechceme povedať že ide o jedinyacute alebo o najlepšiacute
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
812 Nerovnosť prvkov poliacute
Nech maacuteme dve polia X a Y veľkosti n Chceme vyjadriť že
X[i] 6= Y [i] foralli isin 1 2 n (83)
Jednyacutem zo spocircsobov ako postupovať je denovať pre každeacute i reikovaneacute ohraničenie v tvare
bi hArr X[i] 6= Y [i] a naacutesledne povedať že suacutečet všetkyacutech bi sa musiacute rovnať n Ak ohraničenie
nebude splneneacute aspoň pre jedno i zodpovedajuacutece bi bude rovneacute 0 a suacutečet všetkyacutech bi bude menšiacute
než n
813 Riešenie probleacutemu max-CSP
Ako sme povedali vyššie pri riešeniacute predeterminovanyacutech CSP možno niektoreacute ostreacute ohraničenia
nia a čo najvaumlčšiacute počet maumlkkyacutech ohraničeniacute sa potom označuje ako max-CSP
Ak jednotliveacute ohraničenia C1 C2 Cn reikujeme tj b1 hArr C1 bn hArr Cn mocircžeme
pocircvodnyacute max-CSP probleacutem previesť jednoducho na CSP optimalizačnyacute probleacutem kde uacutečelovaacute
funkcia budensum
i=1bi (84)
tj suacutečet reikaacuteciiacute resp počet splnenyacutech ohraničeniacute [2]
Obdobne v priacutepade vaacuteženeacuteho CSP ndash tu by uacutečelovaacute funkcia navyše operovala aj s vaacutehami wi
jednotlivyacutech ohraničeniacute tj
nsumi=1
wibi (85)
82 Polovičnaacute reikaacutecia
Typ reikaacutecie o ktorej sme hovorili vyššie sa nazyacuteva aj uacuteplnaacute reikaacutecia Okrem uacuteplnej reikaacutecie
existuje aj polovičnaacute reikaacutecia [7] ndash tu sa propagaacutecia ohraničeniacute deje len v jednom smere
Priacutekladom takeacuteho ohraničenia mocircže byť b = 1 rArr x = y V tomto priacutepade sa propaguje len
nasledovne [7]
bull Ak sa priradiacute b = 1 propaguje sa ohraničenie x = y
bull Ak platiacute x 6= y propaguje sa b = 0
Mocircže nastať aj priacutepad kedy sa propaguje v opačnom smere Napriacuteklad b = 1 lArr x = y sa
bude propagovať [7]
bull Ak sa priradiacute b = 0 propaguje sa ohraničenie x 6= y
bull Ak platiacute x = y propaguje sa b = 1
middot 19 middot
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
9 | Obľuacutebeneacute benchmark probleacutemyNa tomto mieste uvedieme niekoľko obľuacutebenyacutech benchmark probleacutemov na ktoryacutech sa CP (ale aj
ineacute metoacutedy) často ilustrujuacute resp sa porovnaacuteva ich uacutečinnosť
91 Probleacutem obchodneacuteho cestujuacuteceho
Probleacutem obchodneacuteho cestujuacuteceho (angl travelling salesman problem TSP) je azda jednyacutem z naj-
znaacutemejšiacutech benchmark probleacutemov v oblasti strojoveacuteho učenia vocircbec ndash aplikovalo sa naň už ne-
spočetneacute množstvo rocircznych metoacuted
Podstatou probleacutemu je že obchodnyacute cestujuacuteci maacute za uacutelohu navštiacuteviť určiteacute mestaacute Cieľom
je naplaacutenovať takuacute trasu aby žiadne mesto nenavštiacutevil viackraacutet a aby bola cesta čo najkratšia
Okrem toho sa typicky požaduje aby cesta končila v tom istom bode z ktoreacuteho vychaacutedza (tj aby
bola uzavretaacute) Treba poznamenať že probleacutem obchodneacuteho cestujuacuteceho je NP-ťažkyacute
Probleacutem maacute viacero variantov niektoreacute napriacuteklad povoľujuacute navštiacuteviť to isteacute miesto aj viackraacutet
Zo všetkyacutech takyacutechto variantov vyberaacuteme na ďalšiu diskusiu tieto tri
bull Probleacutem je reprezentovanyacuteneohodnotenyacutemgrafom ktoryacute určuje z ktoreacuteho mesta možno
prejsť do ktoreacuteho
bull Probleacutem je reprezentovanyacute ohodnotenyacutem grafom tj pribuacuteda koncept dĺžky (ceny) cesty
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
a pritom sa všetky čiacuteslice navzaacutejom liacutešili
Spomiacutenanyacute aritmetickyacute vyacuteraz maacute nasledujuacuteci tvar
SEND + MORE = MONEY (91)
Ak vyacuteraz rozpiacutešeme podrobnejšie maacuteme
1000S + 100E + 10N + D+ 1000M + 100O + 10R + E
= 10000M + 1000O + 100N + 10E + Y
(92)
Ako ďalšie ohraničenie pridaacutevame S 6= 0 aM 6= 0 Povedali sme okrem toho že všetky čiacuteslice
sa majuacute navzaacutejom liacutešiť tj S 6= E 6= N 6= D 6= M 6= O 6= R 6= Y
93 Probleacutem magickyacutech postupnostiacute
Ďalšiacutem obľuacutebenyacutem probleacutemom na ktorom sa často ilustruje CP je probleacutem magickyacutech postup-
nostiacute (angl magic series) Cieľom je naacutejsť postupnosť čiacutesel v tvare X = x0 x1 xN takuacute aby
platilo že xi sa rovnaacute počtu vyacuteskytov čiacutesla i v X
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
4 const int sudoku_example[] =
5 0 0 0 0 0 0 0 9 0
6 0 5 0 0 4 2 3 6 0
7 3 0 4 6 0 8 1 7 0
8 8 0 0 0 2 0 0 0 9
9 0 0 0 8 0 1 0 0 0
10 4 0 0 0 6 0 0 0 1
11 0 1 6 2 0 4 9 0 7
12 0 4 9 5 7 0 0 1 0
13 0 0 0 0 0 0 0 0 0
14
101 Direktiacutevy include a linkovanie
Na uacutevod pridaacuteme zopaacuter include direktiacutev a importujeme namespace Gecode ndash viď Lst 2 Prvaacute
direktiacuteva importuje potrebnuacute infraštruktuacuteru pre celočiacuteselneacute (int) ohraničenia hlavičkovyacute suacutebor
minimodel sprostredkuje komfortnejšiacute spocircsob zaacutepisu jednotlivyacutech ohraničeniacute a napokon hlavič-
Ďalej musiacuteme zadenovať samotnyacute probleacutem spĺňania ohraničeniacute Z časti 2 vieme že CSP sa skladaacute
jednak z premennyacutech a ich deničnyacutech oborov a jednak z ohraničeniacute V raacutemci knižnice Gecode
existuje viacero spocircsobov ako probleacutem formalizovať ndash my dediacuteme z triedy Space tj denuje
priestor riešeniacute (mohli by sme dediť aj z inyacutech tried napr z triedy Script ktoraacute poskytuje trochu
ineacute rozhranie)
Vydedenaacute trieda je v Lst 3 Ako vidno trieda obsahuje jednu členskuacute premennuacute vars ktoraacute
je typu IntVarArrays Ide o pole celočiacuteselnyacutech premennyacutech ktoreacute predstavujuacute jednotliveacute poliacutečka
Sudoku a ktoreacute spolu previažeme priacuteslušnyacutemi ohraničeniami
middot 23 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Za zmienku stojiacute aj funkcia copy ktoraacute umožňuje priestor riešeniacute kopiacuterovať Taacuteto funkcia
sa použiacuteva pri vetveniacute ndash aby v priacutepade neuacutespechu bolo možneacute vraacutetiť sa k predchaacutedzajuacutecemu
vetveniu musiacuteme vedieť obnoviť stav v ktorom vtedy boli deničneacute obory premennyacutech Ako
vidno v našom priacutepade z funkcie copy iba volaacuteme priacuteslušnyacutech kopiacuterovaciacute konštruktor
Funkciu print denujeme preto aby sme vedeli hotoveacute riešenie vypiacutesať do štandardneacuteho vyacute-
stupu
Lst 3 Sudoku ndash dediacuteme z triedy Space
1 2 Trieda definujuacuteca premenneacute pre Sudoku o ohranicenia na nich
3
4 class Sudoku public Space
5 protected
6 Pole celociacuteselnyacutech premennyacutech
7 IntVarArray vars
8
9 public
10 Vytvorenie koacutepie
11 virtual Space copy(bool share)
12 return new Sudoku(share this)
13
14
15 Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupu
16 void print() const
17 stdcout ltlt res ltlt stdendl
18
19 MatrixltIntVarArraygt mat(vars 9 9)
20
21 int rows = matheight() cols = matwidth()
22 for(int i = 0 i lt rows i++)
23 for(int j = 0 j lt cols j++)
24 stdcout ltlt mat(i j) ltlt
25
26 stdcout ltlt stdendl
27
28
29 stdcout ltlt stdendl
30
31
32 public
33 Sudoku(const int example = nullptr)
34 Sudoku(bool share Sudokuamp obj)
35
103 Konštrukcia triedy Sudoku
Konštruktor triedy Sudoku obsahuje najpodstatnejšiu časť koacutedu ndash tu sa určuje koľko bude pre-
mennyacutech a pridaacutevajuacute sa jednotliveacute ohraničenia Zodpovedajuacuteci koacuted ukazuje Zoznam obraacutezkov 4
middot 24 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Ako vidno pole celočiacuteselnyacutech premennyacutech vars ktoreacute sme deklarovali vyššie bude obsaho-
vať 99 premennyacutech pričom každaacute bude z deničneacuteho oboru 〈1 9〉V prvom riadku konštruktora vytvaacuterame pomocnyacute objekt mat ndash tento naacutem pocircvodneacute pole pre-
mennyacutech umožňuje reprezentovať ako maticu rozmerov 9times9 Vyacutehodou je že takaacuteto reprezentaacutecia
naacutem umožniacute veľmi prirodzenyacutem spocircsobom zapiacutesať riadkoveacute stĺpcoveacute a štvorcoveacute ohraničenia
Napriacuteklad pre nultyacute riadok stačiacute piacutesať distinct(this matrow(0)) tj že všetky prvky
v nultom riadku sa musia navzaacutejom liacutešiť Obdobne denujeme ohraničenia pre stĺpce (matcol(i))
a štvorce (matslice(i i+3 j j+3))
Ďalej ak sme dostali aj pole s predvyplnenyacutemi poliacutečkami (example) zostaviacuteme priacuteslušneacute ohra-
ničenia Celkom na zaacutever sa zvoliacute typ vetvenia V priacutepade že by sme pracovali s viaceryacutemi po-
ľami premennyacutech a pod registrovalo by sa rovnakyacutem spocircsobom vetvenie pre každeacute osobitne
Pri vetveniacute možno stanoviť cez ktoruacute premennuacute sa bude vetviť ako cez prvuacute (napr premennaacute
s najmenšiacutem deničnyacutem oborom) a od ktorej hodnoty sa začne (napr od najmenšej hodnoty)
Lst 4 Sudoku ndash konštruktor
1 SudokuSudoku(const int example) vars(this 99 1 9)
2 MatrixltIntVarArraygt mat(vars 9 9)
3 int rows = matheight() cols = matwidth()
4
5 Riadkoveacute ohranicenia
6 for(int i = 0 i lt rows i++)
7 distinct(this matrow(i))
8
9
10 Stlpcoveacute ohranicenia
11 for(int i = 0 i lt cols i++)
12 distinct(this matcol(i))
13
14
15 Štvorcoveacute ohranicenia
16 for(int i = 0 i lt 9 i+=3)
17 for(int j = 0 j lt 9 j+=3)
18 distinct(this matslice(i i+3 j j+3))
19
20
21
22 Naciacutetame predplneneacute poliacutecka z priacutekladu ak existuje
23 if(example)
24 for(int i = 0 i lt rows i++)
25 for(int j = 0 j lt cols j++)
26 int val = example[icols + j]
27 if(val) rel(this mat(ij) == val)
28
29
30
31
32 Akeacute sa použije vetvenie
middot 25 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
33 branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX())
34
Druhyacute konštruktor ako sme už spomenuli vyššie je kopiacuterovaciacute (viď Lst 5)2
6 Hlrsquoadaacuteme a postupne vypisujeme všetky riešenia
7 while(Sudoku s = dfsnext())
8 s-gtprint()
9 delete s
10
11
12 return 0
13
2Zvlaacuteštnosťou je že okrem referencie na objekt Sudokuamp obj ako argument požaduje ešte boolovskuacute premennuacute
share Ak share je true znamenaacute to že niektoreacute objekty sa buduacute medzi obomi koacutepiami zdieľať ndash koacutepie sa potom smuacute
použiacutevať len spolu v tom istom vlaacutekne Ak share je false vytvoriacute sa uacuteplnaacute koacutepia ktoraacute je už aj vlaacuteknovo bezpečnaacute
[7]
middot 26 middot
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
include ltgecodeinthhgtinclude ltgecodeminimodelhhgtinclude ltgecodesearchhhgtusing namespace Gecode Priacuteklad Sudoku Nuly suacute nevyplneneacute poliacutečkaconst int sudoku_example[] = 0 0 0 0 0 0 0 9 0 0 5 0 0 4 2 3 6 0 3 0 4 6 0 8 1 7 0 8 0 0 0 2 0 0 0 9 0 0 0 8 0 1 0 0 0 4 0 0 0 6 0 0 0 1 0 1 6 2 0 4 9 0 7 0 4 9 5 7 0 0 1 0 0 0 0 0 0 0 0 0 0 Trieda definujuacuteca premenneacute pre Sudoku o ohraničenia na nichclass Sudoku public Space protected Pole celočiacuteselnyacutech premennyacutechIntVarArray varspublic Vytvorenie koacutepievirtual Space copy(bool share) return new Sudoku(share this) Vyacutepis hodnocirct premennyacutech do štandardneacuteho vyacutestupuvoid print() const stdcout ltlt res ltlt stdendlMatrixltIntVarArraygt mat(vars 9 9)int rows = matheight() cols = matwidth()for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) stdcout ltlt mat(i j) ltlt stdcout ltlt stdendlstdcout ltlt stdendlpublic Sudoku(const int example = nullptr) Sudoku(bool share Sudokuamp obj)SudokuSudoku(const int example) vars(this 99 1 9) MatrixltIntVarArraygt mat(vars 9 9) int rows = matheight() cols = matwidth() Riadkoveacute ohraničenia for(int i = 0 i lt rows i++) distinct(this matrow(i)) Stĺpcoveacute ohraničenia for(int i = 0 i lt cols i++) distinct(this matcol(i)) Štvorcoveacute ohraničenia for(int i = 0 i lt 9 i+=3) for(int j = 0 j lt 9 j+=3) distinct(this matslice(i i+3 j j+3)) Načiacutetame predplneneacute poliacutečka z priacutekladu ak existuje if(example) for(int i = 0 i lt rows i++) for(int j = 0 j lt cols j++) int val = example[icols + j] if(val) rel(this mat(ij) == val) Akeacute sa použije vetvenie branch(this vars INT_VAR_SIZE_MIN() INT_VAL_MAX()) Konštruktor ku podpore prehľadaacutevaniaSudokuSudoku(bool share Sudokuamp obj) Space(share obj) vars() varsupdate(this share objvars)int main() Sudoku sudoku = new Sudoku(sudoku_example)DFSltSudokugt dfs(sudoku) DFS - depth-first searchdelete sudoku Hľadaacuteme a postupne vypisujeme všetky riešeniawhile(Sudoku s = dfsnext()) s-gtprint()delete s return 0
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
11 | Priacuteklad Riešenie Sudoku v jazyku PrologKeďže ako sme povedali vyššie osobitnuacute časť priacutestupov ku programovaniu ohraničeniacute tvoriacute tzv
logickeacute programovanie ohraničeniacute tj aplikaacutecie programovania ohraničeniacute v logickyacutech jazykoch
ako je Prolog uvedieme pre porovnanie aj riešenie Sudoku v prostrediacute SWI-Prolog Toto postupne
prejdeme v nasledujuacutecich častiach Kompletnyacute zdrojovyacute koacuted prikladaacuteme
111 Použiteacute moduly a vloženie Sudoku
Podpora pre logickeacute programovanie ohraničeniacute s konečnyacutemi deničnyacutemi obormi je v prostrediacute
SWI-Prolog poskytovanaacute knižnicou clpfd ktoruacute teda pomocou direktiacutevy use_module importu-
jeme ako to ukazuje Lst 7
V Lst 7 ďalej vidno ako možno vložiť predplneneacute hracie pole Sudoku vkladaacuteme ho pomo-
cou predikaacutetu example formou 2D zoznamu Praacutezdne polia pritom nahraacutedzame znakom _ tj
anonymnou premennou
Lst 7 Sudoku v SWI-Prolog moduly a vloženie Sudoku
žeme použiť s predikaacutetom maplist priamo kvocircli poradiu argumentov preto použijeme pomocnyacute
predikaacutet length_list ktoryacute ich poradie obracia Jeho presnaacute deniacutecia bude ešte uvedenaacute nižšie
middot 27 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Lst 8 Sudoku v SWI-Prolog moduly a vloženie Sudoku
1 2 Predikaacutet s ohraniceniami maplist aplikuje na každyacute prvok
3 zoznamu zadanuacute funkciu
4
5 sudoku(Rows) -
6 Riadkov musiacute bytrsquo 9
7 length(Rows 9)
8 Každyacute riadok musiacute matrsquo 9 prvkov
9 maplist(length_list(9) Rows)
10 Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs
11 append(Rows Vs)
12 Každyacute prvok Vs mocircže matrsquo rozsah od 1 po 9
13 Vs ins 19
14 V každom riadku sa prvky musia liacutešitrsquo
15 maplist(all_distinct Rows)
16 Zo zoznamu riadkov ziacuteskame zoznam stlpcov
17 transpose(Rows Columns)
18 V každom stlpci sa prvky musia liacutešitrsquo
19 maplist(all_distinct Columns)
20 Riadky si oznaciacuteme piacutesmenami
21 Rows = [ABCDEFGHI]
22 Aplikujeme ohranicenia pre bloky najprv
23 pre prveacute tri riadky (A B C) potom pre drsquoalšie 3 atdrsquo
24 blocks(A B C) blocks(D E F) blocks(G H I)
Aby sme denovali deničnyacute obor jednotlivyacutech premennyacutech premietneme pomocou predi-
kaacutetu append všetky riadky do spoločneacuteho 1-rozmerneacuteho zoznamu Vs o ktorom potom povieme
že každyacute jeho prvok musiacute byť z rozsahu od 1 po 9
Ohraničenie pre riadky denujeme tak že pomocou predikaacutetu maplist aplikujeme na každyacute
riadok ohraničenie all_distinct (ekvivalent distinct z knižnice Gecode) Ohraničenia pre stĺpce
riešime obdobne Aby sme ziacuteskali zoznam pre stĺpce Columns deklarujeme že Columns je trans-
poziacutecia zoznamu Rows
O niečo zložitejšie je denovať ohraničenia pre bloky Prolog ako takyacute neobsahuje vhodneacute
naacutestroje na vyacuteber segmentov a blokov zo zoznamov ndash ak by sme teda chceli postupovať obdobne
ako vo vyššie uvedenom C++ koacutede museli by sme si priacuteslušneacute predikaacutety najprv zadenovať
Jednyacutem zo spocircsobov ako sa tomu vyhnuacuteť ukazuje praacuteve Lst 8 Ako vidno najprv si jednotliveacute
riadky označujeme piacutesmenami A B C D E F G H I Naacutesledne volaacuteme predikaacutet blocks (ktoreacuteho
deniacutecia bude evedenaacute nižšie) pre jednotliveacute trojice riadkov ndash tj pre (A B C) (D E F) a (G H I)
Predikaacutet blocks potom postupne vyberie k trojiciam riadkov priacuteslušneacute trojice stĺpcov a na každyacute
takto zloženyacute blok aplikuje ohraničenie all_distinct
middot 28 middot
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
113 Pomocneacute predikaacutety
Vyššie pri denovaniacute ohraničeniacute sme použili pomocnyacute predikaacutet length_list Jeho deniacuteciu
ukazuje Lst 9 Ako vidno predikaacutet sa odkazuje na vstavanyacute predikaacutet length a iba obracia poradie
argumentov (preto ho možno aplikovať spoločne s predikaacutetom maplist tak ako sme to videli
vyššie)
Lst 9 Sudoku v SWI-Prolog pomocnyacute predikaacutet length_list
1 Predikaacutet na kontrolu rozmerov riadkov
2 length_list(L Ls) - length(Ls L)
Tiež sme použili pomocnyacute predikaacutet blocks na denovanie ohraničeniacute pre bloky Deniacuteciu
ukazuje Lst 10 Ako vidno najprv sa denuje verzia predikaacutetu pre praacutezdne zoznamy ktoraacute sluacuteži
na ukončenie rekurzie
Samotnaacute rekurziacutevna deniacutecia predikaacutetu blocks potom odštepuje z hlavy každeacuteho zoznamu
(tj z každeacuteho riadku) vždy po troch prvkoch Keďže blocks operuje vždy na troch riadkoch
a vyberaacute z nich po troch stĺpcoch vznikajuacute takto bloky rozmeru 3 times 3 o ktoreacute maacuteme zaacuteujem
Keďže jednotliveacute prvky bloku sme aj tu označili piacutesmenami stačiacute už len aplikovať ohraničenie
all_distinct na zoznam všetkyacutech piacutesmen
Lst 10 Sudoku v SWI-Prolog pomocnyacute predikaacutet blocks
1 Bloky predikaacutet na ukoncenie rekurzie
2 blocks([] [] [])
3 Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch
4 prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme
5 že sa prvky nesmuacute opakovatrsquo
6 blocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) -
7 all_distinct([ABCDEFGHI])
8 blocks(Bs1 Bs2 Bs3)
114 Riešenie
Na zaacutever už stačiacute len vypiacutesať riešenie Ak chceme riešenie vypiacutesať hneď po kompilaacutecii suacuteboru
mocircžeme použiť zdrojovyacute koacuted Lst 11 Ako vidno tu najprv unikujeme priacuteklad s premennou Rows
a naacutesledne každyacute riadok osobitne (maplist) vypiacutešeme pomocou predikaacutetu writeln
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
- use_module(library(clpfd)) Priacuteklad Sudoku Anonymneacute premenneacute _ suacute nevyplneneacute poliacutečkaexample([[_______9_] [_5__4236_] [3_46_817_] [8___2___9] [___8_1___] [4___6___1] [_162_49_7] [_4957__1_] [_________]]) Predikaacutet s ohraničeniami maplist aplikuje na každyacute prvok zoznamu zadanuacute funkciusudoku(Rows) - Riadkov musiacute byť 9 length(Rows 9) Každyacute riadok musiacute mať 9 prvkov maplist(length_list(9) Rows) Všetky riadky premietneme do 1-rozmerneacuteho zoznamu Vs append(Rows Vs) Každyacute prvok Vs mocircže mať rozsah od 1 po 9 Vs ins 19 V každom riadku sa prvky musia liacutešiť maplist(all_distinct Rows) Zo zoznamu riadkov ziacuteskame zoznam stĺpcov transpose(Rows Columns) V každom stĺpci sa prvky musia liacutešiť maplist(all_distinct Columns) Riadky si označiacuteme piacutesmenami Rows = [ABCDEFGHI] Aplikujeme ohraničenia pre bloky najprv pre prveacute tri riadky (A B C) potom pre ďalšie 3 atď blocks(A B C) blocks(D E F) blocks(G H I) Predikaacutet na kontrolu rozmerov riadkovlength_list(L Ls) - length(Ls L) Bloky predikaacutet na ukončenie rekurzieblocks([] [] []) Z jednotlivyacutech riadkov (argumenty) vyberaacuteme vždy po troch prvkoch (tj bloky 3x3) Pre každyacute takyacuteto blok deklarujeme že sa prvky nesmuacute opakovaťblocks([ABC|Bs1] [DEF|Bs2] [GHI|Bs3]) - all_distinct([ABCDEFGHI]) blocks(Bs1 Bs2 Bs3) Vypiacutešeme riešenie- example(Rows) sudoku(Rows) maplist(writeln Rows)
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Literatuacutera[1] Rossi F ndash Van Beek P ndash Walsh T Handbook of constraint programming Elsevier 2006
ISBN 978-0-444-52726-4
[2] Apt K Principles of constraint programming Cambridge University Press 2003 ISBN
978-0-521-82583-2
[3] Hentenryck P V Lecture 22 ndash Constraint programming propagation arithmetic constraints
[10] Ross T J Fuzzy Logic with Engineering Applications John Wiley amp Sons 2004 second
edition ed ISBN 0-470-86075-8
middot 30 middot
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
Priacutelohy
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
I
A | Množiny a relaacutecieV tejto časti uvedieme niekoľko zaacutekladnyacutech konceptov tyacutekajuacutecich sa množiacuten a relaacuteciiacute ndash pre priacutepad
že by sa s nimi čitateľ predtyacutem nestretol
A1 Identita a kardinalita množiacuten
Dve množiny suacute identickeacute vtedy a len vtedy keď majuacute presne rovnakeacute prvky tj A = B vtedy a len
vtedy ak forallx x isin AhArr x isin B [9]
Z deniacutecie identity vyplyacuteva zaacutever že existuje len jedna praacutezdna množina ndash neobsahuje žiadne
prvky Praacutezdnu množinu označujeme empty [9]
Počet prvkov ktoreacute obsahuje množina A nazyacutevame kardinalitou A Kardinalitu A označujeme
|A| Kardinalita konečnej množiny je prirodzeneacute čiacuteslo Nekonečneacute množiny majuacute tiež kardinalitu ndash
nedaacute sa však vyjadriť prirodzenyacutem čiacuteslom [9]
A2 Karteziaacutensky suacutečin
Majme dve množinyA aB Povedzme že budeme zostavovať usporiadaneacute dvojice tak že prvyacute prvok
vezmeme z množiny A a druhyacute z množiny B Karteziaacutensky suacutečin ozn AtimesB je množina všetkyacutech
Obdobne možno denovať karteziaacutensky suacutečin aplikovať pre viacero množiacuten napr pre tri [9]
AtimesB times C =def (AtimesB)times C (A2)
tj jednoducho sa suacutečin aplikuje zľava a viackraacutet
A21 Vlastnosti karteziaacutenskeho suacutečinu
Karteziaacutensky suacutečin nie je komutatiacutevny tj
AtimesB 6= B times A (A3)
Karteziaacutensky suacutečin nie je ani asociatiacutevny tj
(AtimesB)times C 6= Atimes (B times C) (A4)
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute
Propagaacutecia ohraničeniacute
Arita ohraničeniacute
Globaacutelne ohraničenia
Ciele CP a optimalizaacutecia na baacuteze CP
Konzistenčneacute techniky
Vrcholovaacute konzistentnosť
Hranovaacute konzistentnosť
Ako dosiahnuť hranovuacute konzistentnosť
Konzistentnosť po ceste
Riešenie predeterminovanyacutech CSP
Maumlkkeacute ohraničenia
Max-CSP
Vaacuteženeacute CSP
Fuzzy CSP
Ďalšie priacutestupy
Reifikaacutecia
Využitie reifikaacutecie pri modelovaniacute
Zaacutepis disjunkcie
Nerovnosť prvkov poliacute
Riešenie probleacutemu max-CSP
Polovičnaacute reifikaacutecia
Obľuacutebeneacute benchmark probleacutemy
Probleacutem obchodneacuteho cestujuacuteceho
Neohodnotenyacute graf
Ohodnotenyacute graf
Uacuteplnyacute graf
SEND MORE MONEY
Probleacutem magickyacutech postupnostiacute
Priacuteklad Riešenie Sudoku pomocou Gecode
Direktiacutevy include a linkovanie
Trieda Sudoku
Konštrukcia triedy Sudoku
Funkcia main
Priacuteklad Riešenie Sudoku v jazyku Prolog
Použiteacute moduly a vloženie Sudoku
Definovanie ohraničeniacute
Pomocneacute predikaacutety
Riešenie
Priacutelohy
Množiny a relaacutecie
Identita a kardinalita množiacuten
Karteziaacutensky suacutečin
Vlastnosti karteziaacutenskeho suacutečinu
Relaacutecie
Charakteristickaacute funkcia
II
A3 Relaacutecie
Neformaacutelne možno povedať že relaacutecie suacute vzťahy medzi objektami Ako priacuteklad binaacuternych relaacuteciiacute
(tj vzťahov medzi dvomi objektami) možno uviesť bdquokoleso je suacutečasť autaldquo bdquoMilan je otec Tomaacutešaldquo
a pod Binaacuternu relaacuteciu R medzi objektmi a a b možno označiť Rab resp aRb v zaacutepise pomocou
usporiadanyacutech dvojiacutec značiacuteme 〈a b〉 isin R [9]
Formaacutelne ndash ak maacuteme dve množiny A a B binaacutera relaacutecia z A do B je [9]
R sube AtimesB (A5)
tj relaacutecia R je vlastne podmnoužinou karteziaacutenskeho suacutečinu oboch množiacuten
Uvedeneacutemu treba rozumieť tak že relaacutecia vyberaacute tie usporiadaneacute dvojice medzi ktoryacutemi platiacute
danyacute vzťah Ak napriacuteklad pracujeme s množinou ľudiacute A = Milan Tomaacuteš Michal Svetozaacuter a relaacute-
ciou R bdquoa je otec bldquo karteziaacutensky suacutečin AtimesA je 〈Milan Milan〉 〈Milan Tomaacuteš〉 〈Milan Michal〉〈Milan Svetozaacuter〉 Vzťah bdquoa je otec bldquo však bude platiť len pre niektoreacute kombinaacutecie prvkov ndash
napr pre Milana a Tomaacuteša ndash preto relaacuteciu možno chaacutepať ako podmnožinu karteziaacutenskeho suacutečinu
Obdobne možno relaacutecie denovať aj pre viacero prvkov ndash napr ternaacuterne relaacutecie pre tri prvky
Ak relaacutecia pracuje s n prvkami hovoriacuteme že maacute aritu n
A4 Charakteristickaacute funkcia
Neformaacutelne ndash charakteristickaacute funkcia množiny hovoriacute ktoryacute prvok do množiny patriacute a ktoryacute nie
Charakteristickaacute funkcia množiny S je teda priradenie typu [9 10]
microS U rarr 0 1 (A6)
Ide teda o priradenie hodnoty 0 ndash tj nepatriacute ndash alebo hodnoty 1 ndash tj patriacute ndash ku každeacutemu prvku
x isin U pričom deničnyacute obor charakteristickej funkcie U nazyacutevame univerzum (univerzum je
množina všetkyacutech hodnocirct o ktoryacutech rozhodujeme či do danej množiny patria alebo nepatria platiacute
S sube U )
Formaacutelne možno charakteristickuacute funkciu množiny denovať nasledovne [9 10]
microS(x) =
1 x isin S
0 x isin S(A7)
Tak ako pre ineacute množiny možno charakteristickuacute funkciu použiť aj na denovanie relaacutecie (ktoraacute
je tiež podmnožinou karteziaacutenskeho suacutečinu) V tom priacutepade U bude karteziaacutensky suacutečin množiacuten nad
ktoryacutemi je relaacutecia denovanaacute a funkcia bude nadobuacutedať hodnotu 1 pre prvky patriace do relaacutecie a 0pre prvky ktoreacute do nej nepatria
Uvedeneacute pojmy ďalej rozviacuteja a stavia na nich oblasť matematiky znaacutema ako relačnaacute algebra
ktoraacute sa široko aplikuje napr v databaacutezovyacutech systeacutemoch
Uacutevod
Probleacutem spĺňania ohraničeniacute
Formulaacutecia hry Sudoku ako CSP
Probleacutem SAT
Logickeacute programovanie ohraničeniacute
Programovanie ohraničeniacute ako riešenie Sudoku
Aplikaacutecia ohraničeniacute hry Sudoku
Štvorcoveacute ohraničenia
Riadkoveacute a stĺpcoveacute ohraničenia
Ohraničenia aplikujeme opakovane
Vetvenie
Naacutevrat
Strateacutegie vetvenia
Zaacutekladneacute koncepty v CP
Sklad ohraničeniacute
Interakcia prehľadaacutevania a skladu ohraničeniacute