Buckets:
MisterAI/LocalAI_Demo_backends / cpu-diffusers.upgrade-tmp /venv /lib /python3.10 /site-packages /sympy /assumptions /satask.py
| """ | |
| Module to evaluate the proposition with assumptions using SAT algorithm. | |
| """ | |
| from sympy.core.singleton import S | |
| from sympy.core.symbol import Symbol | |
| from sympy.core.kind import NumberKind, UndefinedKind | |
| from sympy.assumptions.ask_generated import get_all_known_matrix_facts, get_all_known_number_facts | |
| from sympy.assumptions.assume import global_assumptions, AppliedPredicate | |
| from sympy.assumptions.sathandlers import class_fact_registry | |
| from sympy.core import oo | |
| from sympy.logic.inference import satisfiable | |
| from sympy.assumptions.cnf import CNF, EncodedCNF | |
| from sympy.matrices.kind import MatrixKind | |
| def satask(proposition, assumptions=True, context=global_assumptions, | |
| use_known_facts=True, iterations=oo): | |
| """ | |
| 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 | |
| """ | |
| props = CNF.from_prop(proposition) | |
| _props = CNF.from_prop(~proposition) | |
| assumptions = CNF.from_prop(assumptions) | |
| context_cnf = CNF() | |
| if context: | |
| context_cnf = context_cnf.extend(context) | |
| sat = get_all_relevant_facts(props, assumptions, context_cnf, | |
| use_known_facts=use_known_facts, iterations=iterations) | |
| sat.add_from_cnf(assumptions) | |
| if context: | |
| sat.add_from_cnf(context_cnf) | |
| return check_satisfiability(props, _props, sat) | |
| def check_satisfiability(prop, _prop, factbase): | |
| sat_true = factbase.copy() | |
| sat_false = factbase.copy() | |
| sat_true.add_from_cnf(prop) | |
| sat_false.add_from_cnf(_prop) | |
| can_be_true = satisfiable(sat_true) | |
| can_be_false = satisfiable(sat_false) | |
| if can_be_true and can_be_false: | |
| return None | |
| if can_be_true and not can_be_false: | |
| return True | |
| if not can_be_true and can_be_false: | |
| return False | |
| if not can_be_true and not can_be_false: | |
| # TODO: Run additional checks to see which combination of the | |
| # assumptions, global_assumptions, and relevant_facts are | |
| # inconsistent. | |
| raise ValueError("Inconsistent assumptions") | |
| def extract_predargs(proposition, assumptions=None, context=None): | |
| """ | |
| 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)} | |
| """ | |
| req_keys = find_symbols(proposition) | |
| keys = proposition.all_predicates() | |
| # XXX: We need this since True/False are not Basic | |
| lkeys = set() | |
| if assumptions: | |
| lkeys |= assumptions.all_predicates() | |
| if context: | |
| lkeys |= context.all_predicates() | |
| lkeys = lkeys - {S.true, S.false} | |
| tmp_keys = None | |
| while tmp_keys != set(): | |
| tmp = set() | |
| for l in lkeys: | |
| syms = find_symbols(l) | |
| if (syms & req_keys) != set(): | |
| tmp |= syms | |
| tmp_keys = tmp - req_keys | |
| req_keys |= tmp_keys | |
| keys |= {l for l in lkeys if find_symbols(l) & req_keys != set()} | |
| exprs = set() | |
| for key in keys: | |
| if isinstance(key, AppliedPredicate): | |
| exprs |= set(key.arguments) | |
| else: | |
| exprs.add(key) | |
| return exprs | |
| def find_symbols(pred): | |
| """ | |
| Find every :obj:`~.Symbol` in *pred*. | |
| Parameters | |
| ========== | |
| pred : sympy.assumptions.cnf.CNF, or any Expr. | |
| """ | |
| if isinstance(pred, CNF): | |
| symbols = set() | |
| for a in pred.all_predicates(): | |
| symbols |= find_symbols(a) | |
| return symbols | |
| return pred.atoms(Symbol) | |
| def get_relevant_clsfacts(exprs, relevant_facts=None): | |
| """ | |
| 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() | |
| """ | |
| if not relevant_facts: | |
| relevant_facts = CNF() | |
| newexprs = set() | |
| for expr in exprs: | |
| for fact in class_fact_registry(expr): | |
| newfact = CNF.to_CNF(fact) | |
| relevant_facts = relevant_facts._and(newfact) | |
| for key in newfact.all_predicates(): | |
| if isinstance(key, AppliedPredicate): | |
| newexprs |= set(key.arguments) | |
| return newexprs - exprs, relevant_facts | |
| def get_all_relevant_facts(proposition, assumptions, context, | |
| use_known_facts=True, iterations=oo): | |
| """ | |
| 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> | |
| """ | |
| # The relevant facts might introduce new keys, e.g., Q.zero(x*y) will | |
| # introduce the keys Q.zero(x) and Q.zero(y), so we need to run it until | |
| # we stop getting new things. Hopefully this strategy won't lead to an | |
| # infinite loop in the future. | |
| i = 0 | |
| relevant_facts = CNF() | |
| all_exprs = set() | |
| while True: | |
| if i == 0: | |
| exprs = extract_predargs(proposition, assumptions, context) | |
| all_exprs |= exprs | |
| exprs, relevant_facts = get_relevant_clsfacts(exprs, relevant_facts) | |
| i += 1 | |
| if i >= iterations: | |
| break | |
| if not exprs: | |
| break | |
| if use_known_facts: | |
| known_facts_CNF = CNF() | |
| if any(expr.kind == MatrixKind(NumberKind) for expr in all_exprs): | |
| known_facts_CNF.add_clauses(get_all_known_matrix_facts()) | |
| # check for undefinedKind since kind system isn't fully implemented | |
| if any(((expr.kind == NumberKind) or (expr.kind == UndefinedKind)) for expr in all_exprs): | |
| known_facts_CNF.add_clauses(get_all_known_number_facts()) | |
| kf_encoded = EncodedCNF() | |
| kf_encoded.from_cnf(known_facts_CNF) | |
| def translate_literal(lit, delta): | |
| if lit > 0: | |
| return lit + delta | |
| else: | |
| return lit - delta | |
| def translate_data(data, delta): | |
| return [{translate_literal(i, delta) for i in clause} for clause in data] | |
| data = [] | |
| symbols = [] | |
| n_lit = len(kf_encoded.symbols) | |
| for i, expr in enumerate(all_exprs): | |
| symbols += [pred(expr) for pred in kf_encoded.symbols] | |
| data += translate_data(kf_encoded.data, i * n_lit) | |
| encoding = dict(list(zip(symbols, range(1, len(symbols)+1)))) | |
| ctx = EncodedCNF(data, encoding) | |
| else: | |
| ctx = EncodedCNF() | |
| ctx.add_from_cnf(relevant_facts) | |
| return ctx | |
Xet Storage Details
- Size:
- 11.7 kB
- Xet hash:
- a8c0c9acfde1d50cace0b02b397140e98391bc3b27d5db613d52d01d7e9233f3
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.