U
    ZÊ¹já-  ã                   @   sÔ   d Z ddlmZ ddlmZ ddlmZmZ ddlm	Z	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
lmZmZ ddlmZ dedefdd„Zdd„ Zddd„Zdd„ Zddd„Zdefdd„ZdS )zJ
Module to evaluate the proposition with assumptions using SAT algorithm.
é    )ÚS)ÚSymbol)Ú
NumberKindÚUndefinedKind)Úget_all_known_matrix_factsÚget_all_known_number_facts)Úglobal_assumptionsÚAppliedPredicate)Úclass_fact_registry)Úoo)Úsatisfiable)ÚCNFÚ
EncodedCNF)Ú
MatrixKindTc           	      C   sj   t  | ¡}t  |  ¡}t  |¡}t ƒ }|r4| |¡}t|||||d�}| |¡ |r^| |¡ t|||ƒS )a  
    Function to evaluate the proposition with assumptions using SAT algorithm.

    This function extracts every fact relevant to the expressions composing
    proposition and assumptions. For example, if a predicate containing
    ``Abs(x)`` is proposed, then ``Q.zero(Abs(x)) | Q.positive(Abs(x))``
    will be found and passed to SAT solver because ``Q.nonnegative`` is
    registered as a fact for ``Abs``.

    Proposition is evaluated to ``True`` or ``False`` if the truth value can be
    determined. If not, ``None`` is returned.

    Parameters
    ==========

    proposition : Any boolean expression.
        Proposition which will be evaluated to boolean value.

    assumptions : Any boolean expression, optional.
        Local assumptions to evaluate the *proposition*.

    context : AssumptionsContext, optional.
        Default assumptions to evaluate the *proposition*. By default,
        this is ``sympy.assumptions.global_assumptions`` variable.

    use_known_facts : bool, optional.
        If ``True``, facts from ``sympy.assumptions.ask_generated``
        module are passed to SAT solver as well.

    iterations : int, optional.
        Number of times that relevant facts are recursively extracted.
        Default is infinite times until no new fact is found.

    Returns
    =======

    ``True``, ``False``, or ``None``

    Examples
    ========

    >>> from sympy import Abs, Q
    >>> from sympy.assumptions.satask import satask
    >>> from sympy.abc import x
    >>> satask(Q.zero(Abs(x)), Q.zero(x))
    True

    )Úuse_known_factsÚ
iterations)r   Z	from_propÚextendÚget_all_relevant_factsÚadd_from_cnfÚcheck_satisfiability)	ÚpropositionÚassumptionsÚcontextr   r   ÚpropsZ_propsZcontext_cnfÚsat© r   úW/var/www/html/bwave/python/venv/lib/python3.8/site-packages/sympy/assumptions/satask.pyÚsatask   s    2


 ÿ

r   c                 C   sl   |  ¡ }|  ¡ }| | ¡ | |¡ t|ƒ}t|ƒ}|r@|r@d S |rL|sLdS |sX|rXdS |sh|shtdƒ‚d S )NTFzInconsistent assumptions)Úcopyr   r   Ú
ValueError)ÚpropZ_propZfactbaseZsat_trueZ	sat_falseZcan_be_trueZcan_be_falser   r   r   r   U   s    

r   Nc                    sâ   t | ƒ‰ |  ¡ }tƒ }|r&|| ¡ O }|r6|| ¡ O }|tjtjh }d}|tƒ kr”tƒ }|D ]"}t |ƒ}|ˆ @ tƒ kr^||O }q^|ˆ  }ˆ |O ‰ qJ|‡ fdd„|D ƒO }tƒ }	|D ](}
t|
tƒrÒ|	t|
jƒO }	q´|	 	|
¡ q´|	S )aÍ  
    Extract every expression in the argument of predicates from *proposition*,
    *assumptions* and *context*.

    Parameters
    ==========

    proposition : sympy.assumptions.cnf.CNF

    assumptions : sympy.assumptions.cnf.CNF, optional.

    context : sympy.assumptions.cnf.CNF, optional.
        CNF generated from assumptions context.

    Examples
    ========

    >>> from sympy import Q, Abs
    >>> from sympy.assumptions.cnf import CNF
    >>> from sympy.assumptions.satask import extract_predargs
    >>> from sympy.abc import x, y
    >>> props = CNF.from_prop(Q.zero(Abs(x*y)))
    >>> assump = CNF.from_prop(Q.zero(x) & Q.zero(y))
    >>> extract_predargs(props, assump)
    {x, y, Abs(x*y)}

    Nc                    s"   h | ]}t |ƒˆ @ tƒ kr|’qS r   )Úfind_symbolsÚset)Ú.0Úl©Zreq_keysr   r   Ú	<setcomp>œ   s      z#extract_predargs.<locals>.<setcomp>)
