ó
¡¼™\c           @  sÏ   d  Z  d d l m Z m Z d d l m Z d d l m Z m Z d d l	 m
 Z
 d d l m Z m Z d d l m Z m Z m Z m Z e d „ Z d	 „  Z d
 e f d „  ƒ  YZ d e f d „  ƒ  YZ d S(   s«   Implementation of DPLL algorithm

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

References:
  - https://en.wikipedia.org/wiki/DPLL_algorithm
iÿÿÿÿ(   t   print_functiont   division(   t   defaultdict(   t   heappusht   heappop(   t   range(   t   default_sort_keyt   ordered(   t	   conjunctst   to_cnft   to_int_reprt   _find_predicatesc         C  sÔ   t  t |  ƒ ƒ } t | k r9 | r5 d „  t g Dƒ St St t |  ƒ d t ƒ} t d t | ƒ d ƒ } t | | ƒ } t	 | | t
 ƒ  | ƒ } | j ƒ  } | r­ t | ƒ Sy t | ƒ SWn t k
 rÏ t SXd S(   s˜  
    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

    c         s  s   |  ] } | Vq d  S(   N(    (   t   .0t   f(    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pys	   <genexpr>)   s    t   keyi   N(   R   R	   t   Falset   sortedR   R   R   t   lenR
   t	   SATSolvert   sett   _find_modelt   _all_modelst   nextt   StopIteration(   t   exprt
   all_modelst   clausest   symbolst   symbols_int_reprt   clauses_int_reprt   solvert   models(    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyt   dpll_satisfiable   s     
c         c  sN   t  } y" x t r& t |  ƒ Vt } q WWn t k
 rI | sJ t  VqJ n Xd  S(   N(   R   t   TrueR   R   (   R   t   satisfiable(    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR   @   s    	R   c           B  sÝ   e  Z d  Z d d d 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 RS(   s‚   
    Class for representing a SAT solver capable of
     finding a model to a boolean theory in conjunctive
     normal form.
    t   vsidst   noneiô  c         C  sy  | |  _  | |  _ t |  _ g  |  _ g  |  _ | |  _ | d  k rZ t t	 | ƒ ƒ |  _
 n	 | |  _
 |  j | ƒ |  j | ƒ d | k rÆ |  j ƒ  |  j |  _ |  j |  _ |  j |  _ |  j |  _ n t ‚ d | k r|  j |  _ |  j |  _ |  j j |  j ƒ n- d | k r-d „  |  _ d „  |  _ n t ‚ t d ƒ g |  _ | |  j _  d |  _! d |  _" t# |  j$ ƒ |  _% d  S(   NR#   t   simpleR$   c         S  s   d  S(   N(   t   None(   t   x(    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyt   <lambda>v   t    c           S  s   d  S(   N(   R&   (    (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR(   w   R)   i    (&   t   var_settingst	   heuristicR   t   is_unsatisfiedt   _unit_prop_queuet   update_functionst   INTERVALR&   t   listR   R   t   _initialize_variablest   _initialize_clausest   _vsids_initt   _vsids_calculatet   heur_calculatet   _vsids_lit_assignedt   heur_lit_assignedt   _vsids_lit_unsett   heur_lit_unsett   _vsids_clause_addedt   heur_clause_addedt   NotImplementedErrort   _simple_add_learned_clauset   add_learned_clauset   simple_compute_conflictt   compute_conflictt   appendt   simple_clean_clausest   Levelt   levelst   _current_levelt   varsettingst   num_decisionst   num_learned_clausesR   R   t   original_num_clauses(   t   selfR   t	   variablesR*   R   R+   t   clause_learningR/   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyt   __init__R   s>    							
		c         C  s<   t  t ƒ |  _ t  t ƒ |  _ t g t | ƒ d |  _ d S(   s+   Set up the variable data structures needed.i   N(   R   R   t	   sentinelst   intt   occurrence_countR   R   t   variable_set(   RJ   RK   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR1   „   s    c         C  s÷   g  |  _  x$ | D] } |  j  j t | ƒ ƒ q WxÀ t t |  j  ƒ ƒ D]© } d t |  j  | ƒ k r† |  j j |  j  | d ƒ qF n  |  j |  j  | d j | ƒ |  j |  j  | d j | ƒ x( |  j  | D] } |  j | c d 7<qÒ WqF Wd S(   s<  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.
        i   i    iÿÿÿÿN(	   R   RA   R0   R   R   R-   RN   t   addRP   (   RJ   R   t   clst   it   lit(    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR2   Š   s    	c         #  sû  t  } ˆ  j ƒ  ˆ  j r d Sx×t röˆ  j ˆ  j d k rZ x ˆ  j D] } | ƒ  qF Wn  | ru t  } ˆ  j j } nÐ ˆ  j	 ƒ  } ˆ  j d 7_ d | k r/t
 ‡  f d †  ˆ  j Dƒ ƒ Vx ˆ  j j rÖ ˆ  j ƒ  q½ Wt ˆ  j ƒ d k rð d Sˆ  j j } ˆ  j ƒ  ˆ  j j t | d t ƒƒ t } q  n  ˆ  j j t | ƒ ƒ ˆ  j | ƒ ˆ  j ƒ  ˆ  j r  t  ˆ  _ x3 ˆ  j j r£ˆ  j ƒ  d t ˆ  j ƒ k rqd SqqWˆ  j ˆ  j ƒ  ƒ ˆ  j j } ˆ  j ƒ  ˆ  j j t | d t ƒƒ t } q  q  Wd S(   sm  
        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}]
        Ni    i   c         3  s2   |  ]( } ˆ  j  t | ƒ d  | d k f Vq d S(   i   i    N(   R   t   abs(   R   RU   (   RJ   (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pys	   <genexpr>Ø   s   t   flipped(   R   t	   _simplifyR,   R!   RG   R/   R.   RE   t   decisionR5   t   dictR*   RW   t   _undoR   RD   RA   RC   t   _assign_literalR>   R@   (   RJ   t   flip_vart   funcRU   t   flip_lit(    (   RJ   s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR   £   sN    
		

		

c         C  s   |  j  d S(   s£  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}
        iÿÿÿÿ(   RD   (   RJ   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyRE     s    c         C  s/   x( |  j  | D] } | |  j k r t Sq Wt S(   s¡  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
        (   R   R*   R!   R   (   RJ   RS   RU   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyt   _clause_sat  s    c         C  s   | |  j  | k S(   s¨  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
        (   RN   (   RJ   RU   RS   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyt   _is_sentinel0  s    c         C  s&  |  j  j | ƒ |  j j  j | ƒ t |  j t | ƒ <|  j | ƒ t |  j | ƒ } xÈ | D]À } |  j	 | ƒ s^ d } x† |  j | D]w } | | k r‡ |  j | | ƒ rµ | } qþ |  j t | ƒ sþ |  j | j | ƒ |  j | j | ƒ d } Pqþ q‡ q‡ W| r|  j j | ƒ qq^ q^ Wd S(   sÛ  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}
        N(   R*   RR   RE   R!   RQ   RV   R7   R0   RN   R`   R&   R   Ra   t   removeR-   RA   (   RJ   RU   t   sentinel_listRS   t   other_sentinelt   newlit(    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR\   B  s&    	c         C  sX   xD |  j  j D]6 } |  j j | ƒ |  j | ƒ t |  j t | ƒ <q W|  j j ƒ  d S(   sf  
        _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)
        N(	   RE   R*   Rb   R9   R   RQ   RV   RD   t   pop(   RJ   RU   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR[   x  s
    c         C  s=   t  } x0 | r8 t } | |  j ƒ  O} | |  j ƒ  O} q	 Wd S(   sc  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}}
        N(   R!   R   t
   _unit_propt   _pure_literal(   RJ   t   changed(    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyRX     s
    	c         C  sk   t  |  j ƒ d k } xO |  j rf |  j j ƒ  } | |  j k rV t |  _ g  |  _ t S|  j | ƒ q W| S(   s/   Perform unit propagation on the current theory.i    (   R   R-   Rf   R*   R!   R,   R   R\   (   RJ   t   resultt   next_lit(    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyRg   ¹  s    		c         C  s   t  S(   s2   Look for pure literals and assign them when found.(   R   (   RJ   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyRh   Ç  s    c         C  s­   g  |  _  i  |  _ x” t d t |  j ƒ ƒ D]z } t |  j | ƒ |  j | <t |  j | ƒ |  j | <t |  j  |  j | | f ƒ t |  j  |  j | | f ƒ q+ Wd S(   s>   Initialize the data structures needed for the VSIDS heuristic.i   N(   t   lit_heapt
   lit_scoresR   R   RQ   t   floatRP   R   (   RJ   t   var(    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR3   Î  s    		c         C  s1   x* |  j  j ƒ  D] } |  j  | c d <q Wd S(   sÊ  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(   Rm   t   keys(   RJ   RU   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyt   _vsids_decayÙ  s    c         C  su   t  |  j ƒ d k r d SxH |  j t |  j d d ƒ rc t |  j ƒ t  |  j ƒ d k r d Sq Wt |  j ƒ d S(   sà  
            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)]
        i    i   (   R   Rl   RQ   RV   R   (   RJ   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR4   ð  s    !c         C  s   d S(   s;   Handle the assignment of a literal for the VSIDS heuristic.N(    (   RJ   RU   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR6     s    c         C  sL   t  | ƒ } t |  j |  j | | f ƒ t |  j |  j | | f ƒ d S(   s  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(   RV   R   Rl   Rm   (   RJ   RU   Ro   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR8     s    c         C  s7   |  j  d 7_  x! | D] } |  j | c d 7<q Wd S(   sC  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}
        i   N(   RH   Rm   (   RJ   RS   RU   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR:   )  s    c         C  s„   t  |  j ƒ } |  j j | ƒ x! | D] } |  j | c d 7<q& W|  j | d j | ƒ |  j | d j | ƒ |  j | ƒ d S(   s  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}}
        i   i    iÿÿÿÿN(   R   R   RA   RP   RN   RR   R;   (   RJ   RS   t   cls_numRU   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR=   F  s    c         C  s"   g  |  j  d D] } | j ^ q S(   sª   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]
        i   (   RD   RY   (   RJ   t   level(    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyt   _simple_compute_conflicti  s    c         C  s   d S(   s   Clean up learned clauses.N(    (   RJ   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyt   _simple_clean_clausesz  s    N(   t   __name__t
   __module__t   __doc__R&   RM   R1   R2   R   t   propertyRE   R`   Ra   R\   R[   RX   Rg   Rh   R3   Rq   R4   R6   R8   R:   R=   Rt   Ru   (    (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyR   K   s.   1			c			6	%										#	RC   c           B  s   e  Z d  Z e d „ Z RS(   s‚   
    Represents a single level in the DPLL algorithm, and contains
    enough information for a sound backtracking procedure.
    c         C  s"   | |  _  t ƒ  |  _ | |  _ d  S(   N(   RY   R   R*   RW   (   RJ   RY   RW   (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyRM   …  s    	(   Rv   Rw   Rx   R   RM   (    (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyRC     s   N(   Rx   t
   __future__R    R   t   collectionsR   t   heapqR   R   t   sympy.core.compatibilityR   t   sympyR   R   t   sympy.logic.boolalgR   R	   R
   R   R   R    R   t   objectR   RC   (    (    (    s;   lib/python2.7/site-packages/sympy/logic/algorithms/dpll2.pyt   <module>
   s   "+	ÿ ÿ 6