Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pp:25:teme:haskell-sat [2025/05/01 11:09]
mihnea.muraru [Învățarea de noi clauze]
pp:25:teme:haskell-sat [2025/05/08 23:34] (current)
mihnea.muraru [Haskell: SAT Solving]
Line 2: Line 2:
  
   * Data publicării:​ 09.04.2025   * Data publicării:​ 09.04.2025
-  * Data ultimei modificări: ​30.04.2025+  * Data ultimei modificări: ​08.05.2025
   * Deadline hard: ziua laboratorului 10   * Deadline hard: ziua laboratorului 10
   * [[https://​curs.upb.ro/​2024/​mod/​forum/​view.php?​id=152382|Forum]]   * [[https://​curs.upb.ro/​2024/​mod/​forum/​view.php?​id=152382|Forum]]
Line 131: Line 131:
 O altă situație interesantă vizează **literalii puri**. Din moment ce complementul unui literal nu apare în formulă, este întotdeauna avantajos să asumăm acel literal, fără teama inducerii vreunui conflict. La fel ca la clauzele unitare, eliminarea unui literal pur poate genera **noi literali puri**, deci prelucrarea trebuie **repetată**. De exemplu, în formula ''​(x1 ∨ x2) ∧ (¬x2 ∨ x3) ∧ (¬x2 ∨ ¬x3)'',​ nu există clauze unitare, dar există un singur literal pur, ''​x1''​. Prin eliminarea lui, se obține formula ''​(¬x2 ∨ x3) ∧ (¬x2 ∨ ¬x3)'',​ în care apare literalul pur ''​¬x2'',​ care nu era pur în formula originală. Eliminându-l și pe acesta, se obține formula vidă. O altă situație interesantă vizează **literalii puri**. Din moment ce complementul unui literal nu apare în formulă, este întotdeauna avantajos să asumăm acel literal, fără teama inducerii vreunui conflict. La fel ca la clauzele unitare, eliminarea unui literal pur poate genera **noi literali puri**, deci prelucrarea trebuie **repetată**. De exemplu, în formula ''​(x1 ∨ x2) ∧ (¬x2 ∨ x3) ∧ (¬x2 ∨ ¬x3)'',​ nu există clauze unitare, dar există un singur literal pur, ''​x1''​. Prin eliminarea lui, se obține formula ''​(¬x2 ∨ x3) ∧ (¬x2 ∨ ¬x3)'',​ în care apare literalul pur ''​¬x2'',​ care nu era pur în formula originală. Eliminându-l și pe acesta, se obține formula vidă.
  
-De remarcat că cele două prelucrări de mai sus pot **interacționa**:​ satisfacerea unei clauze unitare poate introduce nu numai alte clauze unitare, ci și literali puri, iar eliminarea unui literal pur poate introduce nu numai alți literali puri, ci și clauze unitare. În cazul în care sunt disponibile ambele opțiuni, se preferă **satisfacerea clauzelor unitare mai întâi**, întrucât ele pot conduce la **conflicte**,​ și este de dorit evidențierea **cât mai timpurie** a acestora, pentru a scuti alt efort de calcul care oricum nu ar împiedica generarea unui conflict. Numai dacă formula nu conține **nici clauze unitare**, și **nici literali puri**, are rost să recurgem la **asumpții oarecare**.+De remarcat că cele două prelucrări de mai sus pot **interacționa**:​ satisfacerea unei clauze unitare poate introduce nu numai alte clauze unitare, ci și literali puri. În cazul în care sunt disponibile ambele opțiuni, se preferă **satisfacerea clauzelor unitare mai întâi**, întrucât ele pot conduce la **conflicte**,​ și este de dorit evidențierea **cât mai timpurie** a acestora, pentru a scuti alt efort de calcul care oricum nu ar împiedica generarea unui conflict. Numai dacă formula nu conține **nici clauze unitare**, și **nici literali puri**, are rost să recurgem la **asumpții oarecare**.
  
 În exemplul final, demonstrăm toate cele trei tipuri de prelucrări pe formula ''​(¬x1 ∨ x4) ∧ (x1 ∨ x2 ∨ ¬x3) ∧ (¬x2 ∨ x3 ∨ ¬x4)'':​ În exemplul final, demonstrăm toate cele trei tipuri de prelucrări pe formula ''​(¬x1 ∨ x4) ∧ (x1 ∨ x2 ∨ ¬x3) ∧ (¬x2 ∨ x3 ∨ ¬x4)'':​
Line 218: Line 218:
   * 3, 2, 1. Acțiunile rămase nu sunt de eliminare a unei clauze unitare, și prin urmare clauza curentă rămâne ''​(x5 ∨ x7)''​.   * 3, 2, 1. Acțiunile rămase nu sunt de eliminare a unei clauze unitare, și prin urmare clauza curentă rămâne ''​(x5 ∨ x7)''​.
  
-Pentru a înțelege semnificația acestei clauze, ''​(x5 ∨ x7)'',​ să ne amintim **combinația de asumpții incompatibile** depistată mai sus, ''​{¬x7,​ ¬x5}'',​ conform căreia ambele variabile, ''​x7''​ și ''​x5'',​ au fost asumate false. Pentru a depăși incompatibilitatea,​ **cel puțin una dintre variabile** trebuie asumată adevărată,​ adică exact ce **codifică clauza** ''​(x5 ∨ x7)''​. Proprietatea rezolventului afirmă că acesta este întotdeauna adevărat, dacă clauzele pe baza căruia a fost obținut sunt adevărate. Prin urmare, dacă vrem ca clauza vidată ''​(x1 ∨ x2)''​ și clauzele devenite unitare și eliminate ''​(¬x1 ∨ x2)''​ și ''​(¬x2 ∨ x5 ∨ x7)''​ să fie **simultan adevărate** (într-o anumită interpretare),​ atunci **și clauza** ''​(x5 ∨ x7)''​ trebuie să fie adevărată (în acea interpretare). ​''​(x5 ∨ x7)''​ poartă numele de **//clauză învățată//** (//learned clause//)întrucât ​nu face parte din formula originală.+Pentru a înțelege semnificația acestei clauze, ''​(x5 ∨ x7)'',​ să ne amintim **combinația de asumpții incompatibile** depistată mai sus, ''​{¬x7,​ ¬x5}'',​ conform căreia ambele variabile, ''​x7''​ și ''​x5'',​ au fost asumate false. Pentru a depăși incompatibilitatea,​ **cel puțin una dintre variabile** trebuie asumată adevărată,​ adică exact ce **codifică clauza** ''​(x5 ∨ x7)''​. Proprietatea rezolventului afirmă că acesta este întotdeauna adevărat, dacă clauzele pe baza căruia a fost obținut sunt adevărate. Prin urmare, dacă vrem ca clauza vidată ''​(x1 ∨ x2)''​ și clauzele devenite unitare și eliminate ''​(¬x1 ∨ x2)''​ și ''​(¬x2 ∨ x5 ∨ x7)''​ să fie **simultan adevărate** (într-o anumită interpretare),​ atunci **și clauza** ''​(x5 ∨ x7)''​ trebuie să fie adevărată (în acea interpretare). ​Observați cum într-adevăr clauza referă doar variabile asupra cărora s-au realizat **asumpții arbitrare**, ca ''​x5''​ și ''​x7'', ​nu și variabile pentru care asumpțiile au fost impuse, ca ''​x2''​.
  
-Prin urmarepentru ​a ne asigura că **noua clauză**, ''​(x5 ∨ x7)'',​ nu va mai fi niciodată vidată de asumpțiile realizate, o putem **adăuga la formula originală**,​ și ne putem întoarce în trecut la **cel mai distant punct** în care această clauză **devine unitară** (funcția ''​backtrackToUnitClause''​ din etapa 2), astfel încât următoarea acțiune să o **satisfacă imediat**. Revenirea se poate face cu un număr arbitrar de pași în trecut, motiv pentru care poartă numele de **//​backtracking necronologic//​**. Revenirea la cel mai distant punct, și nu la cel mai recent, scade probabilitatea de eșec al căii curente, ​datorate ​altor asumpții realizate pe anterioara cale eșuată. Astfel, răspundem și la **întrebarea (2)**. Remarcăm că, din moment ce rezolventul derivă logic din anumite clauze ale formulei originale, formula rezultată prin adăugarea clauzei învățate la formula originală este **echivalentă** cu formula originală.+''​(x5 ∨ x7)''​ poartă numele de **//clauză învățată//​** (//learned clause//)întrucât nu face parte din formula originală. Dacă **clauza învățată însăși** este **vidă**, înseamnă că este **imposibil** ca clauzele din care a fost obținută să fie adevărate simultan, și deci formula originală este **nesatisfiabilă**. 
 + 
 +Pentru ​a ne asigura că **noua clauză**, ''​(x5 ∨ x7)'',​ nu va mai fi niciodată vidată de asumpțiile realizate, o putem **adăuga la formula originală**,​ și ne putem întoarce în trecut la **cel mai distant punct** în care această clauză **devine unitară** (funcția ''​backtrackToUnitClause''​ din etapa 2), astfel încât următoarea acțiune să o **satisfacă imediat**. Revenirea se poate face cu un număr arbitrar de pași în trecut, motiv pentru care poartă numele de **//​backtracking necronologic//​**. Revenirea la cel mai distant punct, și nu la cel mai recent, scade probabilitatea de eșec al căii curente, ​datorat ​altor asumpții realizate pe anterioara cale eșuată. Astfel, răspundem și la **întrebarea (2)**. Remarcăm că, din moment ce rezolventul derivă logic din anumite clauze ale formulei originale, formula rezultată prin adăugarea clauzei învățate la formula originală este **echivalentă** cu formula originală.
  
 În exemplul de mai sus, se adaugă clauza învățată ''​(x5 ∨ x7)''​ la formula originală, obținându-se formula ''​(¬x7 ∨ x1) ∧ (¬x6 ∨ ¬x2 ∨ x1) ∧ (¬x5 ∨ x1) ∧ (¬x4 ∨ x3) ∧ (¬x3 ∨ x4) ∧ (¬x2 ∨ ¬x1 ∨ x6) ∧ (¬x2 ∨ x5 ∨ x7) ∧ (¬x1 ∨ x2) ∧ (x1 ∨ x2) ∧ (x5 ∨ x7)'':​ În exemplul de mai sus, se adaugă clauza învățată ''​(x5 ∨ x7)''​ la formula originală, obținându-se formula ''​(¬x7 ∨ x1) ∧ (¬x6 ∨ ¬x2 ∨ x1) ∧ (¬x5 ∨ x1) ∧ (¬x4 ∨ x3) ∧ (¬x3 ∨ x4) ∧ (¬x2 ∨ ¬x1 ∨ x6) ∧ (¬x2 ∨ x5 ∨ x7) ∧ (¬x1 ∨ x2) ∧ (x1 ∨ x2) ∧ (x5 ∨ x7)'':​
Line 248: Line 250:
 ==== Aplicație la problema 3-colorare ==== ==== Aplicație la problema 3-colorare ====
  
-Problema **//​3-colorare//​** a unui **graf neorientat** urmărește asocierea ​uneia dintre trei culori (''​Red'',​ ''​Green'',​ ''​Blue''​) fiecărui nod din graf, astfel încât oricare două **noduri adiacente** să fie **colorate diferit**. Problema poate fi rezolvată prin **reducere la SAT**, parcurgând etapele:+Problema **//​3-colorare//​** a unui **graf neorientat** urmărește asocierea ​unei culori ​din trei (''​Red'',​ ''​Green'',​ ''​Blue''​) fiecărui nod din graf, astfel încât oricare două **noduri adiacente** să fie **colorate diferit**. Problema poate fi rezolvată prin **reducere la SAT**, parcurgând etapele:
  
   - **Codificarea** instanței //​3-colorare//​ într-o formulă CNF.   - **Codificarea** instanței //​3-colorare//​ într-o formulă CNF.
Line 276: Line 278:
 A treia etapă a temei abordează **rezolvarea** clauzelor, **învățarea** clauzelor, algoritmul de **satisfacere** și aplicația la problema **//​3-colorare//​**. A treia etapă a temei abordează **rezolvarea** clauzelor, **învățarea** clauzelor, algoritmul de **satisfacere** și aplicația la problema **//​3-colorare//​**.
  
-Construcțiile și mecanismele de limbaj pe care le veți exploata în rezolvare, pe lângă cele din etapa 1 și 2, sunt:+Construcțiile și mecanismele de limbaj pe care le veți exploata în rezolvare, pe lângă cele din etapele ​1 și 2, sunt:
  
   * **polimorfismul ad-hoc**   * **polimorfismul ad-hoc**
Line 283: Line 285:
 Modulul de interes din **schelet** este ''​Solver'',​ care conține **operațiile** pe care trebuie să le implementați. Găsiți detaliile despre **funcționalitate** și despre **constrângerile de implementare**,​ precum și **exemple**,​ direct în fișier. Aveți de completat definițiile care încep cu ''​%%*** TODO ***%%''​. Modulul de interes din **schelet** este ''​Solver'',​ care conține **operațiile** pe care trebuie să le implementați. Găsiți detaliile despre **funcționalitate** și despre **constrângerile de implementare**,​ precum și **exemple**,​ direct în fișier. Aveți de completat definițiile care încep cu ''​%%*** TODO ***%%''​.
  
-Pentru **rularea testelor**, încărcați în interpretor modulul ''​TestSolver''​ și evaluați ''​main''​.+Pentru **rularea testelor**, încărcați în interpretor modulul ''​TestSolver''​ și evaluați ''​main''​. Ultimul test (''​stress''​) utilizează grafuri mai mari și execuția poate dura câteva secunde.
  
 Este suficient ca arhiva pentru **vmchecker** să conțină modulele ''​Solver'',​ ''​ExtendedFormula''​ din etapa 2 și ''​Formula''​ din etapa 1. Este suficient ca arhiva pentru **vmchecker** să conțină modulele ''​Solver'',​ ''​ExtendedFormula''​ din etapa 2 și ''​Formula''​ din etapa 1.
Line 300: Line 302:
 ===== Changelog ===== ===== Changelog =====
  
 +  * 08.05 (23:30): Publicat testele etapei 3 și actualizat tipurile ''​Graph'',​ ''​Color''​ și ''​ThreeColoring''​ din ''​Solver.hs''​ cu ''​deriving (Show, Eq)''​ în loc de ''​deriving Show''​.
   * 30.04 (22:30): Publicat etapa 3, momentan fără teste   * 30.04 (22:30): Publicat etapa 3, momentan fără teste
   * 27.04 (09:50): Etapa 2: Actualizat teste ''​backtrackToUnitClause''​   * 27.04 (09:50): Etapa 2: Actualizat teste ''​backtrackToUnitClause''​
pp/25/teme/haskell-sat.1746086995.txt.gz · Last modified: 2025/05/01 11:09 by mihnea.muraru
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0