r!   Úall_predicatesr"   r   ÚtrueÚfalseÚ
isinstancer	   Ú	argumentsÚadd)r   r   r   ÚkeysZlkeysZtmp_keysÚtmpr$   ZsymsÚexprsÚkeyr   r%   r   Úextract_predargsm   s0    



r1   c                 C   s8   t | tƒr.tƒ }|  ¡ D ]}|t|ƒO }q|S |  t¡S )zƒ
    Find every :obj:`~.Symbol` in *pred*.

    Parameters
    ==========

    pred : sympy.assumptions.cnf.CNF, or any Expr.

    )r*   r   r"   r'   r!   Zatomsr   )ÚpredÚsymbolsÚar   r   r   r!   ¦   s    

r!   c                 C   sn   |s
t ƒ }tƒ }| D ]L}t|ƒD ]>}t  |¡}| |¡}| ¡ D ]}t|tƒr@|t|jƒO }q@q q||  |fS )a2	  
    Extract relevant facts from the items in *exprs*. Facts are defined in
    ``assumptions.sathandlers`` module.

    This function is recursively called by ``get_all_relevant_facts()``.

    Parameters
    ==========

    exprs : set
        Expressions whose relevant facts are searched.

    relevant_facts : sympy.assumptions.cnf.CNF, optional.
        Pre-discovered relevant facts.

    Returns
    =======

    exprs : set
        Candidates for next relevant fact searching.

    relevant_facts : sympy.assumptions.cnf.CNF
        Updated relevant facts.

    Examples
    ========

    Here, we will see how facts relevant to ``Abs(x*y)`` are recursively
    extracted. On the first run, set containing the expression is passed
    without pre-discovered relevant facts. The result is a set containing
    candidates for next run, and ``CNF()`` instance containing facts
    which are relevant to ``Abs`` and its argument.

    >>> from sympy import Abs
    >>> from sympy.assumptions.satask import get_relevant_clsfacts
    >>> from sympy.abc import x, y
    >>> exprs = {Abs(x*y)}
    >>> exprs, facts = get_relevant_clsfacts(exprs)
    >>> exprs
    {x*y}
    >>> facts.clauses #doctest: +SKIP
    {frozenset({Literal(Q.odd(Abs(x*y)), False), Literal(Q.odd(x*y), True)}),
    frozenset({Literal(Q.zero(Abs(x*y)), False), Literal(Q.zero(x*y), True)}),
    frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.even(x*y), True)}),
    frozenset({Literal(Q.zero(Abs(x*y)), True), Literal(Q.zero(x*y), False)}),
    frozenset({Literal(Q.even(Abs(x*y)), False),
                Literal(Q.odd(Abs(x*y)), False),
                Literal(Q.odd(x*y), True)}),
    frozenset({Literal(Q.even(Abs(x*y)), False),
                Literal(Q.even(x*y), True),
                Literal(Q.odd(Abs(x*y)), False)}),
    frozenset({Literal(Q.positive(Abs(x*y)), False),
                Literal(Q.zero(Abs(x*y)), False)})}

    We pass the first run's results to the second run, and get the expressions
    for next run and updated facts.

    >>> exprs, facts = get_relevant_clsfacts(exprs, relevant_facts=facts)
    >>> exprs
    {x, y}

    On final run, no more candidate is returned thus we know that all
    relevant facts are successfully retrieved.

    >>> exprs, facts = get_relevant_clsfacts(exprs, relevant_facts=facts)
    >>> exprs
    set()

    )	r   r"   r
   Zto_CNFZ_andr'   r*   r	   r+   )r/   Úrelevant_factsZnewexprsÚexprZfactZnewfactr0   r   r   r   Úget_relevant_clsfacts¸   s    F


