K iS~dZddlmZddlmZmZddlmZddlm Z ddl m Z ddZ dZ Gd d ZGd d Zy )zImplementation of DPLL algorithm Features: - Clause learning - Watch literal scheme - VSIDS heuristic References: - https://en.wikipedia.org/wiki/DPLL_algorithm ) defaultdict)heappushheappop)ordered) EncodedCNF) LRASolverct|tst}|j||}dh|jvr |r ddDSy|rt j |\}}nd}g}t |j|z|jt|j|}|j}|r t|S t|S#t$rYywxYw)a Check satisfiability of a propositional sentence. It returns a model rather than True when it succeeds. Returns a generator of all models if all_models is True. Examples ======== >>> from sympy.abc import A, B >>> from sympy.logic.algorithms.dpll2 import dpll_satisfiable >>> dpll_satisfiable(A & ~B) {A: True, B: False} >>> dpll_satisfiable(A & ~A) False rc3 K|]}|ywN).0fs b/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/sympy/logic/algorithms/dpll2.py z#dpll_satisfiable...s'!A's FFN) lra_theory) isinstanceradd_propdatarfrom_encoded_cnf SATSolver variablessetsymbols _find_model _all_modelsnext StopIteration)expr all_modelsuse_lra_theoryexprslraimmediate_conflictssolvermodelss rdpll_satisfiabler's" dJ '  t sdii 'w' '#,#=#=d#C    tyy#66t||hk lF    !F6""F| s? C CCc#`Kd} t|d}#t$r |sdYyYywxYww)NFT)rr)r& satisfiables rrrGsDKv, K Ks.+.+.ceZdZdZ ddZdZdZdZedZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZy)rz Class for representing a SAT solver capable of finding a model to a boolean theory in conjunctive normal form. Nc ||_||_d|_g|_g|_||_|t t||_n||_|j||j|d|k(rU|j|j|_ |j|_|j |_|j$|_nt(d|k(rH|j*|_|j.|_|jj3|j4nd|k(rd|_d|_nt(t7dg|_||j:_d|_d|_ tC|jD|_#||_$y)NFvsidssimplenonecyr r )xs rz$SATSolver.__init__..~cyr r r r3rr1z$SATSolver.__init__..r2r3r)% var_settings heuristicis_unsatisfied_unit_prop_queueupdate_functionsINTERVALlistrr_initialize_variables_initialize_clauses _vsids_init_vsids_calculateheur_calculate_vsids_lit_assignedheur_lit_assigned_vsids_lit_unsetheur_lit_unset_vsids_clause_addedheur_clause_addedNotImplementedError_simple_add_learned_clauseadd_learned_clause_simple_compute_conflictcompute_conflictappend_simple_clean_clausesLevellevels_current_level varsettings num_decisionsnum_learned_clauseslenclausesoriginal_num_clausesr#) selfrUrr5rr6clause_learningr:rs r__init__zSATSolver.__init__Ysb)"# " "  ? 23DL"DL ""9-   ) i     "&"7"7D %)%=%=D ""&"7"7D %)%=%=D " & %  &&*&E&ED #$($A$AD !  ! ! ( ()C)C D  &&4D #$0D !% %Qxj *6'#$ $' $5!r3ctt|_tt|_dgt |dzz|_y)z+Set up the variable data structures needed.FN)rr sentinelsintoccurrence_countrT variable_set)rWrs rr<zSATSolver._initialize_variabless3$S) +C 0"Gs9~'9:r3c|Dcgc] }t|c}|_t|jD]\}}dt|k(r|jj |d3|j |dj||j |dj||D]}|j|xxdz cc<ycc}w)a<Set up the clause data structures needed. For each clause, the following changes are made: - Unit clauses are queued for propagation right away. - Non-unit clauses have their first and last literals set as sentinels. - The number of clauses a literal appears in is computed. r[rN) r;rU enumeraterTr8rLr\addr^)rWrUclauseilits rr=zSATSolver._initialize_clausess4;;V ; "4<<0 0IAvCK%%,,VAY7 NN6!9 % ) )! , NN6": & * *1 - 0%%c*a/* 0 0>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> list(l._find_model()) [{1: True, 2: False, 3: False}, {1: True, 2: True, 3: True}] >>> from sympy.abc import A, B, C >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set(), [A, B, C]) >>> list(l._find_model()) [{A: True, B: False, C: False}, {A: True, B: True, C: True}] FNTrr[c3.K|] }| dvyw)r[Nr )r rfress rrz(SATSolver._find_model..s%asdc!fn%as)flipped) _simplifyr7rRr:r9rPdecisionr@r#r5 assert_litcheck reset_boundsrabsrHany_undorjrTrOrLrN_assign_literalrIrK)rWflip_varfuncrfenc_varflip_litris @rrzSATSolver._find_models 8     !!DMM1Q6 11DF ))22))+""a'"8xx'+'8'8&G"&(("5"5g">C" %&#hhnn.--/"{c!f7;7H7HJ03 $||CHqL9$'!G ,JJ77A?#&%a@S@S@`@`%a"a JJL#&%a@S@S@`@`%a"a--55 --554;;'1, $ 3 3 < <>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{1}, {2}], {1, 2}, set()) >>> next(l._find_model()) {1: True, 2: True} >>> l._current_level.decision 0 >>> l._current_level.flipped False >>> l._current_level.var_settings {1, 2} ra)rOrWs rrPzSATSolver._current_level"s&{{2r3cL|j|D]}||jvsyy)aCheck if a clause is satisfied by the current variable setting. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{1}, {-1}], {1}, set()) >>> try: ... next(l._find_model()) ... except StopIteration: ... pass >>> l._clause_sat(0) False >>> l._clause_sat(1) True TF)rUr5rWclsrfs r _clause_satzSATSolver._clause_sat7s2$<<$ Cd''' r3c$||j|vS)aCheck if a literal is a sentinel of a given clause. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> next(l._find_model()) {1: True, 2: False, 3: False} >>> l._is_sentinel(2, 3) True >>> l._is_sentinel(-3, 1) False )r\)rWrfr|s r _is_sentinelzSATSolver._is_sentinelNs"dnnS)))r3c|jj||jjj|d|jt |<|j |t |j| }|D]}|j|rd}|j|D]w}|| k7s |j||r|}|jt |r8|j| j||j|j|d}n|s|jj|y)aMake a literal assignment. The literal assignment must be recorded as part of the current decision level. Additionally, if the literal is marked as a sentinel of any clause, then a new sentinel must be chosen. If this is not possible, then unit propagation is triggered and another literal is added to the queue to be set in the future. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> next(l._find_model()) {1: True, 2: False, 3: False} >>> l.var_settings {-3, -2, 1} >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l._assign_literal(-1) >>> try: ... next(l._find_model()) ... except StopIteration: ... pass >>> l.var_settings {-1} TN)r5rcrPr_rprBr;r\r}rUrremover8rL)rWrf sentinel_listr|other_sentinelnewlits rrszSATSolver._assign_literalas&> c" ((,,S1&*#c(# s#T^^SD12   AC##C(!%"ll3/"F#~,,VS9-3N!%!2!23v;!? NNC4077< NN6266s;-1N!""))00@ Ar3c|jjD]F}|jj||j|d|jt |<H|j jy)ag _undo the changes of the most recent decision level. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> next(l._find_model()) {1: True, 2: False, 3: False} >>> level = l._current_level >>> level.decision, level.var_settings, level.flipped (-3, {-3, -2}, False) >>> l._undo() >>> level = l._current_level >>> level.decision, level.var_settings, level.flipped (0, {1}, False) FN)rPr5rrDr_rprOpoprWrfs rrrzSATSolver._undose,&&33 0C    $ $S )    $*/D  c#h ' 0 r3cdd}|r,d}||jz}||jz}|r+yy)adIterate over the various forms of propagation to simplify the theory. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.variable_set [False, False, False, False] >>> l.sentinels {-3: {0, 2}, -2: {3, 4}, 2: {0, 3}, 3: {2, 4}} >>> l._simplify() >>> l.variable_set [False, True, False, False] >>> l.sentinels {-3: {0, 2}, -2: {3, 4}, -1: set(), 2: {0, 3}, ...3: {2, 4}} TFN) _unit_prop _pure_literal)rWchangeds rrkzSATSolver._simplifys:.G t( (G t))+ +Gr3ct|jdkD}|jrV|jj}| |jvrd|_g|_y|j ||jrV|S)z/Perform unit propagation on the current theory.rTF)rTr8rr5r7rs)rWresultnext_lits rrzSATSolver._unit_propswT**+a/##,,002HyD---&*#(*%$$X.## r3cy)z2Look for pure literals and assign them when found.Fr rys rrzSATSolver._pure_literalsr3cg|_i|_tdt|jD]}t |j | |j|<t |j |  |j| <t|j|j||ft|j|j| | fy)z>Initialize the data structures needed for the VSIDS heuristic.r[N)lit_heap lit_scoresrangerTr_floatr^r)rWvars rr>zSATSolver._vsids_inits C 1 123 CC#($*?*?*D)D#EDOOC $)4+@+@#+F*F$GDOOSD ! T]]T__S%93$? @ T]]T__cT%:SD$A B  Cr3cp|jjD]}|j|xxdzcc<y)aDecay the VSIDS scores for every literal. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.lit_scores {-3: -2.0, -2: -2.0, -1: 0.0, 1: 0.0, 2: -2.0, 3: -2.0} >>> l._vsids_decay() >>> l.lit_scores {-3: -1.0, -2: -1.0, -1: 0.0, 1: 0.0, 2: -1.0, 3: -1.0} g@N)rkeysrs r _vsids_decayzSATSolver._vsids_decays4*??'') (C OOC C '  (r3cbt|jdk(ry|jt|jddrWt |jt|jdk(ry|jt|jddrWt |jdS)a VSIDS Heuristic Calculation Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.lit_heap [(-2.0, -3), (-2.0, 2), (-2.0, -2), (0.0, 1), (-2.0, 3), (0.0, -1)] >>> l._vsids_calculate() -3 >>> l.lit_heap [(-2.0, -2), (-2.0, 2), (0.0, -1), (0.0, 1), (-2.0, 3)] rr[)rTrr_rprrys rr?zSATSolver._vsids_calculates* t}}  "DMM!$4Q$7 89 DMM "4==!Q&DMM!$4Q$7 89 t}}%a((r3cy)z;Handle the assignment of a literal for the VSIDS heuristic.Nr rs rrAzSATSolver._vsids_lit_assigned3 r3ct|}t|j|j||ft|j|j| | fy)aHandle the unsetting of a literal for the VSIDS heuristic. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.lit_heap [(-2.0, -3), (-2.0, 2), (-2.0, -2), (0.0, 1), (-2.0, 3), (0.0, -1)] >>> l._vsids_lit_unset(2) >>> l.lit_heap [(-2.0, -3), (-2.0, -2), (-2.0, -2), (-2.0, 2), (-2.0, 3), (0.0, -1), ...(-2.0, 2), (0.0, 1)] N)rprrr)rWrfrs rrCzSATSolver._vsids_lit_unset7sI&#h!5s ;<#!6 =>r3cj|xjdz c_|D]}|j|xxdz cc<y)aDHandle the addition of a new clause for the VSIDS heuristic. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.num_learned_clauses 0 >>> l.lit_scores {-3: -2.0, -2: -2.0, -1: 0.0, 1: 0.0, 2: -2.0, 3: -2.0} >>> l._vsids_clause_added({2, -3}) >>> l.num_learned_clauses 1 >>> l.lit_scores {-3: -1.0, -2: -2.0, -1: 0.0, 1: 0.0, 2: -1.0, 3: -2.0} r[N)rSrr{s rrEzSATSolver._vsids_clause_addedNs8.   A%  &C OOC A %  &r3cFt|j}|jj||D]}|j|xxdz cc<|j|dj ||j|dj ||j |y)aAdd a new clause to the theory. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.num_learned_clauses 0 >>> l.clauses [[2, -3], [1], [3, -3], [2, -2], [3, -2]] >>> l.sentinels {-3: {0, 2}, -2: {3, 4}, 2: {0, 3}, 3: {2, 4}} >>> l._simple_add_learned_clause([3]) >>> l.clauses [[2, -3], [1], [3, -3], [2, -2], [3, -2], [3]] >>> l.sentinels {-3: {0, 2}, -2: {3, 4}, 2: {0, 3}, 3: {2, 4, 5}} r[rraN)rTrUrLr^r\rcrF)rWr|cls_numrfs rrHz$SATSolver._simple_add_learned_clausels2dll# C  ,C  ! !# &! + & , s1v""7+ s2w##G, s#r3c\|jddDcgc]}|j c}Scc}w)a Build a clause representing the fact that at least one decision made so far is wrong. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> next(l._find_model()) {1: True, 2: False, 3: False} >>> l._simple_compute_conflict() [3] r[N)rOrl)rWlevels rrJz"SATSolver._simple_compute_conflicts) 04{{12?e%..!???s)cy)zClean up learned clauses.Nr rys rrMzSATSolver._simple_clean_clausesrr3)Nr,r.iN)__name__ __module__ __qualname____doc__rYr<r=rpropertyrPr}rrsrrrkrrr>rr?rArCrErHrJrMr r3rrrRs BFDG"3j; 0.r n(.*&5AnB ,:  C(0)@ ?.&<"$H@$ r3rceZdZdZddZy)rNz Represents a single level in the DPLL algorithm, and contains enough information for a sound backtracking procedure. c>||_t|_||_yr )rlrr5rj)rWrlrjs rrYzLevel.__init__s  E r3Nr)rrrrrYr r3rrNrNs  r3rNN)FF)r collectionsrheapqrrsympy.core.sortingrsympy.assumptions.cnfr!sympy.logic.algorithms.lra_theoryrr'rrrNr r3rrs= $#&,7*dR  R  j  r3