
    sg#                         d Z ddlmZ ddlmZmZmZmZmZm	Z	m
Z
 ddlmZ ddlmZmZ d Zd Zd Zi fd	Zd
 Zd Zd Zd Zd Zd Zy)a&  Implementation of DPLL algorithm

Further improvements: eliminate calls to pl_true, implement branching rules,
efficient unit propagation.

References:
  - https://en.wikipedia.org/wiki/DPLL_algorithm
  - https://www.researchgate.net/publication/242384772_Implementations_of_the_DPLL_Algorithm
    )default_sort_key)OrNot	conjuncts	disjunctsto_cnfto_int_repr_find_predicates)CNF)pl_trueliteral_symbolc                 l   t        | t              st        t        |             }n| j                  }d|v ryt        t        |       t              }t        t        dt        |      dz               }t        ||      }t        ||i       }|s|S i }|D ]  }|j                  ||dz
     ||   i         |S )a>  
    Check satisfiability of a propositional sentence.
    It returns a model rather than True when it succeeds

    >>> from sympy.abc import A, B
    >>> from sympy.logic.algorithms.dpll import dpll_satisfiable
    >>> dpll_satisfiable(A & ~B)
    {A: True, B: False}
    >>> dpll_satisfiable(A & ~A)
    False

    F)key   )
isinstancer   r   r   clausessortedr
   r   setrangelenr	   dpll_int_reprupdate)exprr   symbolssymbols_int_reprclauses_int_reprresultoutputr   s           N/var/www/html/venv/lib/python3.12/site-packages/sympy/logic/algorithms/dpll.pydpll_satisfiabler       s     dC F4L),,%d+1ABG5CL1$456"7G4+-=rBFF 7wsQw'567M    c                    t        | |      \  }}|rG|j                  ||i       |j                  |       |s| }t        | |      } t        | |      \  }}|rGt	        ||       \  }}|rG|j                  ||i       |j                  |       |s| }t        | |      } t	        ||       \  }}|rGg }| D ]*  }t        ||      }|du r y|dus|j                  |       , |s|S | s|S |j                         }|j                         }|j                  |di       |j                  |di       |dd }	t        t        ||      ||      xs  t        t        |t        |            |	|      S )z
    Compute satisfiability in a partial model.
    Clauses is an array of conjuncts.

    >>> from sympy.abc import A, B, D
    >>> from sympy.logic.algorithms.dpll import dpll
    >>> dpll([A, B, D], [A, B], {D: False})
    False

    FTN)find_unit_clauser   removeunit_propagatefind_pure_symbolr   appendpopcopydpllr   
r   r   modelPvalueunknown_clausescval
model_copysymbols_copys
             r   r*   r*   1   s     /HAu
aZ qA !,#GU35   1HAu
aZ qA !,#GW55  O &a%<d?""1%& AJ	LL!Tq%j!1:L3WeD TQ8,
SUr!   c                    t        | |      \  }}|rG|j                  ||i       |j                  |       |s| }t        | |      } t        | |      \  }}|rGt	        ||       \  }}|rG|j                  ||i       |j                  |       |s| }t        | |      } t	        ||       \  }}|rGg }| D ]*  }t        ||      }|du r y|dus|j                  |       , |s|S |j                         }|j                         }|j                  |di       |j                  |di       |j                         }	t        t        ||      ||      xs t        t        ||       |	|      S )z
    Compute satisfiability in a partial model.
    Arguments are expected to be in integer representation

    >>> from sympy.logic.algorithms.dpll import dpll_int_repr
    >>> dpll_int_repr([{1}, {2}, {3}], {1, 2}, {3: False})
    False

    FT)
find_unit_clause_int_reprr   r$   unit_propagate_int_reprfind_pure_symbol_int_reprpl_true_int_reprr'   r(   r)   r   r+   s
             r   r   r   b   s    )%8HAu
aZ qA)'15,We<5  )':HAu
aZ qA)'15,Wg>5  O &q%(%<d?""1%& AJ	LL!Tq%j!<<>L1/1EwPUV b1/A2FV`acr!   c                     d}| D ];  }|dk  r|j                  |       }|| }n|j                  |      }|du r y|:d}= |S )af  
    Lightweight version of pl_true.
    Argument clause represents the set of args of an Or clause. This is used
    inside dpll_int_repr, it is not meant to be used directly.

    >>> from sympy.logic.algorithms.dpll import pl_true_int_repr
    >>> pl_true_int_repr({1, 2}, {1: False})
    >>> pl_true_int_repr({1, 2}, {1: False, 2: False})
    False

    Fr   NT)get)clauser,   r   litps        r   r8   r8      sb     F 