r7   c                    sP  d}t ƒ }tƒ }|dkr$t| ||ƒ}||O }t||ƒ\}}|d7 }||krLqT|sqTq|�r<t ƒ }	tdd„ |D ƒƒr~|	 tƒ ¡ tdd„ |D ƒƒrœ|	 tƒ ¡ tƒ }
|
 	|	¡ dd„ ‰‡fdd	„}g }g }t
|
jƒ}t|ƒD ]4\}‰ |‡ fd
d„|
jD ƒ7 }|||
j|| ƒ7 }qÚttt|tdt
|ƒd ƒƒƒƒ}t||ƒ}ntƒ }| |¡ |S )al  
    Extract all relevant facts from *proposition* and *assumptions*.

    This function extracts the facts by recursively calling
    ``get_relevant_clsfacts()``. Extracted facts are converted to
    ``EncodedCNF`` and returned.

    Parameters
    ==========

    proposition : sympy.assumptions.cnf.CNF
        CNF generated from proposition expression.

    assumptions : sympy.assumptions.cnf.CNF
        CNF generated from assumption expression.

    context : sympy.assumptions.cnf.CNF
        CNF generated from assumptions context.

    use_known_facts : bool, optional.
        If ``True``, facts from ``sympy.assumptions.ask_generated``
        module are encoded as well.

    iterations : int, optional.
        Number of times that relevant facts are recursively extracted.
        Default is infinite times until no new fact is found.

    Returns
    =======

    sympy.assumptions.cnf.EncodedCNF

    Examples
    ========

    >>> from sympy import Q
    >>> from sympy.assumptions.cnf import CNF
    >>> from sympy.assumptions.satask import get_all_relevant_facts
    >>> from sympy.abc import x, y
    >>> props = CNF.from_prop(Q.nonzero(x*y))
    >>> assump = CNF.from_prop(Q.nonzero(x))
    >>> context = CNF.from_prop(Q.nonzero(y))
    >>> get_all_relevant_facts(props, assump, context) #doctest: +SKIP
    <sympy.assumptions.cnf.EncodedCNF at 0x7f09faa6ccd0>

    r   é   c                 s   s   | ]}|j ttƒkV  qd S ©N)Úkindr   r   ©r#   r6   r   r   r   Ú	<genexpr>R  s     z)get_all_relevant_facts.<locals>.<genexpr>c                 s   s"   | ]}|j tkp|j tkV  qd S r9   )r:   r   r   r;   r   r   r   r<   U  s     c                 S   s   | dkr| | S | | S d S )Nr   r   )ZlitÚdeltar   r   r   Útranslate_literal[  s    z1get_all_relevant_facts.<locals>.translate_literalc                    s   ‡ ‡fdd„| D ƒS )Nc                    s    g | ]}‡ ‡fd d„|D ƒ‘qS )c                    s   h | ]}ˆ|ˆ ƒ’qS r   r   )r#   Úi©r=   r>   r   r   r&   b  s     zLget_all_relevant_facts.<locals>.translate_data.<locals>.<listcomp>.<setcomp>r   )r#   Zclauser@   r   r   Ú
<listcomp>b  s     zBget_all_relevant_facts.<locals>.translate_data.<locals>.<listcomp>r   )Údatar=   )r>   )r=   r   Útranslate_dataa  s    z.get_all_relevant_facts.<locals>.translate_datac                    s   g | ]}|ˆ ƒ‘qS r   r   )r#   r2   )r6   r   r   rA   g  s     z*get_all_relevant_facts.<locals>.<listcomp>)r   r"   r1   r7   ÚanyZadd_clausesr   r   r   Zfrom_cnfÚlenr3   Ú	enumeraterB   ÚdictÚlistÚzipÚranger   )r   r   r   r   r   r?   r5   Z	all_exprsr/   Zknown_facts_CNFZ
kf_encodedrC   rB   r3   Zn_litÚencodingÚctxr   )r6   r>   r   r     sB    4

 
r   )NN)N)Ú__doc__Zsympy.core.singletonr   Zsympy.core.symbolr   Zsympy.core.kindr   r   Zsympy.assumptions.ask_generatedr   r   Zsympy.assumptions.assumer   r	   Zsympy.assumptions.sathandlersr
   Z
sympy.corer   Zsympy.logic.inferencer   Zsympy.assumptions.cnfr   r   Zsympy.matrices.kindr   r   r   r1   r!   r7   r   r   r   r   r   Ú<module>   s*    ÿ
D
9
V ÿ