U
    ZÊ¹jä#  ã                   @   s¨   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d„ Zdd	„ Zd
d„ Zi fdd„Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ ZdS )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                 C   sš   t | tƒstt| ƒƒ}n| j}d|kr*dS tt| ƒtd�}tt	dt
|ƒd ƒƒ}t||ƒ}t||i ƒ}|sn|S i }|D ]}| ||d  || i¡ qv|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   ÚsymbolsZsymbols_int_reprZclauses_int_reprÚresultÚoutputr   © r   úZ/var/www/html/bwave/python/venv/lib/python3.8/site-packages/sympy/logic/algorithms/dpll.pyÚdpll_satisfiable   s    

r   c           
      C   sF  t | |ƒ\}}|rN| ||i¡ | |¡ |s4| }t| |ƒ} t | |ƒ\}}qt|| ƒ\}}|rœ| ||i¡ | |¡ |s‚| }t| |ƒ} t|| ƒ\}}q\g }| D ].}t||ƒ}|dkrÀ dS |dk	r¤| |¡ q¤|sÜ|S | sä|S | ¡ }| ¡ }| |di¡ | |di¡ |dd… }	t	t||ƒ||ƒ�pDt	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ÚvalZ
model_copyZsymbols_copyr   r   r   r%   1   sF    




ÿr%   c           
      C   s8  t | |ƒ\}}|rN| ||i¡ | |¡ |s4| }t| |ƒ} t | |ƒ\}}qt|| ƒ\}}|rœ| ||i¡ | |¡ |s‚| }t| |ƒ} t|| ƒ\}}q\g }| D ].}t||ƒ}|dkrÀ dS |dk	r¤| |¡ q¤|sÜ|S | ¡ }| ¡ }| |di¡ | |di¡ | ¡ }	t	t||ƒ||ƒ�p6t	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&   r   r   r   r   b   sB    




ÿr   c                 C   sZ   d}| D ]L}|dk r0|  | ¡}|dk	r:| }n
|  |¡}|dkrH dS |dkrd}q|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   ZlitÚpr   r   r   r0   ’   s    
r0   c                    sv   g }| D ]h}|j tkr"| |¡ q|jD ]<}|ˆ  krX| t‡ fdd„|jD ƒŽ ¡  q|ˆ kr( qq(| |¡ q|S )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]

    c                    s   g | ]}|ˆ  kr|‘qS r   r   )Ú.0Úx©Úsymbolr   r   Ú
<listcomp>Å   s     
 z"unit_propagate.<locals>.<listcomp>)Úfuncr   r"   Úargs)r   r7   r   r+   Úargr   r6   r   r    ­   s    



r    c                    s   ˆ h‰ ‡ ‡fdd„| D ƒS )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}]

    c                    s   g | ]}ˆ|kr|ˆ  ‘qS r   r   )r4   r2   ©ZnegatedÚsr   r   r8   Ù   s      z+unit_propagate_int_repr.<locals>.<listcomp>r   )r   r=   r   r<   r   r.   Î   s    
r.   c                 C   s`   | D ]V}d\}}|D ]0}|s,|t |ƒkr,d}|st|ƒt |ƒkrd}q||kr||f  S qdS )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_negr+   r   r   r   r!   Ü   s    r!   c                 C   sp   t ƒ j|Ž }| | ¡}| dd„ | D ƒ¡}|D ]}| |kr.|df  S q.|D ]}| |krN| df  S qNdS )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)

    c                 S   s   g | ]
}| ‘qS r   r   )r4   r=   r   r   r   r8      s     z-find_pure_symbol_int_repr.<locals>.<listcomp>TFr>   )r   ÚunionÚintersection)r   r*   Zall_symbolsr@   rA   r3   r   r   r   r/   ó   s    


r/   c                 C   s^   | D ]T}d}t |ƒD ].}t|ƒ}||kr|d7 }|t|tƒ  }}q|dkr||f  S qdS )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   r>   )r   r   r   r   )r   r'   r2   Znum_not_in_modelÚliteralr?   r(   r)   r   r   r   r   
  s    
r   c                 C   sb   t |ƒdd„ |D ƒB }| D ]B}|| }t|ƒdkr| ¡ }|dk rP| df  S |df  S qdS )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)

    c                 S   s   h | ]
}| ’qS r   r   )r4   r?   r   r   r   Ú	<setcomp>+  s     z,find_unit_clause_int_repr.<locals>.<setcomp>r   r   FTr>   )r   r   r#   )r   r'   Úboundr2   Úunboundr3   r   r   r   r-      s    r-   N)Ú__doc__Zsympy.core.sortingr   Zsympy.logic.boolalgr   r   r   r   r   r   r	   Zsympy.assumptions.cnfr
   Zsympy.logic.inferencer   r   r   r%   r   r0   r    r.   r!   r/   r   r-   r   r   r   r   Ú<module>   s   
$10!