Assumptions#

A module to implement logical predicates and assumption system.

Predicate#

class sympy.assumptions.assume.Predicate(*args, **kwargs)[source]

Base class for mathematical predicates. It also serves as a constructor for undefined predicate objects.

Explanation

Predicate is a function that returns a boolean value [1].

Predicate function is object, and it is instance of predicate class. When a predicate is applied to arguments, AppliedPredicate instance is returned. This merely wraps the argument and remain unevaluated. To obtain the truth value of applied predicate, use the function ask.

Evaluation of predicate is done by multiple dispatching. You can register new handler to the predicate to support new types.

Every predicate in SymPy can be accessed via the property of Q. For example, Q.even returns the predicate which checks if the argument is even number.

To define a predicate which can be evaluated, you must subclass this class, make an instance of it, and register it to Q. After then, dispatch the handler by argument types.

If you directly construct predicate using this class, you will get UndefinedPredicate which cannot be dispatched. This is useful when you are building boolean expressions which do not need to be evaluated.

Examples

Applying and evaluating to boolean value:

>>> from sympy import Q, ask
>>> ask(Q.prime(7))
True

You can define a new predicate by subclassing and dispatching. Here, we define a predicate for sexy primes [2] as an example.

>>> from sympy import Predicate, Integer
>>> class SexyPrimePredicate(Predicate):
...     name = "sexyprime"
>>> Q.sexyprime = SexyPrimePredicate()
>>> @Q.sexyprime.register(Integer, Integer)
... def _(int1, int2, assumptions):
...     args = sorted([int1, int2])
...     if not all(ask(Q.prime(a), assumptions) for a in args):
...         return False
...     return args[1] - args[0] == 6
>>> ask(Q.sexyprime(5, 11))
True

Direct constructing returns UndefinedPredicate, which can be applied but cannot be dispatched.

>>> from sympy import Predicate, Integer
>>> Q.P = Predicate("P")
>>> type(Q.P)
<class 'sympy.assumptions.assume.UndefinedPredicate'>
>>> Q.P(1)
Q.P(1)
>>> Q.P.register(Integer)(lambda expr, assump: True)
Traceback (most recent call last):
  ...
TypeError: <class 'sympy.assumptions.assume.UndefinedPredicate'> cannot be dispatched.

References

eval(args, assumptions=True)[source]

Evaluate self(*args) under the given assumptions.

This uses only direct resolution methods, not logical inference.

handler = <dispatched AskPredicateHandler>
classmethod register(*types, **kwargs)[source]

Register the signature to the handler.

classmethod register_many(*types, **kwargs)[source]

Register multiple signatures to same handler.

class sympy.assumptions.assume.AppliedPredicate(predicate, *args)[source]

The class of expressions resulting from applying Predicate to the arguments. AppliedPredicate merely wraps its argument and remain unevaluated. To evaluate it, use the ask() function.

Examples

>>> from sympy import Q, ask
>>> Q.integer(1)
Q.integer(1)

The function attribute returns the predicate, and the arguments attribute returns the tuple of arguments.

>>> type(Q.integer(1))
<class 'sympy.assumptions.assume.AppliedPredicate'>
>>> Q.integer(1).function
Q.integer
>>> Q.integer(1).arguments
(1,)

Applied predicates can be evaluated to a boolean value with ask:

>>> ask(Q.integer(1))
True
property arg

Return the expression used by this assumption.

Examples

>>> from sympy import Q, Symbol
>>> x = Symbol('x')
>>> a = Q.integer(x + 1)
>>> a.arg
x + 1
property arguments

Return the arguments which are applied to the predicate.

property function

Return the predicate.

Querying#

Queries are used to ask information about expressions. Main method for this is ask():

sympy.assumptions.ask.ask(proposition, assumptions=True, context={})[source]

Function to evaluate the proposition with assumptions.

Parameters:

proposition : Boolean

Proposition which will be evaluated to boolean value. If this is not AppliedPredicate, it will be wrapped by Q.is_true.

assumptions : Boolean, 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.

Returns:

True, False, or None

Raises:

TypeError : proposition or assumptions is not valid logical expression.

ValueError : assumptions are inconsistent.

Explanation

This function evaluates the proposition to True or False if the truth value can be determined. If not, it returns None.

It should be discerned from refine() which, when applied to a proposition, simplifies the argument to symbolic Boolean instead of Python built-in True, False or None.

Syntax

  • ask(proposition)

    Evaluate the proposition in global assumption context.

  • ask(proposition, assumptions)

    Evaluate the proposition with respect to assumptions in global assumption context.

Examples

>>> from sympy import ask, Q, pi
>>> from sympy.abc import x, y
>>> ask(Q.rational(pi))
False
>>> ask(Q.even(x*y), Q.even(x) & Q.integer(y))
True
>>> ask(Q.prime(4*x), Q.integer(x))
False

If the truth value cannot be determined, None will be returned.

>>> print(ask(Q.odd(3*x))) # cannot determine unless we know x
None

ValueError is raised if assumptions are inconsistent.

>>> ask(Q.integer(x), Q.even(x) & Q.odd(x))
Traceback (most recent call last):
  ...
ValueError: inconsistent assumptions Q.even(x) & Q.odd(x)

Notes

Relations in assumptions are not implemented (yet), so the following will not give a meaningful result.

>>> ask(Q.positive(x), x > 0)

It is however a work in progress.

See also

sympy.assumptions.refine.refine

Simplification using assumptions. Proposition is not reduced to None if the truth value cannot be determined.

ask’s optional second argument should be a boolean expression involving assumptions about objects in expr. Valid values include:

  • Q.integer(x)

  • Q.positive(x)

  • Q.integer(x) & Q.positive(x)

  • etc.

Q is an object holding known predicates.

See documentation for the logic module for a complete list of valid boolean expressions.

You can also define a context so you don’t have to pass that argument each time to function ask(). This is done by using the assuming context manager from module sympy.assumptions.

>>> from sympy import *
>>> x = Symbol('x')
>>> y = Symbol('y')
>>> facts = Q.positive(x), Q.positive(y)
>>> with assuming(*facts):
...     print(ask(Q.positive(2*x + y)))
True

Contents#

Performance improvements#

On queries that involve symbolic coefficients, logical inference is used. Work on improving satisfiable function (sympy.logic.inference.satisfiable) should result in notable speed improvements.

Logic inference used in one ask could be used to speed up further queries, and current system does not take advantage of this. For example, a truth maintenance system (https://en.wikipedia.org/wiki/Truth_maintenance_system) could be implemented.

Misc#

You can find more examples in the form of tests in the directory sympy/assumptions/tests/