7		3$A}E		#A9YF
 Mr!   c                 :   g }| D ]  }|j                   t        k7  r|j                  |       (|j                  D ]G  }|| k(  r8|j                  t        |j                  D cg c]  }|| k7  s
| c}         u||k(  sG } |j                  |        |S c c}w )a  
    Returns an equivalent set of clauses
    If a set of clauses contains the unit clause l, the other clauses are
    simplified by the application of the two following rules:

      1. every clause containing l is removed
      2. in every clause that contains ~l this literal is deleted

    Arguments are expected to be in CNF.

    >>> from sympy.abc import A, B, D
    >>> from sympy.logic.algorithms.dpll import unit_propagate
    >>> unit_propagate([A | B, D | ~B, B], B)
    [D, B]

    )funcr   r'   args)r   symbolr   r0   argxs         r   r%   r%      s    " F 66R<MM!66 	Cvg~baff"EfW1"EFGf}	 MM! M #Fs    B,Bc                 D    | h}| D cg c]  }||vs||z
   c}S c c}w )z
    Same as unit_propagate, but arguments are expected to be in integer
    representation

    >>> from sympy.logic.algorithms.dpll import unit_propagate_int_repr
    >>> unit_propagate_int_repr([{1, 2}, {3, -2}, {2}], 2)
    [{3}]

     )r   snegatedr;   s       r   r6   r6      s,     rdG+2FavoFWFFFs   	c                     | D ]F  }d\  }}|D ]/  }|s|t        |      v rd}|rt        |      t        |      v s.d}1 ||k7  sB||fc S  y)a#  
    Find a symbol and its value if it appears only as a positive literal
    (or only as a negative) in clauses.

    >>> from sympy.abc import A, B, D
    >>> from sympy.logic.algorithms.dpll import find_pure_symbol
    >>> find_pure_symbol([A, B, D], [A|~B,~B|~D,D|A])
    (A, True)

    )FFTNN)r   r   )r   r/   sym	found_pos	found_negr0   s         r   r&   r&      so      "+	9  	!A	!!4 	SYq\!9 			!
 	!	>!" r!   c                      t               j                  | }|j                  |       }|j                  | D cg c]  }|  c}      }|D ]  }| |vs	|dfc S  |D ]  }| |vs	| dfc S  yc c}w )a  
    Same as find_pure_symbol, but arguments are expected
    to be in integer representation

    >>> from sympy.logic.algorithms.dpll import find_pure_symbol_int_repr
    >>> find_pure_symbol_int_repr({1,2,3},
    ...     [{1, -2}, {-2, -3}, {3, 1}])
    (1, True)

    TFrI   )r   unionintersection)r   r/   all_symbolsrK   rF   rL   r=   s          r   r7   r7      s     #%++/K((1I((g)>1")>?I 2Yd7N  2Y2u9  *?s   
A/c                     | D ]G  }d}t        |      D ]*  }t        |      }||vs|dz  }|t        |t               }}, |dk(  sCfc S  y)a  
    A unit clause has only 1 variable that is not bound in the model.

    >>> from sympy.abc import A, B, D
    >>> from sympy.logic.algorithms.dpll import find_unit_clause
    >>> find_unit_clause([A | B | D, B | ~D, A | ~B], {A:True})
    (B, False)

    r   r   rI   )r   r   r   r   )r   r,   r;   num_not_in_modelliteralrJ   r-   r.   s           r   r#   r#   
  su       ( 	=G )C% A% Jw$< <5		=
 q e8O r!   c                     t        |      |D ch c]  }|  c}z  }| D ]7  }||z
  }t        |      dk(  s|j                         }|dk  r| dfc S |dfc S  yc c}w )a  
    Same as find_unit_clause, but arguments are expected to be in
    integer representation.

    >>> from sympy.logic.algorithms.dpll import find_unit_clause_int_repr
    >>> find_unit_clause_int_repr([{1, 2, 3},
    ...     {2, -3}, {1, -2}], {1: True})
    (2, False)

    r   r   FTrI   )r   r   r(   )r   r,   rJ   boundr;   unboundr=   s          r   r5   r5      st     J%033$00E 5.w<1A1ur5y $w  1s   
AN)__doc__sympy.core.sortingr   sympy.logic.boolalgr   r   r   r   r   r	   r
   sympy.assumptions.cnfr   sympy.logic.inferencer   r   r    r*   r   r8   r%   r6   r&   r7   r#   r5   rE   r!   r   <module>r\      sa    0" " " % 9>.Ub+c` $& 6BG..,r!   