
    gS                         d Z ddlmZ ddlmZmZ ddlmZ ddlm	Z	 ddl
mZ ddZd	 Z G d
 d          Z G d d          ZdS )zImplementation of DPLL algorithm

Features:
  - Clause learning
  - Watch literal scheme
  - VSIDS heuristic

References:
  - https://en.wikipedia.org/wiki/DPLL_algorithm
    )defaultdict)heappushheappop)ordered)
EncodedCNF)	LRASolverFc                    t          | t                    s%t                      }|                    |            |} dh| j        v r|rd dD             S dS |rt	          j        |           \  }}nd}g }t          | j        |z   | j        t                      | j	        |          }|
                                }|rt          |          S 	 t          |          S # t          $ r Y dS w xY w)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

    r   c              3      K   | ]}|V  d S N ).0fs     X/var/www/html/ai-engine/env/lib/python3.11/site-packages/sympy/logic/algorithms/dpll2.py	<genexpr>z#dpll_satisfiable.<locals>.<genexpr>.   s"      ''!A''''''    FFN)
lra_theory)
isinstancer   add_propdatar   from_encoded_cnf	SATSolver	variablessetsymbols_find_model_all_modelsnextStopIteration)expr
all_modelsuse_lra_theoryexprslraimmediate_conflictssolvermodelss           r   dpll_satisfiabler(      s   " dJ'' t 	
sdi 	(''w''''u !#,#=d#C#C    ty#66t|hklllF!!F #6"""F||   uus   C 
C('C(c              #   j   K   d}	 	 t          |           V  d}# t          $ r |sdV  Y d S Y d S w xY w)NFT)r   r   )r'   satisfiables     r   r   r   G   st      K	v,,K	     	KKKKKK	 	 	s    22c                       e Zd ZdZ	 	 	 ddZd Zd Zd	 Zed
             Z	d Z
d Zd Zd Z	 d Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd ZdS )r   z
    Class for representing a SAT solver capable of
     finding a model to a boolean theory in conjunctive
     normal form.
    Nvsidsnone  c	                    || _         || _        d| _        g | _        g | _        || _        |"t          t          |                    | _        n|| _        | 	                    |           | 
                    |           d|k    rE|                                  | j        | _        | j        | _        | j        | _        | j        | _        nt(          d|k    r8| j        | _        | j        | _        | j                            | j                   nd|k    rd | _        d | _        nt(          t7          d          g| _        || j        _        d| _        d| _         tC          | j"                  | _#        || _$        d S )NFr,   simpler-   c                     d S r   r   )xs    r   <lambda>z$SATSolver.__init__.<locals>.<lambda>~   s     r   c                      d S r   r   r   r   r   r3   z$SATSolver.__init__.<locals>.<lambda>   s    D r   r   )%var_settings	heuristicis_unsatisfied_unit_prop_queueupdate_functionsINTERVALlistr   r   _initialize_variables_initialize_clauses_vsids_init_vsids_calculateheur_calculate_vsids_lit_assignedheur_lit_assigned_vsids_lit_unsetheur_lit_unset_vsids_clause_addedheur_clause_addedNotImplementedError_simple_add_learned_clauseadd_learned_clause_simple_compute_conflictcompute_conflictappend_simple_clean_clausesLevellevels_current_levelvarsettingsnum_decisionsnum_learned_clauseslenclausesoriginal_num_clausesr$   )	selfrU   r   r5   r   r6   clause_learningr:   r   s	            r   __init__zSATSolver.__init__Y   s    )"# " " ?	 2 233DLL"DL""9---  )))i"&"7D%)%=D""&"7D%)%=D"" &%&&&*&ED#$($AD!!(()CDDDD&&&4nD#$0LD!!%% Qxxj*6' #$ $'$5$5!r   c                     t          t                    | _        t          t                    | _        dgt          |          dz   z  | _        dS )z+Set up the variable data structures needed.F   N)r   r   	sentinelsintoccurrence_countrT   variable_set)rW   r   s     r   r<   zSATSolver._initialize_variables   sA    $S)) +C 0 0"Gs9~~'9:r   c                    d |D             | _         t          | j                   D ]\  }}dt          |          k    r!| j                            |d                    9| j        |d                                      |           | j        |d                                      |           |D ]}| j        |xx         dz  cc<   dS )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.
        c                 ,    g | ]}t          |          S r   )r;   )r   clauses     r   
<listcomp>z1SATSolver._initialize_clauses.<locals>.<listcomp>   s    ;;;V;;;r   r[   r   N)rU   	enumeraterT   r8   rL   r\   addr^   )rW   rU   irb   lits        r   r=   zSATSolver._initialize_clauses   s     <;7;;;"4<00 	0 	0IAv CKK%,,VAY777N6!9%))!,,,N6":&**1--- 0 0%c***a/****0	0 	0r   c              #      K   d}                                    j        rdS 	  j         j        z  dk    r j        D ]} |             |rd} j        j        }n                                 } xj        dz  c_        d|k    r3 j        r[ j	        D ] } j        
                    |          }| n! j                                        } j                                         nd}||d         r fd j	        D             V  n                     |d                     j        j        r                                    j        j         t!           j                  dk    rdS  j        j         }                                   j                            t'          |d                     d} j                            t'          |                                          |                                               j        rd _         j        j        r:                                  dt!           j                  k    rdS  j        j        :                                                                  j        j         }                                   j                            t'          |d                     d})an  
        Main DPLL loop. Returns a generator of models.

        Variables are chosen successively, and assigned to be either
        True or False. If a solution is not found with this setting,
        the opposite is chosen and the search continues. The solver
        halts when every variable has a setting.

        Examples
        ========

        >>> 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}]

        FNTr   r[   c                 T    i | ]$}j         t          |          d z
           |dk    %S )r[   r   )r   abs)r   rh   rW   s     r   
<dictcomp>z)SATSolver._find_model.<locals>.<dictcomp>   sG     J J J03  $|CHHqL9$'!GJ J Jr   )flipped)	_simplifyr7   rR   r:   r9   rP   decisionr@   r$   r5   
assert_litcheckreset_boundsrH   rm   _undorT   rO   rL   rN   _assign_literalrI   rK   )rW   flip_varfuncrh   enc_varresflip_lits   `      r   r   zSATSolver._find_model   s1     8  	 	FJ	 !DM1Q66 1  DDFFFF (/ )2 ))++""a'"" 88 x #'+'8 & &G"&("5"5g">">C" %  /"hnn..--////"{c!f{J J J J7;7HJ J J J J J J 77A???-5 %

 -5 %4;''1,, $ 3 <<HJJLLLK&&uXt'D'D'DEEE#H ""5::...   %%% NN "  &+# )1 JJLLL C,,,, )1  ''(=(=(?(?@@@ !/88

""54#@#@#@AAAUJ	 r   c                     | j         d         S )a  The current decision level data structure

        Examples
        ========

        >>> 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}

        rd   rO   rW   s    r   rP   zSATSolver._current_level  s    & {2r   c                 >    | j         |         D ]}|| j        v r dS dS )a  Check 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)rU   r5   rW   clsrh   s      r   _clause_satzSATSolver._clause_sat3  s9    $ <$ 	 	Cd'''tt (ur   c                      || j         |         v S )a  Check 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\   )rW   rh   r   s      r   _is_sentinelzSATSolver._is_sentinelJ  s    " dnS)))r   c                    | j                             |           | j        j                             |           d| j        t	          |          <   |                     |           t          | j        |                    }|D ]}|                     |          sd}| j	        |         D ]}|| k    rx| 
                    ||          r|}"| j        t	          |                   sE| j        |                              |           | j        |                             |           d} n|r| j                            |           dS )a  Make 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)r5   rf   rP   r_   rk   rB   r;   r\   r   rU   r   remover8   rL   )rW   rh   sentinel_listr   other_sentinelnewlits         r   rt   zSATSolver._assign_literal]  sg   > 	c"""(,,S111&*#c((#s###T^SD122  	A 	AC##C(( A!%"l3/ " "F#~~,,VS99 "-3NN!%!23v;;!? " NC4077<<< N6266s;;;-1N!E " A)00@@@	A 	Ar   c                     | j         j        D ]H}| j                            |           |                     |           d| j        t          |          <   I| j                                         dS )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)rP   r5   r   rD   r_   rk   rO   poprW   rh   s     r   rs   zSATSolver._undo  st    , &3 	0 	0C$$S)))$$$*/Dc#hh'' 	r   c                 v    d}|r4d}||                                  z  }||                                 z  }|2dS dS )ad  Iterate 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)rW   changeds     r   rn   zSATSolver._simplify  s^    .  	,Gt(((Gt))+++G  	, 	, 	, 	, 	,r   c                     t          | j                  dk    }| j        rO| j                                        }| | j        v rd| _        g | _        dS |                     |           | j        O|S )z/Perform unit propagation on the current theory.r   TF)rT   r8   r   r5   r7   rt   )rW   resultnext_lits      r   r   zSATSolver._unit_prop  s    T*++a/# 	/,0022HyD---&*#(*%u$$X... # 	/ r   c                     dS )z2Look for pure literals and assign them when found.Fr   r|   s    r   r   zSATSolver._pure_literal  s    ur   c                    g | _         i | _        t          dt          | j                            D ]}t          | j        |                    | j        |<   t          | j        |                     | j        | <   t          | j         | j        |         |f           t          | j         | j        |          | f           dS )z>Initialize the data structures needed for the VSIDS heuristic.r[   N)lit_heap
lit_scoresrangerT   r_   floatr^   r   )rW   vars     r   r>   zSATSolver._vsids_init  s    C 12233 	C 	CC#($*?*D)D#E#EDOC $)4+@#+F*F$G$GDOSD!T]T_S%93$?@@@T]T_cT%:SD$ABBBB		C 	Cr   c                 h    | j                                         D ]}| j         |xx         dz  cc<   dS )a  Decay 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)r   keysr   s     r   _vsids_decayzSATSolver._vsids_decay  sL    * ?'')) 	( 	(COC   C'    	( 	(r   c                 r   t          | j                  dk    rdS | j        t          | j        d         d                            rYt	          | j                   t          | j                  dk    rdS | j        t          | j        d         d                            Yt	          | j                  d         S )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)]

        r   r[   )rT   r   r_   rk   r   r|   s    r   r?   zSATSolver._vsids_calculate  s    * t}""1 DM!$4Q$7 8 89 	DM"""4=!!Q&&q DM!$4Q$7 8 89 	
 t}%%a((r   c                     dS )z;Handle the assignment of a literal for the VSIDS heuristic.Nr   r   s     r   rA   zSATSolver._vsids_lit_assigned/      r   c                     t          |          }t          | j        | j        |         |f           t          | j        | j        |          | f           dS )a  Handle 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)rk   r   r   r   )rW   rh   r   s      r   rC   zSATSolver._vsids_lit_unset3  sU    & #hh!5s ;<<<#!6 =>>>>>r   c                 Z    | xj         dz  c_         |D ]}| j        |xx         dz  cc<   dS )aD  Handle 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)rS   r   r~   s      r   rE   zSATSolver._vsids_clause_addedJ  sR    . 	  A%   	& 	&COC   A%    	& 	&r   c                 X   t          | j                  }| j                            |           |D ]}| j        |xx         dz  cc<   | j        |d                                      |           | j        |d                                      |           |                     |           dS )a  Add 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[   r   rd   N)rT   rU   rL   r^   r\   rf   rF   )rW   r   cls_numrh   s       r   rH   z$SATSolver._simple_add_learned_clauseh  s    2 dl##C    	, 	,C!#&&&!+&&&&s1v""7+++s2w##G,,,s#####r   c                 4    d | j         dd         D             S )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]

        c                     g | ]
}|j          S r   )ro   )r   levels     r   rc   z6SATSolver._simple_compute_conflict.<locals>.<listcomp>  s    ???e%.!???r   r[   Nr{   r|   s    r   rJ   z"SATSolver._simple_compute_conflict  s#      @?t{122????r   c                     dS )zClean up learned clauses.Nr   r|   s    r   rM   zSATSolver._simple_clean_clauses  r   r   )Nr,   r-   r.   N)__name__
__module____qualname____doc__rY   r<   r=   r   propertyrP   r   r   rt   rs   rn   r   r   r>   r   r?   rA   rC   rE   rH   rJ   rM   r   r   r   r   r   R   s         BFDG"3 3 3 3j; ; ;0 0 0.n  n  n f   X(  .* * *&5A 5A 5An  B
, , ,:    	C 	C 	C( ( (0) ) )@  ? ? ?.& & &<"$ "$ "$H@ @ @$    r   r   c                       e Zd ZdZddZdS )rN   z
    Represents a single level in the DPLL algorithm, and contains
    enough information for a sound backtracking procedure.
    Fc                 H    || _         t                      | _        || _        d S r   )ro   r   r5   rm   )rW   ro   rm   s      r   rY   zLevel.__init__  s      EEr   Nr   )r   r   r   r   rY   r   r   r   rN   rN     s2         
     r   rN   N)FF)r   collectionsr   heapqr   r   sympy.core.sortingr   sympy.assumptions.cnfr   !sympy.logic.algorithms.lra_theoryr   r(   r   r   rN   r   r   r   <module>r      s   	 	 $ # # # # # # # # # # # # # & & & & & & , , , , , , 7 7 7 7 7 7* * * *d  N	 N	 N	 N	 N	 N	 N	 N	b	 	 	 	 	 	 	 	 	 	r   