o
    jg-                     @   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  }|r||}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   	from_propextendget_all_relevant_factsadd_from_cnfcheck_satisfiability)	propositionassumptionscontextr   r   props_propscontext_cnfsat r   P/var/www/html/zoom/venv/lib/python3.10/site-packages/sympy/assumptions/satask.pysatask   s   
2



r    c                 C   sp   |  }|  }||  || t|}t|}|r |r d S |r&|s&dS |s,|r,dS |s4|s6tdd S d S )NTFzInconsistent assumptions)copyr   r   
ValueError)prop_propfactbasesat_true	sat_falsecan_be_truecan_be_falser   r   r   r   U   s   

r   Nc                    s   t |  |  }t }|r|| O }|r|| O }|tjtjh }d}|t krNt }|D ]}t |}| @ t kr@||O }q/|  } |O  |t ks*| fdd|D O }t }	|D ]}
t|
trm|	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req_keysr   r   	<setcomp>   s   " z#extract_predargs.<locals>.<setcomp>)
r*   all_predicatesr+   r   truefalse
isinstancer	   	argumentsadd)r   r   r   keyslkeystmp_keystmpr-   symsexprskeyr   r.   r   extract_predargsm   s4   


r>   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.

    )r4   r   r+   r1   r*   atomsr   )predsymbolsar   r   r   r*      s   


r*   c                 C   sn   |st  }t }| D ]&}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
   to_CNF_andr1   r4   r	   r5   )r<   relevant_factsnewexprsexprfactnewfactr=   r   r   r   get_relevant_clsfacts   s   F


rJ   c                    sP  d}t  }t }	 |dkrt| ||}||O }t||\}}|d7 }||kr'n|s*nq	|rt  }	tdd |D r?|	t  tdd |D rN|	t  t }
|
	|	 dd fd	d
}g }g }t
|
j}t|D ]\} | fdd|
jD 7 }|||
j|| 7 }qmt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   T   c                 s   s    | ]
}|j ttkV  qd S N)kindr   r   r,   rG   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 rL   )rM   r   r   rN   r   r   r   rO   U  s   " c                 S   s   | dkr| | S | | S )Nr   r   )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rQ   rR   r   r   r0   b  s    zLget_all_relevant_facts.<locals>.translate_data.<locals>.<listcomp>.<setcomp>r   )r,   clauserT   r   r   
<listcomp>b  s     zBget_all_relevant_facts.<locals>.translate_data.<locals>.<listcomp>r   )datarQ   )rR   )rQ   r   translate_dataa  s   z.get_all_relevant_facts.<locals>.translate_datac                    s   g | ]}| qS r   r   )r,   r@   )rG   r   r   rV   g  s    z*get_all_relevant_facts.<locals>.<listcomp>)r   r+   r>   rJ   anyadd_clausesr   r   r   from_cnflenrA   	enumeraterW   dictlistzipranger   )r   r   r   r   r   rS   rE   	all_exprsr<   known_facts_CNF
kf_encodedrX   rW   rA   n_litencodingctxr   )rG   rR   r   r     sF   4

 
r   )NNrL   )__doc__sympy.core.singletonr   sympy.core.symbolr   sympy.core.kindr   r   sympy.assumptions.ask_generatedr   r   sympy.assumptions.assumer   r	   sympy.assumptions.sathandlersr
   
sympy.corer   sympy.logic.inferencer   sympy.assumptions.cnfr   r   sympy.matrices.kindr   r    r   r>   r*   rJ   r   r   r   r   r   <module>   s(    
D
9
V