[PATCH 0/4] Query system

12 views
Skip to first unread message

Fabian Pedregosa

unread,
Jul 21, 2009, 4:02:07 PM7/21/09
to sympy-...@googlegroups.com
In this series of 4 patches, I implement a new query system.

You can also pull from my repo, branch master:

git pull http://fseoane.net/git/sympy.git master


Fabian Pedregosa

unread,
Jul 21, 2009, 4:02:08 PM7/21/09
to sympy-...@googlegroups.com, Fabian Pedregosa
It used to return True with subinstances of Basic that had no
arguments. See test added for a test case of the bug.

I also squashed together two test cases that had the same name
(and thus probably only one was getting run)
---
sympy/core/basic.py | 8 +++++---
sympy/core/tests/test_basic.py | 23 +++++++++++------------
2 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/sympy/core/basic.py b/sympy/core/basic.py
index b20ed06..35d39c4 100644
--- a/sympy/core/basic.py
+++ b/sympy/core/basic.py
@@ -822,11 +822,13 @@ def is_number(self):
True

"""
+ result = False
for obj in self.iter_basic_args():
- if not obj.is_number:
+ if obj.is_number:
+ result = True
+ else:
return False
- else:
- return True
+ return result

@property
def func(self):
diff --git a/sympy/core/tests/test_basic.py b/sympy/core/tests/test_basic.py
index 7c51702..238f144 100644
--- a/sympy/core/tests/test_basic.py
+++ b/sympy/core/tests/test_basic.py
@@ -325,13 +325,6 @@ def test_doit():

assert (2*Integral(x, x)).doit() == x**2

-def test_is_number():
- assert Rational(8).is_number
- assert not x.is_number
- assert (8+log(2)).is_number
- assert not (8+log(2)+x).is_number
- assert (1+x**2/x-x).is_number
-
def test_attribute_error():
raises(AttributeError, "x.cos()")
raises(AttributeError, "x.sin()")
@@ -525,19 +518,25 @@ def test_is_number():
assert Real(3.14).is_number == True
assert Integer(737).is_number == True
assert Rational(3, 2).is_number == True
-
+ assert Rational(8).is_number == True
assert x.is_number == False
assert (2*x).is_number == False
-
assert (x + y).is_number == False
-
assert log(2).is_number == True
assert log(x).is_number == False
-
assert (2 + log(2)).is_number == True
+ assert (8+log(2)).is_number == True
assert (2 + log(x)).is_number == False
-
+ assert (8+log(2)+x).is_number == False
assert (2*g).is_number == False
+ assert (1+x**2/x-x).is_number == True
+
+ # test extensibility of .is_number
+ # on subinstances of Basic
+ class A(Basic):
+ pass
+ a = A()
+ assert a.is_number == False


# TODO write more tests for as_coeff_factors
--
1.6.2.2

Fabian Pedregosa

unread,
Jul 21, 2009, 4:02:09 PM7/21/09
to sympy-...@googlegroups.com, Fabian Pedregosa
This is now independent from objects and out of the core. Assume is
the basic object is this new model, and it is only a container
(all logic is done by sympy.logic and sympy.queries).
---
sympy/__init__.py | 2 +-
sympy/assumptions/__init__.py | 2 +
sympy/assumptions/assume.py | 97 +++++++++++++++++++++++++
sympy/assumptions/tests/test_assumptions_2.py | 58 +++++++++++++++
sympy/printing/pretty/pretty.py | 3 +
5 files changed, 161 insertions(+), 1 deletions(-)
create mode 100644 sympy/assumptions/__init__.py
create mode 100644 sympy/assumptions/assume.py
create mode 100644 sympy/assumptions/tests/test_assumptions_2.py

diff --git a/sympy/__init__.py b/sympy/__init__.py
index 3be16a4..c813490 100644
--- a/sympy/__init__.py
+++ b/sympy/__init__.py
@@ -21,7 +21,7 @@ def __sympy_debug():

import symbol as stdlib_symbol
from sympy.core import *
-
+from assumptions import *
from polys import *
from series import *
from functions import *
diff --git a/sympy/assumptions/__init__.py b/sympy/assumptions/__init__.py
new file mode 100644
index 0000000..bdd47c2
--- /dev/null
+++ b/sympy/assumptions/__init__.py
@@ -0,0 +1,2 @@
+from assume import Assume, register_global_assumptions, list_global_assumptions, \
+ remove_global_assumptions, clean_global_assumptions
diff --git a/sympy/assumptions/assume.py b/sympy/assumptions/assume.py
new file mode 100644
index 0000000..4069ee9
--- /dev/null
+++ b/sympy/assumptions/assume.py
@@ -0,0 +1,97 @@
+# doctests are disabled because of issue #1521
+from sympy.core import Basic, Symbol
+from sympy.core.relational import Relational
+
+__global_assumptions = []
+
+def register_global_assumptions(*assump):
+ """Register an assumption as global
+
+ Examples:
+# >>> from sympy import *
+# >>> list_global()
+# []
+# >>> x = Symbol('x')
+# >>> register_global(Assume(x, real=True))
+# True
+# >>> list_global()
+# [Assume(x, real=True)]
+
+ You can undo this calling remove_global
+ """
+ __global_assumptions.extend(assump)
+
+def list_global_assumptions():
+ """List all global assumptions"""
+ return __global_assumptions[:] # make a copy
+
+def remove_global_assumptions(*assump):
+ """Remove a global assumption. If argument is not
+ a global assumption, it will raise ValueError
+ """
+ for assumption in assump:
+ __global_assumptions.remove(assumption)
+
+def clean_global_assumptions():
+ """Remove all global assumptions"""
+ global __global_assumptions
+ __global_assumptions = []
+
+class Assume(Basic):
+ """New-style assumptions
+
+# >>> from sympy import Symbol, Assume
+# >>> x = Symbol('x')
+# >>> Assume(x, integer=True)
+# Assume( x, integer = True )
+# >>> Assume(x, integer=False)
+# Assume( x, integer = False )
+# >>> Assume( x > 1 )
+# Assume( x > 1, relational = True)
+ """
+
+ def __init__(self, expr, *args, **kwargs):
+ if isinstance(expr, Symbol):
+ key, value = kwargs.popitem()
+ elif isinstance(expr, Relational):
+ key, value = 'relational', True
+ if kwargs:
+ raise ValueError('Wrong set of arguments')
+ self._args = (expr, key, value)
+
+ is_Atom = True # do not attempt to decompose this
+
+ @property
+ def expr(self):
+ return self._args[0]
+
+ @property
+ def key(self):
+ return self._args[1]
+
+ @property
+ def value(self):
+ return self._args[2]
+
+ def __eq__(self, other):
+ if type(other) == Assume:
+ return self._args == other._args
+ return False
+
+def eliminate_assume(expr, symbol=None):
+ """
+ Will convert an expression with assumptions to an equivalent with all assumptions
+ replaced by symbols
+ Assume(x, integer=True) --> integer
+ Assume(x, integer=False) --> ~integer
+ """
+ if type(expr) == Assume:
+ if symbol is not None:
+ if not expr.expr.has(symbol): return
+ if expr.value: return Symbol(expr.key)
+ return ~Symbol(expr.key)
+ args = []
+ for a in expr.args:
+ args.append(eliminate_assume(a))
+ return type(expr)(*args)
+
diff --git a/sympy/assumptions/tests/test_assumptions_2.py b/sympy/assumptions/tests/test_assumptions_2.py
new file mode 100644
index 0000000..d95162f
--- /dev/null
+++ b/sympy/assumptions/tests/test_assumptions_2.py
@@ -0,0 +1,58 @@
+"""rename this to test_assumptions.py when the old assumptions system is deleted"""
+from sympy.core import symbols
+from sympy.assumptions import Assume, register_global_assumptions, \
+ list_global_assumptions, remove_global_assumptions, clean_global_assumptions
+from sympy.assumptions.assume import eliminate_assume
+from sympy.printing import pretty
+
+def test_assume():
+ x = symbols('x')
+ assump = Assume(x, integer=True)
+ assert assump.expr == x
+ assert assump.key == 'integer'
+ assert assump.value == True
+
+def test_False():
+ """Test Assume object with False keys"""
+ x = symbols('x')
+ assump = Assume(x, integer=False)
+ assert assump.expr == x
+ assert assump.key == 'integer'
+ assert assump.value == False
+
+def test_equal():
+ """Test for equality"""
+ x = symbols('x')
+ assert Assume(x, positive=True) == Assume(x, positive=True)
+ assert Assume(x, positive=True) != Assume(x, positive=False)
+ assert Assume(x, positive=False) == Assume(x, positive=False)
+
+def test_pretty():
+ x = symbols('x')
+ assert pretty(Assume(x, positive=True)) == 'Assume(x, positive=True)'
+
+def test_eliminate_assumptions():
+ a, b, x, y = symbols('abxy')
+ assert eliminate_assume(Assume(x, a=True)) == a
+ assert eliminate_assume(Assume(x, a=True), symbol=x) == a
+ assert eliminate_assume(Assume(x, a=True), symbol=y) == None
+ assert eliminate_assume(Assume(x, a=False)) == ~a
+ assert eliminate_assume(Assume(x, a=False), symbol=y) == None
+ assert eliminate_assume(Assume(x, a=True) | Assume(x, b=True)) == a | b
+ assert eliminate_assume(Assume(x, a=True) | Assume(x, b=False)) == a | ~b
+
+def test_global():
+ """Test for global assumptions"""
+ x, y = symbols('x y')
+ register_global_assumptions(Assume(x>0))
+ assert Assume(x>0) in list_global_assumptions()
+ remove_global_assumptions(Assume(x>0))
+ assert (Assume(x>0) in list_global_assumptions()) == False
+
+ # same with multiple of assumptions
+ register_global_assumptions(Assume(x>0), Assume(y>0))
+ assert Assume(x>0) in list_global_assumptions()
+ assert Assume(y>0) in list_global_assumptions()
+ clean_global_assumptions()
+ assert (Assume(x>0) in list_global_assumptions()) == False
+ assert (Assume(y>0) in list_global_assumptions()) == False
diff --git a/sympy/printing/pretty/pretty.py b/sympy/printing/pretty/pretty.py
index 19ffff2..6d7f4da 100644
--- a/sympy/printing/pretty/pretty.py
+++ b/sympy/printing/pretty/pretty.py
@@ -56,6 +56,9 @@ def _print_Atom(self, e):
except KeyError:
return self.emptyPrinter(e)

+ def _print_Assume(self, e):
+ return prettyForm("Assume(%s, %s=%s)" % (e.expr, e.key, e.value))
+
# Infinity inherits from Rational, so we have to override _print_XXX order
_print_Infinity = _print_Atom
_print_NegativeInfinity = _print_Atom
--
1.6.2.2

Fabian Pedregosa

unread,
Jul 21, 2009, 4:02:10 PM7/21/09
to sympy-...@googlegroups.com, Fabian Pedregosa
The old query system (.is_* properties) has some limitations:

1. Can't assume relations. It is not possible to specify relations between different
objects. For example, you can assume that x>0 and y>0, but you can't
assume x>y. You also can't assume facts on expressions, only on symbols.

2. Verbose code splitted across multiple classes. Each class must override
query methods (.is_*).

3. Extensibility. To add new assumptions you have to add code to
the core

The assumption system implemented in this series of patches relies on these
principles:

1. Assumptions are separate from objects. Assumptions are instances of Assume, which is
a class that holds a reference to the expression and to the 'key' (what it assumes)

2. Queries out of the core. No more .is_* methods. Specific queries are implemented
as subclasses of QueryHandler, and the query function calls the appropriate
subclass of QueryHandler

query -> QueryHandler -> QueryNegativeHandler
-> QueryIntegerHandler
-> QueryBoundedHandler
...
That way, creating new queries is a matter of subclassing QueryHandler and override
the apropriate methods.

3. Extensibility. This system can be extended with new keys and new types. See last tests
for examples on this.
---
sympy/__init__.py | 1 +
sympy/queries/__init__.py | 162 ++++++
sympy/queries/handlers/__init__.py | 40 ++
sympy/queries/handlers/calculus.py | 145 ++++++
sympy/queries/handlers/ntheory.py | 207 ++++++++
sympy/queries/handlers/order.py | 173 +++++++
sympy/queries/handlers/sets.py | 433 ++++++++++++++++
sympy/queries/tests/test_query.py | 979 ++++++++++++++++++++++++++++++++++++
8 files changed, 2140 insertions(+), 0 deletions(-)
create mode 100644 sympy/queries/__init__.py
create mode 100644 sympy/queries/handlers/__init__.py
create mode 100644 sympy/queries/handlers/calculus.py
create mode 100644 sympy/queries/handlers/ntheory.py
create mode 100644 sympy/queries/handlers/order.py
create mode 100644 sympy/queries/handlers/sets.py
create mode 100644 sympy/queries/tests/test_query.py

diff --git a/sympy/__init__.py b/sympy/__init__.py
index c813490..fbec483 100644
--- a/sympy/__init__.py
+++ b/sympy/__init__.py
@@ -40,6 +40,7 @@ def __sympy_debug():
pprint_try_use_unicode, print_gtk, print_tree
from printing import ccode, latex, preview, view, pngview, pdfview, dviview
from printing import python, print_python, srepr, sstr, sstrrepr
+from queries import query

evalf._create_evalf_table()

diff --git a/sympy/queries/__init__.py b/sympy/queries/__init__.py
new file mode 100644
index 0000000..49ee205
--- /dev/null
+++ b/sympy/queries/__init__.py
@@ -0,0 +1,162 @@
+import inspect
+from sympy.core import Symbol, sympify
+from sympy.utilities.source import get_class
+from sympy.assumptions import list_global_assumptions
+from sympy.assumptions.assume import eliminate_assume
+from sympy.logic.boolalg import to_cnf, conjuncts, \
+ compile_rule, Equivalent, And
+from sympy.logic.algorithms.dpll import dpll_satisfiable
+
+def query(expr, *args, **kwargs):
+ """
+ Method for inferring properties about objects.
+
+ Syntax
+
+ * query(expression, key=boolean)
+
+ * query(expression, key=boolean, assumptions=assumptions)
+
+ where expression is any SymPy expression, and boolean is any
+ boolean value (True/False). key can have any value listed in
+ handlers_dict.keys()
+
+ It accepts an optional keyword assumptions, a boolean expression
+ containing assumptions satisfied by expr.
+
+ Examples
+ >>> from sympy import *


+ >>> x, y = symbols('x y')

+ >>> query(pi, rational=True)
+ False
+ >>> query(x*y, even=True, assumptions=Assume(x, even=True) & Assume(y, integer=True))
+ True
+ >>> query(x*y, prime=True, assumptions=Assume(x, integer=True) & Assume(y, integer=True))
+ False
+
+ Remarks
+ Relations in assumptions are not implemented (yet), so the following
+ will not give a meaningful result.
+ #>>> query(x, positive=True, Assume(x>0))
+ It is however a work in progress and should be available before
+ the official release
+ """
+ assumptions = kwargs.pop('assumptions', [])
+ if assumptions and not hasattr(assumptions, '__iter__'):
+ assumptions = conjuncts(to_cnf(assumptions))
+ # Warning: global assumptions are expected to be in CNF
+ assumptions.extend(list_global_assumptions())
+


+ key, value = kwargs.popitem()

+ expr = sympify(expr)
+ if kwargs:
+ # split multiple queries
+ k = {key: value}
+ return query(expr, assumptions=assumptions, **k) and \
+ query(expr, assumptions=assumptions, **kwargs)
+ if not value: # only True queries from now on (e.g. prime=True)
+ k = {key: True}
+ result = query(expr, assumptions=assumptions, **k)
+ if result is not None:
+ return not result
+ return
+
+ # direct resolution method, no logic
+ resolutors = []
+ for handler in handlers_dict[key]:
+ resolutors.append( get_class(handler) )
+ res, _res = None, None
+ mro = inspect.getmro(type(expr))
+ for handler in resolutors:
+ for subclass in mro:
+ if hasattr(handler, subclass.__name__):
+ res = getattr(handler, subclass.__name__)(expr, assumptions)
+ if _res is None: _res = res
+ elif _res != res: raise ValueError, 'incompatible resolutors'
+ break
+ if res is not None:
+ return res
+
+ # use logic inference
+ if not expr.is_Atom: return
+ clauses = []
+ for k, values in known_facts_dict.iteritems():
+ for v in values:
+ clauses.append(Equivalent(compile_rule(k), compile_rule(v)))
+ result = None
+
+ # add assumptions to the knowledge base
+ for assump in assumptions:
+ clauses.append(eliminate_assume(assump, symbol=expr))
+
+ clauses.append(Symbol(key))
+ # TODO: call dpll and avoid creating this object
+ if not dpll_satisfiable(And(*clauses)):
+ return False
+ clauses[-1] = ~clauses[-1]
+ if not dpll_satisfiable(And(*clauses)):
+ # if the negation is satisfiable, it is entailed
+ return True
+ clauses.pop(-1)
+
+
+def register_handler(key, handler):
+ """Register a handler in the query system. key must be a string and handler a
+ class inheriting from QueryHandler.
+
+ >>> from sympy.queries.handlers import QueryHandler
+ >>> class MersenneHandler(QueryHandler):
+ ... # Mersenne numbers are in the form 2**n + 1, n integer
+ ... @staticmethod
+ ... def Integer(expr, assumptions):
+ ... import math
+ ... return query(math.log(expr + 1, 2), integer=True)
+ >>> register_handler('mersenne', MersenneHandler)
+ >>> query(7, mersenne=True)
+ True
+ """
+ if key in handlers_dict:
+ handlers_dict[key].append(handler)
+ else:
+ handlers_dict.update({key: [handler]})
+
+def remove_handler(key, handler):
+ """Removes a handler from the query system. Same syntax as register_handler"""
+ handlers_dict[key].remove(handler)
+
+# query_dict tells us what query handler we should use
+# for a particular key
+handlers_dict = {
+ 'bounded' : ['sympy.queries.handlers.calculus.QueryBoundedHandler'],
+ 'commutative' : ['sympy.queries.handlers.QueryCommutativeHandler'],
+ 'complex' : ['sympy.queries.handlers.sets.QueryComplexHandler'],
+ 'composite' : ['sympy.queries.handlers.ntheory.QueryCompositeHandler'],
+ 'even' : ['sympy.queries.handlers.ntheory.QueryEvenHandler'],
+ 'extended_real' : ['sympy.queries.handlers.sets.QueryExtendedRealHandler'],
+ 'imaginary' : ['sympy.queries.handlers.sets.QueryImaginaryHandler'],
+ 'infinitesimal' : ['sympy.queries.handlers.calculus.QueryInfinitesimalHandler'],
+ 'integer' : ['sympy.queries.handlers.sets.QueryIntegerHandler'],
+ 'irrational' : ['sympy.queries.handlers.sets.QueryIrrationalHandler'],
+ 'rational' : ['sympy.queries.handlers.sets.QueryRationalHandler'],
+ 'negative' : ['sympy.queries.handlers.order.QueryNegativeHandler'],
+ 'positive' : ['sympy.queries.handlers.order.QueryPositiveHandler'],
+ 'prime' : ['sympy.queries.handlers.ntheory.QueryPrimeHandler'],
+ 'real' : ['sympy.queries.handlers.sets.QueryRealHandler'],
+ 'odd' : ['sympy.queries.handlers.ntheory.QueryOddHandler'],
+ 'zero' : ['sympy.queries.handlers.order.QueryZeroHandler']
+}
+
+known_facts_dict = {
+ 'complex' : ['real | complex_number_re_0'],
+ 'even' : ['integer & ~odd'],
+ 'extended_real' : ['real | infinity'],
+ 'odd' : ['integer & ~even'],
+ 'prime' : ['integer & positive & ~composite'],
+ 'integer' : ['rational & denominator_one'],
+ 'imaginary' : ['complex & ~real'],
+ 'negative' : ['real & ~positive & ~zero'],
+ 'positive' : ['real & ~negative & ~zero'],
+ 'rational' : ['real & ~irrational'],
+ 'real' : ['rational | irrational' ],
+ 'zero' : ['real & ~positive & ~negative']
+}
diff --git a/sympy/queries/handlers/__init__.py b/sympy/queries/handlers/__init__.py
new file mode 100644
index 0000000..ba9bb89
--- /dev/null
+++ b/sympy/queries/handlers/__init__.py
@@ -0,0 +1,40 @@
+from sympy.queries import query
+
+class QueryHandler(object):
+ """Base class that all Query Handlers must inherit"""
+ pass
+
+class CommonHandler(QueryHandler):
+ """Defines some useful methods common to most Handlers """
+
+ @staticmethod
+ def NaN(expr, assumptions):
+ return False
+
+class QueryCommutativeHandler(CommonHandler):
+ """
+ Handler for key 'commutative'
+ """
+
+ @staticmethod
+ def Symbol(expr, assumptions):
+ """Objects are expected to be commutative unless otherwise stated"""
+ for assump in assumptions:
+ if assump.expr == expr and assump.key == 'commutative':
+ return assump.value
+ return True
+
+ @staticmethod
+ def Basic(expr, assumptions):
+ for arg in expr.args:
+ if not query(arg, commutative=True, assumptions=assumptions):
+ return False
+ return True
+
+ @staticmethod
+ def Number(expr, assumptions):
+ return True
+
+ @staticmethod
+ def NaN(expr, assumptions):
+ return True
diff --git a/sympy/queries/handlers/calculus.py b/sympy/queries/handlers/calculus.py
new file mode 100644
index 0000000..4885aee
--- /dev/null
+++ b/sympy/queries/handlers/calculus.py
@@ -0,0 +1,145 @@
+"""
+This module contains query handlers resposible for calculus queries:
+infinitesimal, bounded, etc.
+"""
+from sympy.queries import query
+from sympy.queries.handlers import CommonHandler
+
+class QueryInfinitesimalHandler(CommonHandler):
+ """
+ Handler for key 'infinitesimal'
+ Test that a given expression is equivalent to an infinitesimal
+ number
+ """
+
+ @staticmethod
+ def _number(expr, assumptions):
+ # helper method
+ return expr.evalf() == 0
+
+ @staticmethod
+ def Basic(expr, assumptions):
+ if expr.is_number:
+ return QueryInfinitesimalHandler._number(expr, assumptions)
+
+ @staticmethod
+ def Mul(expr, assumptions):
+ """
+ Infinitesimal*Bounded -> Infinitesimal
+ """
+ if expr.is_number:
+ return QueryInfinitesimalHandler._number(expr, assumptions)
+ result = False
+ for arg in expr.args:
+ if query(arg, infinitesimal=True, assumptions=assumptions):
+ result = True
+ elif query(arg, bounded=True, assumptions=assumptions):
+ continue
+ else: break
+ else:
+ return result
+
+ Add, Pow = Mul, Mul
+
+ @staticmethod
+ def Number(expr, assumptions):
+ return expr == 0
+
+ NumberSymbol = Number
+
+ @staticmethod
+ def ImaginaryUnit(expr, assumptions):
+ return False
+
+
+class QueryBoundedHandler(CommonHandler):
+ """
+ Handler for key 'bounded'
+ Test that an expression is bounded respect to all its variables
+ """
+
+ @staticmethod
+ def Add(expr, assumptions):
+ """
+ Bounded + Bounded -> Bounded
+ Unbounded + Bounded -> Unbounded
+ Unbounded + Unbounded -> ?
+ """
+ result = True
+ for arg in expr.args:
+ _bounded = query(arg, bounded=True, assumptions=assumptions)
+ if _bounded: continue
+ elif _bounded is None: return
+ elif _bounded is False:
+ if result: result = False
+ else: return
+ return result
+
+ Mul = Add
+
+ @staticmethod
+ def Pow(expr, assumptions):
+ """
+ Unbounded ** Whatever -> Unbounded
+ Bounded ** Unbounded -> Unbounded if base > 1
+ Bounded ** Unbounded -> Unbounded if base < 1
+ """
+ base_bounded = query(expr.base, bounded=True, assumptions=assumptions)
+ if not base_bounded: return base_bounded
+ if query(expr.exp, bounded=True, assumptions=assumptions) \
+ and base_bounded: return True
+ if base_bounded and expr.base.is_number:
+ # We need to implement relations for this
+ if abs(expr.base) > 1:
+ return False
+ return True
+
+ @staticmethod
+ def Symbol(expr, assumptions):
+ if query(expr, zero=True, assumptions=assumptions):
+ return True
+ for assump in assumptions:
+ if assump.key == 'bounded' and assump.expr == expr:
+ return assump.value
+ return False
+
+ @staticmethod
+ def log(expr, assumptions):
+ return query(expr.args[0], bounded=True, assumptions=assumptions)
+
+ exp = log
+
+ @staticmethod
+ def sin(expr, assumptions):
+ return True
+
+ cos = sin
+
+ @staticmethod
+ def Number(expr, assumptions):
+ return True
+
+ @staticmethod
+ def Infinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def NegativeInfinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def Pi(expr, assumptions):
+ return True
+
+ @staticmethod
+ def Exp1(expr, assumptions):
+ return True
+
+ @staticmethod
+ def ImaginaryUnit(expr, assumptions):
+ return True
+
+ @staticmethod
+ def sign(expr, assumptions):
+ return True
+
diff --git a/sympy/queries/handlers/ntheory.py b/sympy/queries/handlers/ntheory.py
new file mode 100644
index 0000000..196f2aa
--- /dev/null
+++ b/sympy/queries/handlers/ntheory.py
@@ -0,0 +1,207 @@
+"""
+Handlers for keys related to number theory: prime, even, odd, etc.
+"""
+from sympy.queries import query
+from sympy.queries.handlers import CommonHandler
+from sympy.ntheory import isprime
+
+class QueryPrimeHandler(CommonHandler):
+ """
+ Handler for key 'prime'
+ Test that an expression represents a prime number
+ """
+
+ @staticmethod
+ def _number(expr, assumptions):
+ # helper method
+ if (expr.as_real_imag()[1] == 0) and int(expr.evalf()) == expr:
+ return isprime(expr.evalf(1))
+ return False
+
+ @staticmethod
+ def Basic(expr, assumptions):
+ # Just use int(expr) once
+ # http://code.google.com/p/sympy/issues/detail?id=1462
+ # is solved
+ if expr.is_number:
+ return QueryPrimeHandler._number(expr, assumptions)
+
+ @staticmethod
+ def Mul(expr, assumptions):
+ if expr.is_number:
+ return QueryPrimeHandler._number(expr, assumptions)
+ for arg in expr.args:
+ if query(arg, integer=True, assumptions=assumptions):
+ pass
+ else: break
+ else:
+ # a product of integers can't be a prime
+ return False
+
+ @staticmethod
+ def Pow(expr, assumptions):
+ """
+ Integer**Integer -> !Prime
+ """
+ if expr.is_number:
+ return QueryPrimeHandler._number(expr, assumptions)
+ if query(expr.exp, integer=True, assumptions=assumptions) and \
+ query(expr.base, integer=True, assumptions=assumptions):
+ return False
+
+ @staticmethod
+ def Integer(expr, assumptions):
+ return isprime(expr)
+
+ @staticmethod
+ def Rational(expr, assumptions):
+ return False
+
+ @staticmethod
+ def Real(expr, assumptions):
+ return QueryPrimeHandler._number(expr, assumptions)
+
+ @staticmethod
+ def Infinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def NegativeInfinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def ImaginaryUnit(expr, assumptions):
+ return False
+
+ @staticmethod
+ def NumberSymbol(expr, assumptions):
+ return QueryPrimeHandler._number(expr, assumptions)
+
+class QueryCompositeHandler(CommonHandler):
+
+ @staticmethod
+ def Basic(expr, assumptions):
+ return query(expr, positive=True, integer=True, prime=False, \
+ assumptions=assumptions)
+
+class QueryEvenHandler(CommonHandler):
+
+ @staticmethod
+ def _number(expr, assumptions):
+ # helper method
+ if (expr.as_real_imag()[1] == 0) and expr.evalf(1) == expr:
+ return float(expr.evalf()) % 2 == 0
+ else: return False
+
+ @staticmethod
+ def Basic(expr, assumptions):
+ if expr.is_number:
+ return QueryEvenHandler._number(expr, assumptions)
+
+ @staticmethod
+ def Mul(expr, assumptions):
+ """
+ Even * Integer -> Even
+ Even * Odd -> Even
+ Integer * Odd -> ?
+ Odd * Odd -> Odd
+ """
+ if expr.is_number:
+ return QueryEvenHandler._number(expr, assumptions)
+ even, odd, irrational = False, 0, False
+ for arg in expr.args:
+ # check for all integers and at least one even
+ if query(arg, integer=True, assumptions=assumptions):
+ if query(arg, even=True, assumptions=assumptions):
+ even = True
+ elif query(arg, odd=True, assumptions=assumptions):
+ odd += 1
+ elif query(arg, irrational=True, assumptions=assumptions):
+ # one irrational makes the result False
+ # two makes it undefined
+ if irrational:
+ break
+ irrational = True
+ else: break
+ else:
+ if irrational: return False
+ if even: return True
+ if odd == len(expr.args): return False
+
+ @staticmethod
+ def Add(expr, assumptions):
+ """
+ Even + Odd -> Odd
+ Even + Even -> Even
+ Odd + Odd -> Even
+
+ TODO: remove float() when issue
+ http://code.google.com/p/sympy/issues/detail?id=1473
+ is solved
+ """
+ if expr.is_number:
+ return QueryEvenHandler._number(expr, assumptions)
+ _result = True
+ for arg in expr.args:
+ if query(arg, even=True, assumptions=assumptions):
+ pass
+ elif query(arg, odd=True, assumptions=assumptions):
+ _result = not _result
+ else: break
+ else:
+ return _result
+
+ @staticmethod
+ def Integer(expr, assumptions):
+ return expr % 2 == 0
+
+ @staticmethod
+ def Rational(expr, assumptions):
+ return False
+
+ @staticmethod
+ def Real(expr, assumptions):
+ return expr % 2 == 0
+
+ @staticmethod
+ def Infinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def NegativeInfinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def NumberSymbol(expr, assumptions):
+ return QueryEvenHandler._number(expr, assumptions)
+
+ @staticmethod
+ def ImaginaryUnit(expr, assumptions):
+ return False
+
+ @staticmethod
+ def abs(expr, assumptions):
+ if query(expr.args[0], real=True, assumptions=assumptions):
+ return query(expr.args[0], even=True, assumptions=assumptions)
+
+ @staticmethod
+ def re(expr, assumptions):
+ if query(expr.args[0], real=True, assumptions=assumptions):
+ return query(expr.args[0], even=True, assumptions=assumptions)
+
+ @staticmethod
+ def im(expr, assumptions):
+ if query(expr.args[0], real=True, assumptions=assumptions):
+ return True
+
+class QueryOddHandler(CommonHandler):
+ """
+ Handler for key 'odd'
+ Test that an expression represents an odd number
+ """
+
+ @staticmethod
+ def Basic(expr, assumptions):
+ return query(expr, integer=True, even=False, \
+ assumptions=assumptions)
+
diff --git a/sympy/queries/handlers/order.py b/sympy/queries/handlers/order.py
new file mode 100644
index 0000000..42d63d5
--- /dev/null
+++ b/sympy/queries/handlers/order.py
@@ -0,0 +1,173 @@
+"""
+QueryHandlers related to order relations: positive, negative, etc.
+"""
+from sympy.queries import query
+from sympy.queries.handlers import CommonHandler
+
+
+class QueryNegativeHandler(CommonHandler):
+ """
+ Handler for key 'negative'
+ Test that an expression is less (strict) than zero
+ """
+
+ @staticmethod
+ def _number(expr, assumptions):
+ if not expr.as_real_imag()[1]:
+ return expr.evalf() < 0
+ else: return False
+
+ @staticmethod
+ def Basic(expr, assumptions):
+ if expr.is_number:
+ return QueryNegativeHandler._number(expr, assumptions)
+
+ @staticmethod
+ def Add(expr, assumptions):
+ """
+ Positive + Positive -> Positive,
+ Negative + Negative -> Negative
+ """
+ if expr.is_number:
+ return QueryNegativeHandler._number(expr, assumptions)
+ for arg in expr.args:
+ if not query(arg, negative=True, assumptions=assumptions):
+ break
+ else:
+ # if all argument's are negative
+ return True
+
+ @staticmethod
+ def Mul(expr, assumptions):
+ if expr.is_number:
+ return QueryNegativeHandler._number(expr, assumptions)
+ result = False
+ for arg in expr.args:
+ _negative = query(arg, real=True, negative=True, assumptions=assumptions)
+ if _negative is None: return
+ result = result ^ _negative
+ return result
+
+ @staticmethod
+ def Pow(expr, assumptions):
+ if expr.is_number:
+ return QueryNegativeHandler._number(expr, assumptions)
+ if query(expr.base, negative=True, assumptions=assumptions):
+ if query(expr.exp, odd=True, assumptions=assumptions):
+ return True
+ if query(expr.exp, even=True, assumptions=assumptions):
+ return False
+ elif query(expr.base, positive=True, assumptions=assumptions):
+ if query(expr.exp, real=True, assumptions=assumptions):
+ return False
+
+ @staticmethod
+ def ImaginaryUnit(expr, assumptions):
+ return False
+
+ @staticmethod
+ def abs(expr, assumptions):
+ return False
+
+class QueryZeroHandler(CommonHandler):
+ """
+ Handler for key 'zero'
+ Test that an expression is not identically zero
+ """
+
+ @staticmethod
+ def Basic(expr, assumptions):
+ if expr.is_number:
+ # if there are no symbols just evalf
+ return expr.evalf() == 0
+
+ @staticmethod
+ def Add(expr, assumptions):
+ if all([query(x, positive=True, assumptions=assumptions) for x in expr.args]) \
+ or all([query(x, negative=True, assumptions=assumptions) for x in expr.args]):
+ return False
+
+ @staticmethod
+ def Mul(expr, assumptions):
+ for arg in expr.args:
+ result = query(arg, zero=True, assumptions=assumptions)
+ if result == True:
+ # one zero is enough
+ return True
+ elif result is None:
+ return None
+ else:
+ return False
+
+ @staticmethod
+ def Pow(expr, assumptions):
+ if query(expr.exp, zero=True, assumptions=assumptions) == False:
+ return query(expr.base, zero=True, assumptions=assumptions)
+
+ @staticmethod
+ def abs(expr, assumptions):
+ return query(expr.args[0], zero=True, assumptions=assumptions)
+
+class QueryPositiveHandler(CommonHandler):
+ """
+ Handler for key 'positive'
+ Test that an expression is greater (strict) than zero
+ """
+
+ @staticmethod
+ def _number(expr, assumptions):
+ if not expr.as_real_imag()[1]:
+ return expr.evalf() > 0
+ else: return False
+
+ @staticmethod
+ def Basic(expr, assumptions):
+ if expr.is_number:
+ return QueryPositiveHandler._number(expr, assumptions)
+
+ @staticmethod
+ def Mul(expr, assumptions):
+ if expr.is_number:
+ return QueryPositiveHandler._number(expr, assumptions)
+ result = True
+ for arg in expr.args:
+ if query(arg, positive=True, assumptions=assumptions): continue
+ elif query(arg, negative=True, assumptions=assumptions):
+ result = result ^ True
+ else: return
+ return result
+
+ @staticmethod
+ def Add(expr, assumptions):
+ if expr.is_number:
+ return QueryPositiveHandler._number(expr, assumptions)
+ for arg in expr.args:
+ if query(arg, positive=True, assumptions=assumptions) is not True:
+ break
+ else:
+ # if all argument's are positive
+ return True
+
+ @staticmethod
+ def Pow(expr, assumptions):
+ if expr.is_number: return expr.evalf() > 0
+ if query(expr.base, positive=True, assumptions=assumptions):
+ return True
+ if query(expr.base, negative=True, assumptions=assumptions):
+ if query(expr.exp, even=True, assumptions=assumptions):
+ return True
+ if query(expr.exp, even=True, assumptions=assumptions):
+ return False
+
+ @staticmethod
+ def exp(expr, assumptions):
+ if query(expr.args[0], real=True, assumptions=assumptions):
+ return True
+
+ @staticmethod
+ def ImaginaryUnit(expr, assumptions):
+ return False
+
+ @staticmethod
+ def abs(expr, assumptions):
+ return query(expr, zero=False, assumptions=assumptions)
diff --git a/sympy/queries/handlers/sets.py b/sympy/queries/handlers/sets.py
new file mode 100644
index 0000000..61971ce
--- /dev/null
+++ b/sympy/queries/handlers/sets.py
@@ -0,0 +1,433 @@
+"""
+Handlers for keys related to set membership: integer, rational, etc.
+"""
+from sympy.queries import query
+from sympy.queries.handlers import CommonHandler
+
+class QueryIntegerHandler(CommonHandler):
+ """
+ Handler for key 'integer'
+ Test that an expression belongs to the field of integer numbers
+ """
+
+ @staticmethod
+ def _number(expr, assumptions):
+ # helper method
+ if expr.as_real_imag()[1] == 0:
+ return expr.evalf(1) == expr
+ return False
+
+ @staticmethod
+ def Add(expr, assumptions):
+ """
+ Integer + Integer -> Integer
+ Integer + !Integer -> !Integer
+ !Integer + !Integer -> ?
+ """
+ if expr.is_number:
+ return QueryIntegerHandler._number(expr, assumptions)
+ return test_closed_group(expr, assumptions, 'integer')
+
+ @staticmethod
+ def Mul(expr, assumptions):
+ """
+ Integer*Integer -> Integer
+ Integer*Irrational -> !Integer
+ Odd/Even -> !Integer
+ Integer*Rational -> ?
+ """
+ if expr.is_number:
+ return QueryIntegerHandler._number(expr, assumptions)
+ _output = True
+ for arg in expr.args:
+ if not query(arg, integer=True, assumptions=assumptions):
+ if arg.is_Rational:
+ if arg.q == 2:
+ return query(2*expr, even=True, assumptions=assumptions)
+ if arg.q % 2 == 1:
+ if query(arg.q*expr, even=True, assumptions=assumptions):
+ # even / odd -> !integer
+ return False
+ else: break
+ elif query(arg, irrational=True, assumptions=assumptions):
+ if _output:
+ _output = False
+ else:
+ return
+ else:
+ return
+ else:
+ return _output
+
+ Pow = Add
+
+ @staticmethod
+ def int(expr, assumptions):
+ return True
+
+ @staticmethod
+ def Integer(expr, assumptions):
+ return True
+
+ @staticmethod
+ def Rational(expr, assumptions):
+ # rationals with denominator one get
+ # evaluated to Integers
+ return False
+
+ @staticmethod
+ def Real(expr, assumptions):
+ return int(expr) == expr
+
+ @staticmethod
+ def Pi(expr, assumptions):
+ return False
+
+ @staticmethod
+ def Exp1(expr, assumptions):
+ return False
+
+ @staticmethod
+ def Infinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def NegativeInfinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def ImaginaryUnit(expr, assumptions):
+ return False
+
+ @staticmethod
+ def abs(expr, assumptions):
+ return query(expr.args[0], integer=True, assumptions=assumptions)
+
+class QueryRationalHandler(CommonHandler):
+ """
+ Handler for key 'rational'
+ Test that an expression belongs to the field of rational numbers
+ """
+
+ @staticmethod
+ def Symbol(expr, assumptions):
+ if query(expr, zero=True, assumptions=assumptions):
+ # zero is a rational number
+ return True
+
+ @staticmethod
+ def Add(expr, assumptions):
+ """
+ Rational + Rational -> Rational
+ Rational + !Rational -> !Rational
+ !Rational + !Rational -> ?
+ """
+ if expr.is_number:
+ if expr.as_real_imag()[1]:
+ return False
+ return test_closed_group(expr, assumptions, 'rational')
+
+ Mul = Add
+
+ @staticmethod
+ def Pow(expr, assumptions):
+ """
+ Rational ** Integer -> Rational
+ Irrational ** Rational -> Irrational
+ Rational ** Irrational -> ?
+ """
+ if query(expr.exp, integer=True, assumptions=assumptions):
+ return query(expr.base, rational=True, assumptions=assumptions)
+ elif query(expr.exp, rational=True, assumptions=assumptions):
+ if query(expr.base, prime=True, assumptions=assumptions):
+ return False
+
+ @staticmethod
+ def Rational(expr, assumptions):
+ return True
+
+ @staticmethod
+ def Real(expr, assumptions):
+ # it's finite-precission
+ return True
+
+ @staticmethod
+ def ImaginaryUnit(expr, assumptions):
+ return False
+
+ @staticmethod
+ def Infinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def NegativeInfinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def Pi(expr, assumptions):
+ return False
+
+ @staticmethod
+ def Exp1(expr, assumptions):
+ return False
+
+class QueryIrrationalHandler(CommonHandler):
+
+ @staticmethod
+ def Basic(expr, assumptions):
+ return query(expr, real=True, rational=False, \
+ assumptions=assumptions)
+
+class QueryRealHandler(CommonHandler):
+ """
+ Handler for key 'real'
+ Test that an expression belongs to the field of real numbers
+ """
+
+ @staticmethod
+ def _number(expr, assumptions):
+ return not expr.as_real_imag()[1]
+
+ @staticmethod
+ def Add(expr, assumptions):
+ """
+ Real + Real -> Real
+ Real + (Complex & !Real) -> !Real
+ """
+ if expr.is_number:
+ return QueryRealHandler._number(expr, assumptions)
+ return test_closed_group(expr, assumptions, 'real')
+
+ @staticmethod
+ def Mul(expr, assumptions):
+ """
+ Real*Real -> Real
+ Real*Imaginary -> !Real
+ Imaginary*Imaginary -> Real
+ """
+ if expr.is_number:
+ return QueryRealHandler._number(expr, assumptions)
+ result = True
+ for arg in expr.args:
+ if query(arg, real=True, assumptions=assumptions):
+ pass
+ elif query(arg, imaginary=True, assumptions=assumptions):
+ result = result ^ True
+ else:
+ break
+ else:
+ return result
+
+ @staticmethod
+ def Pow(expr, assumptions):
+ """
+ Real**Integer -> Real
+ Positive**Real -> Real
+ Real**(Integer/Even) -> Real if base is nonnegative
+ Real**(Integer/Odd) -> Real
+ """
+ if expr.is_number:
+ return QueryRealHandler._number(expr, assumptions)
+ if query(expr.base, real=True, assumptions=assumptions):
+ if query(expr.exp, integer=True, assumptions=assumptions):
+ return True
+ elif expr.exp.is_Rational:
+ if (expr.exp.q % 2 == 0):
+ return query(expr.base, real=True, negative=False, \
+ assumptions=assumptions)
+ else: return True
+ elif query(expr.exp, real=True, assumptions=assumptions):
+ if query(expr.base, positive=True, assumptions=assumptions):
+ return True
+
+ @staticmethod
+ def Rational(expr, assumptions):
+ return True
+
+ @staticmethod
+ def Real(expr, assumptions):
+ return True
+
+ @staticmethod
+ def Pi(expr, assumptions):
+ return True
+
+ @staticmethod
+ def Exp1(expr, assumptions):
+ return True
+
+ @staticmethod
+ def abs(expr, assumptions):
+ return True
+
+ @staticmethod
+ def re(expr, assumptions):
+ return True
+
+ im = re
+
+ @staticmethod
+ def ImaginaryUnit(expr, assumptions):
+ return False
+
+ @staticmethod
+ def Infinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def NegativeInfinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def sin(expr, assumptions):
+ if query(expr.args[0], real=True, assumptions=assumptions):
+ return True
+
+ cos, exp = sin, sin
+
+class QueryExtendedRealHandler(QueryRealHandler):
+ """
+ Handler for key 'extended_real'
+ Test that an expression belongs to the field of extended real numbers,
+ that is real numbers union {Infinity, -Infinity}
+ """
+
+ @staticmethod
+ def Add(expr, assumptions):
+ return test_closed_group(expr, assumptions, 'extended_real')
+
+ Mul, Pow = Add, Add
+
+ @staticmethod
+ def Infinity(expr, assumptions):
+ return True
+
+ @staticmethod
+ def NegativeInfinity(expr, assumptions):
+ return True
+
+class QueryComplexHandler(CommonHandler):
+ """
+ Handler for key 'complex'
+ Test that an expression belongs to the field of complex numbers
+ """
+
+ @staticmethod
+ def Add(expr, assumptions):
+ return test_closed_group(expr, assumptions, 'complex')
+
+ Mul, Pow = Add, Add
+
+ @staticmethod
+ def Number(expr, assumptions):
+ return True
+
+ @staticmethod
+ def NumberSymbol(expr, assumptions):
+ return True
+
+ @staticmethod
+ def abs(expr, assumptions):
+ return True
+
+ @staticmethod
+ def ImaginaryUnit(expr, assumptions):
+ return True
+
+ @staticmethod
+ def Infinity(expr, assumptions):
+ return False
+
+ @staticmethod
+ def NegativeInfinity(expr, assumptions):
+ return False
+
+ sin, cos, exp, re, im = [abs]*5 # they are all complex functions
+
+class QueryImaginaryHandler(CommonHandler):
+ """
+ Handler for key 'imaginary'
+ Test that an expression belongs to the field of imaginary numbers,
+ that is, numbers in the form x*I, where x is real
+ """
+
+ @staticmethod
+ def _number(expr, assumptions):
+ # helper method
+ return not expr.as_real_imag()[0]
+
+ @staticmethod
+ def Add(expr, assumptions):
+ """
+ Imaginary + Imaginary -> Imaginary
+ Imaginary + Complex -> ?
+ Imaginary + Real -> !Imaginary
+ """
+ if expr.is_number:
+ return QueryImaginaryHandler._number(expr, assumptions)
+ reals = 0
+ for arg in expr.args:
+ if query(arg, imaginary=True, assumptions=assumptions):
+ pass
+ elif query(arg, real=True, assumptions=assumptions):
+ reals += 1
+ else:
+ break
+ else:
+ if reals == 0:
+ return True
+ if reals == 1 or (len(expr.args) == reals):
+ # two reals could sum 0 thus giving an imaginary
+ return False
+
+ @staticmethod
+ def Mul(expr, assumptions):
+ """
+ Real*Imaginary -> Imaginary
+ Imaginary*Imaginary -> Real
+ """
+ if expr.is_number:
+ return QueryImaginaryHandler._number(expr, assumptions)
+ result = False
+ reals = 0
+ for arg in expr.args:
+ if query(arg, imaginary=True, assumptions=assumptions):
+ result = result ^ True
+ elif not query(arg, real=True, assumptions=assumptions):
+ break
+ else:
+ if reals == len(expr.args):
+ return False
+ return result
+
+ Pow = Add
+
+ @staticmethod
+ def Number(expr, assumptions):
+ return not (expr.as_real_imag()[1] == 0)
+
+ NumberSymbol = Number
+
+ @staticmethod
+ def ImaginaryUnit(expr, assumptions):
+ return True
+
+
+#### Helper methods
+
+def test_closed_group(expr, assumptions, key):
+ """
+ Test for membership in a group with respect
+ to the current operation
+ """
+ kwargs = {'assumptions': assumptions, key: True}
+ result = True
+ for arg in expr.args:
+ _out = query(arg, **kwargs)
+ if _out is None: break
+ elif _out is False:
+ if result: result = False
+ else: break
+ else:
+ return result
+
diff --git a/sympy/queries/tests/test_query.py b/sympy/queries/tests/test_query.py
new file mode 100644
index 0000000..34a41b6
--- /dev/null
+++ b/sympy/queries/tests/test_query.py
@@ -0,0 +1,979 @@
+from sympy.core import Symbol, symbols, S, Rational, Integer
+from sympy.functions import exp, log, sin, cos, sign, re, im, sqrt


+from sympy.assumptions import Assume, register_global_assumptions, \

+ clean_global_assumptions
+from sympy.queries import query, register_handler, remove_handler
+from sympy.queries.handlers import QueryHandler
+from sympy.utilities.pytest import raises, XFAIL
+
+def test_int_1():
+ z = 1
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == True
+ assert query(z, rational=True) == True
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == False
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == True
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == True
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == True
+
+def test_float_1():
+ z = 1.0
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == True
+ assert query(z, rational=True) == True
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == False
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == True
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == True
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == True
+
+ z = 7.2123
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == False
+ assert query(z, rational=True) == True
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == False
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == True
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+def test_zero_0():
+ z = Integer(0)
+ assert query(z, zero=True) == True
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == True
+ assert query(z, rational=True) == True
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == False
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == True
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == True
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+def test_negativeone():
+ z = Integer(-1)
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == True
+ assert query(z, rational=True) == True
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == False
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == False
+ assert query(z, negative=True) == True
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == True
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+def test_infinity():
+ oo = S.Infinity
+ assert query(oo, commutative=True) == True
+ assert query(oo, integer=True) == False
+ assert query(oo, rational=True) == False
+ assert query(oo, real=True) == False
+ assert query(oo, extended_real=True) == True
+ assert query(oo, complex=True) == False
+ assert query(oo, irrational=True) == False
+ assert query(oo, imaginary=True) == False
+ assert query(oo, positive=True) == True
+ assert query(oo, negative=True) == False
+ assert query(oo, even=True) == False
+ assert query(oo, odd=True) == False
+ assert query(oo, bounded=True) == False
+ assert query(oo, infinitesimal=True) == False
+ assert query(oo, prime=True) == False
+ assert query(oo, composite=True) == False
+
+def test_neg_infinity():
+ mm = S.NegativeInfinity
+ assert query(mm, commutative=True) == True
+ assert query(mm, integer=True) == False
+ assert query(mm, rational=True) == False
+ assert query(mm, real=True) == False
+ assert query(mm, extended_real=True) == True
+ assert query(mm, complex=True) == False
+ assert query(mm, irrational=True) == False
+ assert query(mm, imaginary=True) == False
+ assert query(mm, positive=True) == False
+ assert query(mm, negative=True) == True
+ assert query(mm, even=True) == False
+ assert query(mm, odd=True) == False
+ assert query(mm, bounded=True) == False
+ assert query(mm, infinitesimal=True) == False
+ assert query(mm, prime=True) == False
+ assert query(mm, composite=True) == False
+
+def test_nan():
+ nan = S.NaN
+ assert query(nan, commutative=True) == True
+ assert query(nan, integer=True) == False
+ assert query(nan, rational=True) == False
+ assert query(nan, real=True) == False
+ assert query(nan, extended_real=True) == False
+ assert query(nan, complex=True) == False
+ assert query(nan, irrational=True) == False
+ assert query(nan, imaginary=True) == False
+ assert query(nan, positive=True) == False
+ assert query(nan, zero=True) == False
+ assert query(nan, even=True) == False
+ assert query(nan, odd=True) == False
+ assert query(nan, bounded=True) == False
+ assert query(nan, infinitesimal=True) == False
+ assert query(nan, prime=True) == False
+ assert query(nan, composite=True) == False
+
+def test_Rational_number():
+ r = Rational(3,4)
+ assert query(r, commutative=True) == True
+ assert query(r, integer=True) == False
+ assert query(r, rational=True) == True
+ assert query(r, real=True) == True
+ assert query(r, complex=True) == True
+ assert query(r, irrational=True) == False
+ assert query(r, imaginary=True) == False
+ assert query(r, positive=True) == True
+ assert query(r, negative=True) == False
+ assert query(r, even=True) == False
+ assert query(r, odd=True) == False
+ assert query(r, bounded=True) == True
+ assert query(r, infinitesimal=True) == False
+ assert query(r, prime=True) == False
+ assert query(r, composite=True) == False
+
+ r = Rational(1,4)
+ assert query(r, positive=True) == True
+ assert query(r, negative=True) == False
+
+ r = Rational(5,4)
+ assert query(r, negative=True) == False
+ assert query(r, positive=True) == True
+
+ r = Rational(5,3)
+ assert query(r, positive=True) == True
+ assert query(r, negative=True) == False
+
+ r = Rational(-3,4)
+ assert query(r, positive=True) == False
+ assert query(r, negative=True) == True
+
+ r = Rational(-1,4)
+ assert query(r, positive=True) == False
+ assert query(r, negative=True) == True
+
+ r = Rational(-5,4)
+ assert query(r, negative=True) == True
+ assert query(r, positive=True) == False
+
+ r = Rational(-5,3)
+ assert query(r, positive=True) == False
+ assert query(r, negative=True) == True
+
+def test_sqrt_2():
+ z = sqrt(2)
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == False
+ assert query(z, rational=True) == False
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == True
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == True
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+def test_pi():
+ z = S.Pi
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == False
+ assert query(z, rational=True) == False
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == True
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == True
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+ z = S.Pi + 1
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == False
+ assert query(z, rational=True) == False
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == True
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == True
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+ z = 2*S.Pi
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == False
+ assert query(z, rational=True) == False
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == True
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == True
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+ z = S.Pi ** 2
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == False
+ assert query(z, rational=True) == False
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == True
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == True
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+ z = (1+S.Pi) ** 2
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == False
+ assert query(z, rational=True) == False
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == True
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == True
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+def test_E():
+ z = S.Exp1
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == False
+ assert query(z, rational=True) == False
+ assert query(z, real=True) == True
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == True
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == True
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+def test_I():
+ I = S.ImaginaryUnit
+ z = I
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == False
+ assert query(z, rational=True) == False
+ assert query(z, real=True) == False
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == False
+ assert query(z, imaginary=True) == True
+ assert query(z, positive=True) == False
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+ z = 1 + I
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == False
+ assert query(z, rational=True) == False
+ assert query(z, real=True) == False
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == False
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == False
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+ z = I*(1+I)
+ assert query(z, commutative=True) == True
+ assert query(z, integer=True) == False
+ assert query(z, rational=True) == False
+ assert query(z, real=True) == False
+ assert query(z, complex=True) == True
+ assert query(z, irrational=True) == False
+ assert query(z, imaginary=True) == False
+ assert query(z, positive=True) == False
+ assert query(z, negative=True) == False
+ assert query(z, even=True) == False
+ assert query(z, odd=True) == False
+ assert query(z, bounded=True) == True
+ assert query(z, infinitesimal=True) == False
+ assert query(z, prime=True) == False
+ assert query(z, composite=True) == False
+
+def test_bounded():


+ x, y = symbols('xy')

+ assert query(x, bounded=True) == False
+ assert query(x, bounded=False) == True
+ assert query(x, bounded=True, assumptions=Assume(x, bounded=True)) == True
+ assert query(x, bounded=True, assumptions=Assume(y, bounded=True)) == False
+ assert query(x, bounded=True, assumptions=Assume(x, complex=True)) == False
+ assert query(x, bounded=True, assumptions=Assume(x, zero=True)) == True
+ assert query(x+ 1, bounded=True) == False
+ assert query(x+ 1, bounded=True, assumptions=Assume(x, bounded=True)) == True
+ assert query(x+y, bounded=True) == None
+ assert query(x+y, bounded=True, assumptions=Assume(x, bounded=True)) == False
+ assert query(x+1, bounded=True, assumptions=[Assume(x, bounded=True), \
+ Assume(y, bounded=True)]) == True
+ assert query(2*x, bounded=True) == False
+ assert query(2*x, bounded=True, assumptions=Assume(x, bounded=True)) == True
+ assert query(x*y, bounded=True) == None
+ assert query(x*y, bounded=True, assumptions=Assume(x, bounded=True)) == False
+ assert query(x*y, bounded=True, assumptions=Assume(x, bounded=True) & \
+ Assume(y, bounded=True)) == True
+
+ assert query(x**2, bounded=True) == False
+ assert query(2**x, bounded=True) == False
+ assert query(2**x, bounded=True, assumptions=Assume(x, bounded=True)) == True
+ assert query(x**x, bounded=True) == False
+ assert query(Rational(1,2) ** x, bounded=True) == True
+ assert query(x ** Rational(1,2), bounded=True) == False
+
+ # sign function
+ assert query(sign(x), bounded=True) == True
+ assert query(sign(x), bounded=True, assumptions=Assume(x, bounded=False)) == True
+
+ # exponential functions
+ assert query(log(x), bounded=True) == False
+ assert query(log(x), bounded=True, assumptions=Assume(x, bounded=True)) == True
+ assert query(exp(x), bounded=True) == False
+ assert query(exp(x), bounded=True, assumptions=Assume(x, bounded=True)) == True
+ assert query(exp(2), bounded=True) == True
+
+ # trigonometric functions
+ assert query(sin(x), bounded=True) == True
+ assert query(sin(x), bounded=True, assumptions=Assume(x, bounded=False)) == True
+ assert query(cos(x), bounded=True) == True
+ assert query(cos(x), bounded=True, assumptions=Assume(x, bounded=False)) == True
+ assert query(2*sin(x), bounded=True) == True
+ assert query(sin(x)**2, bounded=True) == True
+ assert query(cos(x)**2, bounded=True) == True
+ assert query(cos(x) + sin(x), bounded=True) == True
+
+@XFAIL
+def test_bounded_xfail():
+ """We need to support relations in query for this to work"""
+ x = Symbol('x')
+ assert query(sin(x)**x, bounded=True) == True
+ assert query(cos(x)**x, bounded=True) == True
+ assert query(sin(x) ** x, bounded=True) == True
+
+def test_commutative():
+ """By default objects are commutative that is why it returns True
+ for both key=True and key=False"""


+ x, y = symbols('xy')

+ assert query(x, commutative=True) == True
+ assert query(x, commutative=False) == False
+ assert query(x, commutative=True, assumptions=Assume(x, commutative=False)) == False
+ assert query(x, commutative=True, assumptions=Assume(x, complex=True)) == True
+ assert query(x, commutative=True, assumptions=Assume(x, imaginary=True)) == True
+ assert query(x, commutative=True, assumptions=Assume(x, real=True)) == True
+ assert query(x, commutative=True, assumptions=Assume(x, positive=True)) == True
+ assert query(x, commutative=True, assumptions=Assume(y, commutative=False)) == True
+
+ assert query(2*x, commutative=True ) == True
+ assert query(2*x, commutative=True, assumptions=Assume(x, commutative=False)) == False
+
+ assert query(x + 1, commutative=True ) == True
+ assert query(x + 1, commutative=True, assumptions=Assume(x, commutative=False)) == False
+
+ assert query(x**2, commutative=True) == True
+ assert query(x**2, commutative=True, assumptions=Assume(x, commutative=False)) == False
+
+ assert query(log(x), commutative=True) == True
+
+def test_complex():


+ x, y = symbols('xy')

+ assert query(x, complex=True) == None
+ assert query(x, complex=False) == None
+ assert query(x, complex=True, assumptions=Assume(x, complex=True)) == True
+ assert query(x, complex=True, assumptions=Assume(y, complex=True)) == None
+ assert query(x, complex=True, assumptions=Assume(x, complex=False)) == False
+ assert query(x, complex=True, assumptions=Assume(x, real=True)) == True
+ assert query(x, complex=True, assumptions=Assume(x, real=False)) == None
+ assert query(x, complex=True, assumptions=Assume(x, rational=True)) == True
+ assert query(x, complex=True, assumptions=Assume(x, irrational=True)) == True
+ assert query(x, complex=True, assumptions=Assume(x, zero=True)) == True
+ assert query(x, complex=True, assumptions=Assume(x, zero=False)) == None
+ assert query(x, complex=True, assumptions=Assume(x, positive=True)) == True
+ assert query(x, complex=True, assumptions=Assume(x, imaginary=True)) == True
+
+ # a+b
+ assert query(x+1, complex=True, assumptions=Assume(x, complex=True)) == True
+ assert query(x+1, complex=True, assumptions=Assume(x, real=True)) == True
+ assert query(x+1, complex=True, assumptions=Assume(x, rational=True)) == True
+ assert query(x+1, complex=True, assumptions=Assume(x, irrational=True)) == True
+ assert query(x+1, complex=True, assumptions=Assume(x, imaginary=True)) == True
+ assert query(x+1, complex=True, assumptions=Assume(x, integer=True)) == True
+ assert query(x+1, complex=True, assumptions=Assume(x, even=True)) == True
+ assert query(x+1, complex=True, assumptions=Assume(x, odd=True)) == True
+ assert query(x+y, complex=True, assumptions=Assume(x, complex=True) & \
+ Assume(y, complex=True)) == True
+ assert query(x+y, complex=True, assumptions=Assume(x, real=True) & \
+ Assume(y, imaginary=True)) == True
+
+ # a*x +b
+ assert query(2*x+1, complex=True, assumptions=Assume(x, complex=True)) == True
+ assert query(2*x+1, complex=True, assumptions=Assume(x, real=True)) == True
+ assert query(2*x+1, complex=True, assumptions=Assume(x, positive=True)) == True
+ assert query(2*x+1, complex=True, assumptions=Assume(x, rational=True)) == True
+ assert query(2*x+1, complex=True, assumptions=Assume(x, irrational=True)) == True
+ assert query(2*x+1, complex=True, assumptions=Assume(x, imaginary=True)) == True
+ assert query(2*x+1, complex=True, assumptions=Assume(x, integer=True)) == True
+ assert query(2*x+1, complex=True, assumptions=Assume(x, even=True)) == True
+ assert query(2*x+1, complex=True, assumptions=Assume(x, odd=True)) == True
+
+ # x**2
+ assert query(x**2, complex=True, assumptions=Assume(x, complex=True)) == True
+ assert query(x**2, complex=True, assumptions=Assume(x, real=True)) == True
+ assert query(x**2, complex=True, assumptions=Assume(x, positive=True)) == True
+ assert query(x**2, complex=True, assumptions=Assume(x, rational=True)) == True
+ assert query(x**2, complex=True, assumptions=Assume(x, irrational=True)) == True
+ assert query(x**2, complex=True, assumptions=Assume(x, imaginary=True)) == True
+ assert query(x**2, complex=True, assumptions=Assume(x, integer=True)) == True
+ assert query(x**2, complex=True, assumptions=Assume(x, even=True)) == True
+ assert query(x**2, complex=True, assumptions=Assume(x, odd=True)) == True
+
+ # 2**x
+ assert query(2**x, complex=True, assumptions=Assume(x, complex=True)) == True
+ assert query(2**x, complex=True, assumptions=Assume(x, real=True)) == True
+ assert query(2**x, complex=True, assumptions=Assume(x, positive=True)) == True
+ assert query(2**x, complex=True, assumptions=Assume(x, rational=True)) == True
+ assert query(2**x, complex=True, assumptions=Assume(x, irrational=True)) == True
+ assert query(2**x, complex=True, assumptions=Assume(x, imaginary=True)) == True
+ assert query(2**x, complex=True, assumptions=Assume(x, integer=True)) == True
+ assert query(2**x, complex=True, assumptions=Assume(x, even=True)) == True
+ assert query(2**x, complex=True, assumptions=Assume(x, odd=True)) == True
+ assert query(x**y, complex=True, assumptions=Assume(x, complex=True) & \
+ Assume(y, complex=True)) == True
+
+ # trigonometric expressions
+ assert query(sin(x), complex=True) == True
+ assert query(sin(2*x + 1), complex=True) == True
+ assert query(cos(x), complex=True) == True
+ assert query(cos(2*x+1), complex=True) == True
+
+ # exponential
+ assert query(exp(x), complex=True) == True
+ assert query(exp(x), complex=True) == True
+
+ # complexes
+ assert query(abs(x), complex=True) == True
+ assert query(re(x), complex=True) == True
+ assert query(im(x), complex=True) == True
+
+def test_even():
+ x, y, z, t = symbols('x y z t')
+ assert query(x, even=True) == None
+ assert query(x, even=True, assumptions=Assume(x, integer=True)) == None
+ assert query(x, even=True, assumptions=Assume(x, integer=False)) == False
+ assert query(x, even=True, assumptions=Assume(x, rational=True)) == None
+ assert query(x, even=True, assumptions=Assume(x, positive=True)) == None
+
+ assert query(2*x, even=True) == None
+ assert query(2*x, even=True, assumptions=Assume(x, integer=True)) == True
+ assert query(2*x, even=True, assumptions=Assume(x, even=True)) == True
+ assert query(2*x, even=True, assumptions=Assume(x, irrational=True)) == False
+ assert query(2*x, even=True, assumptions=Assume(x, odd=True)) == True
+ assert query(2*x, even=True, assumptions=Assume(x, integer=False)) == None
+ assert query(3*x, even=True, assumptions=Assume(x, integer=True)) == None
+ assert query(3*x, even=True, assumptions=Assume(x, even=True)) == True
+ assert query(3*x, even=True, assumptions=Assume(x, odd=True)) == False
+
+ assert query(x+1, even=True, assumptions=Assume(x, odd=True)) == True
+ assert query(x+1, even=True, assumptions=Assume(x, even=True)) == False
+ assert query(x+2, even=True, assumptions=Assume(x, odd=True)) == False
+ assert query(x+2, even=True, assumptions=Assume(x, even=True)) == True
+ assert query(7-x, even=True, assumptions=Assume(x, odd=True)) == True
+ assert query(7+x, even=True, assumptions=Assume(x, odd=True)) == True
+ assert query(x+y, even=True, assumptions=Assume(x, odd=True) & Assume(y, odd=True)) == True
+ assert query(x+y, even=True, assumptions=Assume(x, odd=True) & Assume(y, even=True)) == False
+ assert query(x+y, even=True, assumptions=Assume(x, even=True) & Assume(y, even=True)) == True
+
+ assert query(2*x + 1, even=True, assumptions=Assume(x, integer=True)) == False
+ assert query(2*x*y, even=True, assumptions=Assume(x, rational=True) & Assume(x, rational=True)) == None
+ assert query(2*x*y, even=True, assumptions=Assume(x, irrational=True) & Assume(x, irrational=True)) == None
+
+ assert query(x+y+z, even=True, assumptions=Assume(x, odd=True) & Assume(y, odd=True) & \
+ Assume(z, even=True)) == True
+ assert query(x+y+z+t, even=True, assumptions=Assume(x, odd=True) & Assume(y, odd=True) & \
+ Assume(z, even=True) & Assume(t, integer=True)) == None
+
+ assert query(abs(x), even=True, assumptions=Assume(x, even=True)) == True
+ assert query(abs(x), even=True, assumptions=Assume(x, even=False)) == None
+ assert query(re(x), even=True, assumptions=Assume(x, even=True)) == True
+ assert query(re(x), even=True, assumptions=Assume(x, even=False)) == None
+ assert query(im(x), even=True, assumptions=Assume(x, even=True)) == True
+ assert query(im(x), even=True, assumptions=Assume(x, real=True)) == True
+
+def test_extended_real():


+ x = symbols('x')

+ assert query(x, extended_real=True, assumptions=Assume(x, positive=True)) == True
+ assert query(-x, extended_real=True, assumptions=Assume(x, positive=True)) == True
+ assert query(-x, extended_real=True, assumptions=Assume(x, negative=True)) == True
+
+ assert query(x+S.Infinity, extended_real=True, assumptions=Assume(x, real=True)) == True
+
+def test_rational():


+ x, y = symbols('xy')

+ assert query(x, rational=True, assumptions=Assume(x, zero=True)) == True
+ assert query(x, rational=True, assumptions=Assume(x, integer=True)) == True
+ assert query(x, rational=True, assumptions=Assume(x, irrational=True)) == False
+ assert query(x, rational=True, assumptions=Assume(x, real=True)) == None
+ assert query(x, rational=True, assumptions=Assume(x, positive=True)) == None
+ assert query(x, rational=True, assumptions=Assume(x, negative=True)) == None
+ assert query(x, rational=True, assumptions=Assume(x, nonzero=True)) == None
+
+ assert query(2*x, rational=True, assumptions=Assume(x, rational=True)) == True
+ assert query(2*x, rational=True, assumptions=Assume(x, integer=True)) == True
+ assert query(2*x, rational=True, assumptions=Assume(x, even=True)) == True
+ assert query(2*x, rational=True, assumptions=Assume(x, odd=True)) == True
+ assert query(2*x, rational=True, assumptions=Assume(x, irrational=True)) == False
+
+ assert query(x/2, rational=True, assumptions=Assume(x, rational=True)) == True
+ assert query(x/2, rational=True, assumptions=Assume(x, integer=True)) == True
+ assert query(x/2, rational=True, assumptions=Assume(x, even=True)) == True
+ assert query(x/2, rational=True, assumptions=Assume(x, odd=True)) == True
+ assert query(x/2, rational=True, assumptions=Assume(x, irrational=True)) == False
+
+ assert query(1/x, rational=True, assumptions=Assume(x, rational=True)) == True
+ assert query(1/x, rational=True, assumptions=Assume(x, integer=True)) == True
+ assert query(1/x, rational=True, assumptions=Assume(x, even=True)) == True
+ assert query(1/x, rational=True, assumptions=Assume(x, odd=True)) == True
+ assert query(1/x, rational=True, assumptions=Assume(x, irrational=True)) == False
+
+ assert query(2/x, rational=True, assumptions=Assume(x, rational=True)) == True
+ assert query(2/x, rational=True, assumptions=Assume(x, integer=True)) == True
+ assert query(2/x, rational=True, assumptions=Assume(x, even=True)) == True
+ assert query(2/x, rational=True, assumptions=Assume(x, odd=True)) == True
+ assert query(2/x, rational=True, assumptions=Assume(x, irrational=True)) == False
+
+ # with multiple symbols
+ assert query(x*y, rational=True, assumptions=[Assume(x, irrational=True), \
+ Assume(y, irrational=True)]) == None
+ assert query(y/x, rational=True, assumptions=[Assume(x, rational=True), \
+ Assume(y, rational=True)]) == True
+ assert query(y/x, rational=True, assumptions=[Assume(x, integer=True), \
+ Assume(y, rational=True)]) == True
+ assert query(y/x, rational=True, assumptions=[Assume(x, even=True), \
+ Assume(y, rational=True)]) == True
+ assert query(y/x, rational=True, assumptions=[Assume(x, odd=True), \
+ Assume(y, rational=True)]) == True
+ assert query(y/x, rational=True, assumptions=[Assume(x, irrational=True), \
+ Assume(y, rational=True)]) == False
+
+def test_imaginary():
+ x, y, z = symbols('x y z')
+ I = S.ImaginaryUnit
+ assert query(x, imaginary=True) == None
+ assert query(x, imaginary=True, assumptions=Assume(x, real=True)) == False
+ assert query(x, imaginary=True, assumptions=Assume(x, prime=True)) == False
+
+ assert query(x+1, imaginary=True, assumptions=Assume(x, real=True)) == False
+ assert query(x+1, imaginary=True, assumptions=Assume(x, imaginary=True)) == False
+ assert query(x+I, imaginary=True, assumptions=Assume(x, real=True)) == False
+ assert query(x+I, imaginary=True, assumptions=Assume(x, imaginary=True)) == True
+ assert query(x+y, imaginary=True, assumptions=Assume(x, imaginary=True) & \
+ Assume(y, imaginary=True)) == True
+ assert query(x+y, imaginary=True, assumptions=Assume(x, real=True) & \
+ Assume(y, real=True)) == False
+ assert query(x+y, imaginary=True, assumptions=Assume(x, imaginary=True) & \
+ Assume(y, real=True)) == False
+ assert query(x+y, imaginary=True, assumptions=Assume(x, complex=True) & \
+ Assume(y, real=True)) == None
+
+ assert query(I*x, imaginary=True, assumptions=Assume(x, real=True)) == True
+ assert query(I*x, imaginary=True, assumptions=Assume(x, imaginary=True)) == False
+ assert query(I*x, imaginary=True, assumptions=Assume(x, complex=True)) == None
+ assert query(x*y, imaginary=True, assumptions=Assume(x, imaginary=True) & \
+ Assume(y, real=True)) == True
+
+ assert query(x+y+z, imaginary=True, assumptions=Assume(x, real=True) & \
+ Assume(y, real=True) & Assume(z, real=True)) == False
+ assert query(x+y+z, imaginary=True, assumptions=Assume(x, real=True) & \
+ Assume(y, real=True) & Assume(z, imaginary=True)) == None
+ assert query(x+y+z, imaginary=True, assumptions=Assume(x, real=True) & \
+ Assume(y, imaginary=True) & Assume(z, imaginary=True)) == False
+
+def test_infinitesimal():


+ x, y = symbols('x y')

+ assert query(x, infinitesimal=True) == None
+ assert query(x, infinitesimal=True, assumptions=Assume(x, infinitesimal=True)) == True
+
+ assert query(2*x, infinitesimal=True, assumptions=Assume(x, infinitesimal=True)) == True
+ assert query(x*y, infinitesimal=True, assumptions=Assume(x, infinitesimal=True)) == None
+ assert query(x*y, infinitesimal=True, assumptions=Assume(x, infinitesimal=True) & \
+ Assume(y, infinitesimal=True)) == True
+ assert query(x*y, infinitesimal=True, assumptions=Assume(x, infinitesimal=True) & \
+ Assume(y, bounded=True)) == True
+
+ assert query(x**2, infinitesimal=True, assumptions=Assume(x, infinitesimal=True)) == True
+
+def test_integer():


+ x = symbols('x')

+ assert query(x, integer=True) == None
+ assert query(x, integer=True, assumptions=Assume(x, integer=True)) == True
+ assert query(x, integer=True, assumptions=Assume(x, integer=False)) == False
+ assert query(x, integer=True, assumptions=Assume(x, real=False)) == False
+ assert query(x, integer=True, assumptions=Assume(x, positive=False)) == None
+
+ assert query(2*x, integer=True, assumptions=Assume(x, integer=True)) == True
+ assert query(2*x, integer=True, assumptions=Assume(x, even=True)) == True
+ assert query(2*x, integer=True, assumptions=Assume(x, prime=True)) == True
+ assert query(2*x, integer=True, assumptions=Assume(x, rational=True)) == None
+ assert query(2*x, integer=True, assumptions=Assume(x, real=True)) == None
+
+ assert query(x/2, integer=True, assumptions=Assume(x, odd=True)) == False
+ assert query(x/2, integer=True, assumptions=Assume(x, even=True)) == True
+ assert query(x/3, integer=True, assumptions=Assume(x, odd=True)) == None
+ assert query(x/3, integer=True, assumptions=Assume(x, even=True)) == False
+
+def test_negative():


+ x, y = symbols('xy')

+ assert query(x, negative=True, assumptions=Assume(x, negative=True)) == True
+ assert query(x, negative=True, assumptions=Assume(x, positive=True)) == False
+ assert query(x, negative=True, assumptions=Assume(x, real=False)) == False
+ assert query(x, negative=True, assumptions=Assume(x, prime=True)) == False
+ assert query(x, negative=True, assumptions=Assume(x, prime=False)) == None
+
+ assert query(-x, negative=True, assumptions=Assume(x, positive=True)) == True
+ assert query(-x, negative=True, assumptions=Assume(x, positive=False)) == None
+ assert query(-x, negative=True, assumptions=Assume(x, negative=True)) == False
+ assert query(-x, negative=True, assumptions=Assume(x, positive=True)) == True
+
+ assert query(x-1, negative=True, assumptions=Assume(x, negative=True)) == True
+ assert query(x+y, negative=True) == None
+ assert query(x+y, negative=True, assumptions=Assume(x, negative=True)) == None
+ assert query(x+y, negative=True, assumptions=Assume(x, negative=True) &\
+ Assume(y, negative=True)) == True
+
+ assert query(x*y, negative=True) == None
+ assert query(x*y, negative=True, assumptions=Assume(x, positive=True) & \
+ Assume(y, positive=True)) == False
+ assert query(x*y, negative=True, assumptions=Assume(x, positive=True) & \
+ Assume(y, negative=True)) == True
+ assert query(x*y, negative=True, assumptions=Assume(x, complex=True) & \
+ Assume(y, complex=True)) == None
+
+ assert query(x**y, negative=True) == None
+ assert query(x**y, negative=True, assumptions=Assume(x, negative=True) & \
+ Assume(y, even=True)) == False
+ assert query(x**y, negative=True, assumptions=Assume(x, negative=True) & \
+ Assume(y, odd=True)) == True
+ assert query(x**y, negative=True, assumptions=Assume(x, positive=True) & \
+ Assume(y, integer=True)) == False
+
+ assert query(abs(x), negative=True) == False
+
+def test_nonzero():
+ x = Symbol('x')
+ def nonzero(expr, assumptions=[]):
+ return query(expr, real=True, assumptions=assumptions) and \
+ query(expr, zero=False, assumptions=assumptions)
+ assert nonzero(x) == None
+ assert nonzero(x, assumptions=Assume(x, real=True) & Assume(x, zero=False))== True
+ assert nonzero(x, assumptions=Assume(x, zero=True)) == False
+ assert nonzero( x, assumptions=Assume(x, positive=True)) == True
+ assert nonzero(2*x, assumptions=Assume(x, positive=True)) == True
+
+def test_odd():
+ x, y, z, t = symbols('x y z t')
+ assert query(x, odd=True) == None
+ assert query(x, odd=True, assumptions=Assume(x, odd=True)) == True
+ assert query(x, odd=True, assumptions=Assume(x, integer=True)) == None
+ assert query(x, odd=True, assumptions=Assume(x, integer=False)) == False
+ assert query(x, odd=True, assumptions=Assume(x, rational=True)) == None
+ assert query(x, odd=True, assumptions=Assume(x, positive=True)) == None
+
+ assert query(-x, odd=True, assumptions=Assume(x, odd=True)) == True
+
+ assert query(2*x, odd=True) == None
+ assert query(2*x, odd=True, assumptions=Assume(x, integer=True)) == False
+ assert query(2*x, odd=True, assumptions=Assume(x, odd=True)) == False
+ assert query(2*x, odd=True, assumptions=Assume(x, irrational=True)) == False
+ assert query(2*x, odd=True, assumptions=Assume(x, integer=False)) == None
+ assert query(3*x, odd=True, assumptions=Assume(x, integer=True)) == None
+
+ assert query(x/3, odd=True, assumptions=Assume(x, odd=True)) == None
+ assert query(x/3, odd=True, assumptions=Assume(x, even=True)) == None
+
+ assert query(x+1, odd=True, assumptions=Assume(x, even=True)) == True
+ assert query(x+2, odd=True, assumptions=Assume(x, even=True)) == False
+ assert query(x+2, odd=True, assumptions=Assume(x, odd=True)) == True
+ assert query(3-x, odd=True, assumptions=Assume(x, odd=True)) == False
+ assert query(3-x, odd=True, assumptions=Assume(x, even=True)) == True
+ assert query(3+x, odd=True, assumptions=Assume(x, odd=True)) == False
+ assert query(3+x, odd=True, assumptions=Assume(x, even=True)) == True
+ assert query(x+y, odd=True, assumptions=Assume(x, odd=True) & Assume(y, odd=True)) == False
+ assert query(x+y, odd=True, assumptions=Assume(x, odd=True) & Assume(y, even=True)) == True
+ assert query(x-y, odd=True, assumptions=Assume(x, even=True) & Assume(y, odd=True)) == True
+ assert query(x-y, odd=True, assumptions=Assume(x, odd=True) & Assume(y, odd=True)) == False
+
+ assert query(x+y+z, odd=True, assumptions=Assume(x, odd=True) & Assume(y, odd=True) & \
+ Assume(z, even=True)) == False
+ assert query(x+y+z+t, odd=True, assumptions=Assume(x, odd=True) & Assume(y, odd=True) & \
+ Assume(z, even=True) & Assume(t, integer=True)) == None
+
+ assert query(2*x + 1, odd=True, assumptions=Assume(x, integer=True)) == True
+ assert query(2*x + y, odd=True, assumptions=Assume(x, integer=True) & Assume(y, odd=True)) == True
+ assert query(2*x + y, odd=True, assumptions=Assume(x, integer=True) & Assume(y, even=True)) == False
+ assert query(2*x + y, odd=True, assumptions=Assume(x, integer=True) & Assume(y, integer=True)) == None
+ assert query(x*y, odd=True, assumptions=Assume(x, odd=True) & Assume(y, even=True)) == False
+ assert query(x*y, odd=True, assumptions=Assume(x, odd=True) & Assume(y, odd=True)) == True
+ assert query(2*x*y, odd=True, assumptions=Assume(x, rational=True) & Assume(x, rational=True)) == None
+ assert query(2*x*y, odd=True, assumptions=Assume(x, irrational=True) & Assume(x, irrational=True)) == None
+
+ assert query(abs(x), odd=True, assumptions=Assume(x, odd=True)) == True
+
+def test_prime():


+ x, y = symbols('x y')

+ assert query(x, prime=True, assumptions=Assume(x, prime=True)) == True
+ assert query(x, prime=True, assumptions=Assume(x, prime=False)) == False
+ assert query(x, prime=True, assumptions=Assume(x, integer=True)) == None
+ assert query(x, prime=True, assumptions=Assume(x, integer=False)) == False
+
+ assert query(2*x, prime=True, assumptions=Assume(x, integer=True)) == False
+ assert query(x*y, prime=True) == None
+ assert query(x*y, prime=True, assumptions=Assume(x, prime=True)) == None
+ assert query(x*y, prime=True, assumptions=Assume(x, integer=True) & \
+ Assume(y, integer=True)) == False
+
+ assert query(x**2, prime=True, assumptions=Assume(x, integer=True)) == False
+ assert query(x**2, prime=True, assumptions=Assume(x, prime=True)) == False
+ assert query(x**y, prime=True, assumptions=Assume(x, integer=True) & \
+ Assume(y, integer=True)) == False
+
+def test_positive():
+ x, y, z, w = symbols('xyzw')
+ assert query(x, positive=True, assumptions=Assume(x, positive=True)) == True
+ assert query(x, positive=True, assumptions=Assume(x, negative=True)) == False
+ assert query(x, positive=True, assumptions=Assume(x, zero=True)) == False
+ assert query(x, positive=True, assumptions=Assume(x, nonnegative=True)) == None
+ assert query(x, positive=True, assumptions=Assume(x, nonnegative=False)) == None
+
+ assert query(-x, positive=True, assumptions=Assume(x, positive=True)) == False
+ assert query(-x, positive=True, assumptions=Assume(x, negative=True)) == True
+
+ assert query(x+y, positive=True, assumptions=Assume(x, positive=True) & \
+ Assume(y, positive=True)) == True
+ assert query(x+y, positive=True, assumptions=Assume(x, positive=True) & \
+ Assume(y, negative=True)) == None
+
+ assert query(2*x, positive=True, assumptions=Assume(x, positive=True)) == True
+ assumptions = Assume(x, positive=True) & Assume(y, negative=True) & \
+ Assume(z, negative=True) & Assume(w, positive=True)
+ assert query(x*y*z, positive=True) == None
+ assert query(x*y*z, positive=True, assumptions=assumptions) == True
+ assert query(-x*y*z, positive=True, assumptions=assumptions) == False
+
+ assert query(x**2, positive=True, assumptions=Assume(x, positive=True)) == True
+ assert query(x**2, positive=True, assumptions=Assume(x, negative=True)) == True
+ assert query(x**2, positive=True, assumptions=Assume(x, nonnegative=True)) == None # could be 0
+
+ #exponential
+ assert query(exp(x), positive=True, assumptions=Assume(x, real=True)) == True
+ assert query(x + exp(x), positive=True, assumptions=Assume(x, real=True)) == None
+
+ #absolute value
+ assert query(abs(x), positive=True) == None # abs(0) = 0
+ assert query(abs(x), positive=True, assumptions=Assume(x, positive=True)) == True
+
+@XFAIL
+def test_positive_xfail():
+ assert query(1/(1 + x**2), positive=True, assumptions=Assume(x, real=True)) == True
+
+def test_real():


+ x, y = symbols('x y')

+ assert query(x, real=True) == None
+ assert query(x, real=True, assumptions=Assume(x, real=True)) == True
+ assert query(x, real=True, assumptions=Assume(x, zero=True)) == True
+ assert query(x, real=True, assumptions=Assume(x, zero=False) & Assume(x, real=True)) == True
+ assert query(x, real=True, assumptions=Assume(x, positive=True)) == True
+ assert query(x, real=True, assumptions=Assume(x, negative=True)) == True
+ assert query(x, real=True, assumptions=Assume(x, negative=True) | Assume(x, zero=True)) == True
+ assert query(x, real=True, assumptions=Assume(x, positive=True) | Assume(x, zero=True)) == True
+ assert query(x, real=True, assumptions=Assume(x, integer=True)) == True
+ assert query(x, real=True, assumptions=Assume(x, even=True)) == True
+ assert query(x, real=True, assumptions=Assume(x, prime=True)) == True
+
+ assert query(x/sqrt(2), real=True, assumptions=Assume(x, real=True)) == True
+ assert query(x/sqrt(-2), real=True, assumptions=Assume(x, real=True)) == False
+
+ I = S.ImaginaryUnit
+ assert query(x+1, real=True, assumptions=Assume(x, real=True)) == True
+ assert query(x+I, real=True, assumptions=Assume(x, real=True)) == False
+ assert query(x+I, real=True, assumptions=Assume(x, complex=True)) == None
+
+ assert query(2*x, real=True, assumptions=Assume(x, real=True)) == True
+ assert query(I*x, real=True, assumptions=Assume(x, real=True)) == False
+ assert query(I*x, real=True, assumptions=Assume(x, imaginary=True)) == True
+ assert query(I*x, real=True, assumptions=Assume(x, complex=True)) == None
+
+ assert query(x**2, real=True, assumptions=Assume(x, real=True)) == True
+ assert query(sqrt(x), real=True, assumptions=Assume(x, negative=True)) == False
+ assert query(x**y, real=True, assumptions=Assume(x, real=True) & \
+ Assume(y, integer=True)) == True
+ assert query(x**y, real=True, assumptions=Assume(x, real=True) & \
+ Assume(y, real=True)) == None
+ assert query(x**y, real=True, assumptions=Assume(x, positive=True) &\
+ Assume(y, real=True)) == True
+
+ # trigonometric functions
+ assert query(sin(x), real=True) == None
+ assert query(cos(x), real=True) == None
+ assert query(sin(x), real=True, assumptions=Assume(x, real=True)) == True
+ assert query(cos(x), real=True, assumptions=Assume(x, real=True)) == True
+
+ # exponential function
+ assert query(exp(x), real=True) == None
+ assert query(exp(x), real=True, assumptions=Assume(x, real=True)) == True
+ assert query(x + exp(x), real=True, assumptions=Assume(x, real=True)) == True
+
+ # complexes
+ assert query(re(x), real=True) == True
+ assert query(im(x), real=True) == True
+
+def test_zero():


+ x, y = symbols('xy')

+ assert query(x, zero=True) == None
+ assert query(x, zero=True, assumptions=Assume(x, positive=True)) == False
+ assert query(x, zero=True, assumptions=Assume(x, negative=True)) == False
+
+ assert query(x+y, zero=True) == None
+ assert query(x+y, zero=True, assumptions=Assume(x, positive=True) & Assume(y, positive=True)) == False
+ assert query(x+y, zero=True, assumptions=Assume(x, positive=True) & Assume(y, negative=True)) == None
+ assert query(x+y, zero=True, assumptions=Assume(x, negative=True) & Assume(y, negative=True)) == False
+
+ assert query(2*x, zero=True) == None
+ assert query(2*x, zero=True, assumptions=Assume(x, positive=True)) == False
+ assert query(2*x, zero=True, assumptions=Assume(x, negative=True)) == False
+ assert query(x*y, zero=True, assumptions=Assume(x, zero=False)) == None
+ assert query(x*y, zero=True, assumptions=Assume(x, zero=False) & Assume(y, zero=False)) == False
+
+ assert query(abs(x), zero=True) == None
+ assert query(abs(x), zero=True, assumptions=Assume(x, zero=False)) == False
+
+def test_global():
+ """Test query with global assumptions"""


+ x = symbols('x')

+ assert query(x, integer=True) == None
+ register_global_assumptions(Assume(x, integer=True))
+ assert query(x, integer=True) == True
+ clean_global_assumptions()
+ assert query(x, integer=True) == None
+
+def test_incompatible_resolutors():


+ x = symbols('x')

+ class Prime2QueryHandler(QueryHandler):
+ @staticmethod
+ def Number(expr, assumptions):
+ return True
+ register_handler('prime', Prime2QueryHandler)
+ raises(ValueError, 'query(4, prime=True)')
+
+def test_key_extensibility():
+ """test that you can add keys to the query system at runtime"""
+ x = Symbol('x')
+ # make sure thie key is not defined
+ raises(KeyError, "query(x, my_key=True)")
+ class MyQueryHandler(QueryHandler):
+ @staticmethod
+ def Symbol(expr, assumptions):
+ return True
+ register_handler('my_key', MyQueryHandler)
+ assert query(x, my_key=True) == True
+ assert query(x+1, my_key=True) == None
+ remove_handler('my_key', MyQueryHandler)
+
+def test_type_extensibility():
+ """test that new types can be added to the query system at runtime
+ We create a custom type MyType, and override query prime=True with handler
+ MyQueryHandler for this type
+
+ TODO: test incompatible resolutors
+ """
+ from sympy.core import Basic
+
+ class MyType(Basic):
+ pass
+
+ class MyQueryHandler(QueryHandler):
+ @staticmethod
+ def MyType(expr, assumptions):
+ return True
+
+ a = MyType()
+ register_handler('prime', MyQueryHandler)
+ assert query(a, prime=True) == True
--
1.6.2.2

Fabian Pedregosa

unread,
Jul 21, 2009, 4:02:11 PM7/21/09
to sympy-...@googlegroups.com, Fabian Pedregosa
---
doc/src/modules.txt | 5 +-
doc/src/modules/queries.txt | 375 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 378 insertions(+), 2 deletions(-)
create mode 100644 doc/src/modules/queries.txt

diff --git a/doc/src/modules.txt b/doc/src/modules.txt
index 0816df0..ae5bbdb 100644
--- a/doc/src/modules.txt
+++ b/doc/src/modules.txt
@@ -17,6 +17,7 @@ access any SymPy module, or use this contens:
:maxdepth: 2

modules/core.txt
+ modules/concrete.txt
modules/evalf.txt
modules/functions.txt
modules/geometry.txt
@@ -26,14 +27,14 @@ access any SymPy module, or use this contens:
modules/logic.txt
modules/matrices.txt
modules/mpmath/index.txt
- modules/rewriting.txt
modules/polynomials.txt
modules/printing.txt
modules/plotting.txt
+ modules/queries.txt
+ modules/rewriting.txt
modules/series.txt
modules/simplify.txt
modules/statistics.txt
- modules/concrete.txt
modules/solvers.txt
modules/utilities/index.txt

diff --git a/doc/src/modules/queries.txt b/doc/src/modules/queries.txt
new file mode 100644
index 0000000..0d665cb
--- /dev/null
+++ b/doc/src/modules/queries.txt
@@ -0,0 +1,375 @@
+Query module
+============
+
+.. module:: sympy.queries
+
+Queries are used to ask information about expression. Main method in this
+module is function query:
+
+.. automethod:: sympy.queries.query
+
+Assumptions
+===========
+
+query has a keyword argument assumptions. It's value should be a boolean
+expression involving assumptions about objects in expr. Valid values include:
+
+ * Assume(x, integer=True)
+ * Assume(x, integer=False)
+ * Assume(x, integer=True) & Assume(x, positive=True)
+ * etc.
+
+See documentation for the logic module for a complete list of valid boolean
+expressions.
+
+
+Supported queries
+=================
+
+bounded
+-------
+
+Test that a function is bounded with respect to it's variables. For example,
+sin(x) is a bounded functions, but exp(x) is not.
+
+Examples::
+


+ >>> from sympy import *

+ >>> x = Symbol('x')

+ >>> query(exp(x), bounded=True)
+ False
+ >>> query(exp(x), bounded=True , assumptions=Assume(x, bounded=True))
+ True
+ >>> query(sin(x), bounded=True)
+ True
+
+
+commutative
+-----------
+
+Test that objects are commutative. By default, symbols in SymPy are considered
+commutative except otherwise stated
+
+Examples::
+


+ >>> from sympy import *
+ >>> x, y = symbols('x y')

+ >>> query(x, commutative=True)
+ True
+ >>> query(x, commutative=True, assumptions=Assume(x, commutative=False))
+ False
+ >>> query(x*y, commutative=True, assumptions=Assume(x, commutative=False))
+ False
+
+
+complex
+-------
+
+Test that expression belongs to the field of complex numbers.
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(2, complex=True)
+ True
+ >>> query(I, complex=True)
+ True


+ >>> x, y = symbols('x y')

+ >>> query(x+I*y, complex=True, assumptions=Assume(x, real=True) & Assume(y, real=True))
+ True
+
+
+even
+----
+
+Test that expression represents an even number, that is, an number that
+can be written in the form 2*n, n integer.
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(2, even=True)
+ True
+ >>> n = Symbol('n')
+ >>> query(2*n, even=True, assumptions=Assume(n, integer=True))
+ True
+
+
+extended_real
+-------------
+
+Test that an expression belongs to the field of extended real numbers, that is, real
+numbers union {Infinity, -Infinity}
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(oo, extended_real=True)
+ True
+ >>> query(2, extended_real=True)
+ True
+ >>> query(x, extended_real=True, assumptions=Assume(x, real=True))
+ True
+
+
+imaginary
+---------
+
+Test that an expression belongs to the field of imaginary numbers, that is,
+ it can be written as x*I, where x is real and I is the imaginary unit.
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(2*I, imaginary=True)
+ True


+ >>> x = Symbol('x')

+ >>> query(x*I, imaginary=True, assumptions=Assume(x, real=True))
+ True
+
+
+infinitesimal
+-------------
+
+Test that an expression is equivalent to an infinitesimal number.
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(1/oo, infinitesimal=True)
+ True


+ >>> x, y = symbols('x y')

+ >>> query(2*x, infinitesimal=True, assumptions=Assume(x, infinitesimal=True))
+ True
+ >>> query(x*y, infinitesimal=True, assumptions=Assume(x, infinitesimal=True) & Assume(y, bounded=True))
+ True
+
+
+integer
+-------
+
+Test that an expression belongs to the field of integer numbers
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(2, integer=True)
+ True
+ >>> query(sqrt(2), integer=True)
+ False


+ >>> x = Symbol('x')

+ >>> query(x/2, integer=True, assumptions=Assume(x, even=True))
+ True
+
+
+irrational
+----------
+
+Test that an expression represents an irrational number.
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(pi, irrational=True)
+ True
+ >>> query(sqrt(2), irrational=True)
+ True
+ >>> query(x*sqrt(2), irrational=True, assumptions=Assume(x, rational=True))
+ True
+
+
+rational
+--------
+
+Test that an expression represents a rational number.
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(Rational(3, 4), rational=True)
+ True


+ >>> x, y = symbols('x y')

+ >>> query(x/2, rational=True, assumptions=Assume(x, integer=True))
+ True
+ >>> query(x/y, rational=True, assumptions=Assume(x, integer=True) & Assume(y, integer=True))
+ True
+
+
+negative
+--------
+
+Test that an expression is less (strict) than zero.
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(0.3, negative=True)
+ False


+ >>> x = Symbol('x')

+ >>> query(-x, negative=True, assumptions=Assume(x, positive=True))
+ True
+
+Remarks
+^^^^^^^
+negative numbers are defined as real numbers that are not zero nor positive, so
+complex numbers (with nontrivial imaginary coefficients) will return False
+in this query. The same applies to query positive.
+
+
+positive
+--------
+
+Test that a given expression is greater (strict) than zero.
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(0.3, positive=True)
+ True


+ >>> x = Symbol('x')

+ >>> query(-x, positive=True, assumptions=Assume(x, negative=True))
+ True
+
+Remarks
+^^^^^^^
+see Remarks for negative
+
+
+prime
+-----
+
+Test that an expression represents a prime number.
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(13, prime=True)
+ True
+
+Remarks: Use sympy.ntheory.isprime for efficiently test numeric values
+
+
+real
+----
+
+Test that an expression belongs to the field of real numbers.
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(sqrt(2), real=True)
+ True


+ >>> x, y = symbols('x y')

+ >>> query(x*y, real=True, assumptions=Assume(x, real=True) & Assume(y, real=True))
+ True
+
+
+odd
+---
+
+Test that an expression represents an odd number.
+
+Examples::
+


+ >>> from sympy import *

+ >>> query(3, odd=True)
+ True
+ >>> n = Symbol('n')
+ >>> query(2*n + 1, odd=True, assumptions=Assume(n, integer=True))
+ True
+
+
+zero
+----
+
+Test that an expression is zero. This is mostly used for assumptions.
+
+Examples::
+


+ >>> from sympy import *

+ >>> x = Symbol('x')

+ >>> query(x, negative=True, assumptions=Assume(x, real=True) & Assume(x, positive=False) & Assume(x, zero=False))
+ True
+
+Note: To solve equations, use solve() instead
+
+
+Design
+======
+
+Each time query is called, the appropriate Handler for the current key is called. This is
+always a subclass of sympy.queries.QueryHandler. It's classmethods have the name's of the classes
+it supports. For example, a (simplified) QueryHandler for the query 'positive' would
+look like this::
+
+ class QueryPositiveHandler(CommonHandler):
+
+ def Mul(self):
+ # return True if all argument's in self.expr.args are positive
+ ...
+
+ def Add(self):
+ for arg in self.expr.args:
+ if not query(arg, positive=True, self.assumptions):


+ break
+ else:
+ # if all argument's are positive
+ return True

+ ...
+
+The .Mul() method is called when self.expr is an instance of Mul, the Add method
+would be called when self.expr is an instance of Add and so on.
+
+
+Extensibility
+=============
+
+You can define new queries or support new types by subclassing sympy.queries.QueryHandler
+ and registering that handler for a particular key by calling register_handler:
+
+.. automethod:: sympy.queries.register_handler
+
+You can undo this operation by calling remove_handler.
+
+.. automethod:: sympy.queries.remove_handler
+
+You can support new types [1]_ by adding a handler to an existing key. In the
+following example, we will create a new type MyType and extend the key 'prime'
+to accept this type (and return True)
+
+.. parsed-literal::


+
+ >>> from sympy.core import Basic

+ >>> from sympy.queries import register_handler


+ >>> from sympy.queries.handlers import QueryHandler

+ >>> class MyType(Basic):
+ ... pass
+ >>> class MyQueryHandler(QueryHandler):
+ ... @staticmethod
+ ... def MyType(expr, assumptions):
+ ... return True


+ >>> a = MyType()
+ >>> register_handler('prime', MyQueryHandler)

+ None
+ >>> query(a, prime=True)
+ True
+
+
+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 query could be used to speed up further queries, and
+current system does not take advantage of this. For example, a truth maintenance
+system (http://en.wikipedia.org/wiki/Truth_maintenance_system) could be implemented.
+
+Misc
+====
+
+You can find more examples in the in the form of test under directory sympy/query/tests/
+
+.. [1] New type must inherit from Basic, otherwise an exception will be raised.
+ This is a bug and should be fixed.
--
1.6.2.2

Aaron S. Meurer

unread,
Jul 21, 2009, 4:34:26 PM7/21/09
to sympy-...@googlegroups.com
How do you actually attach assumptions to variables? The old style
keyword argument to Symbol doesn't seem to work. I know that you can
pass Assume objects to query(), but is there a way to globally define
x as positive?
In [1]: x = Symbol('x', positive=True)

In [2]: query(x, positive=True)
<returns None>

In [3]: Assume(x, positive=True)
Out[3]: Assume(x, positive=True)

In [4]: query(x, positive=True)
<returns None>

In [5]: sqrt(x**2)
Out[5]: x

In [6]: sqrt(y**2)
Out[6]:
⎽⎽⎽⎽
╱ 2
╲╱ y

In [9]: Assume(y, positive=True)
Out[9]: Assume(y, positive=True)

In [10]: sqrt(y**2)
Out[10]:
⎽⎽⎽⎽
╱ 2
╲╱ y

So the reduction of sqrt(x**2) comes from the old assumptions, not the
new ones. I realize that not everything is implemented yet, but it
seems that at least [4] should return True.

For example, in Maple, typing assume(x, positive) changes the variable
x to be positive everywhere. You can also use "assuming" to only
assume for one expression:
> x;
x
> assume(x, positive);
> x;
x~ (the tilde indicates that x
has an assumption on it)
> is(x, positive);
true
> coulditbe(x, negative);
false
> sqrt(x**2)
x~
> sqrt(y**2) assuming y::positive;
y
> sqrt(y**2);
(1/2)
/ 2\
\y /

See http://www.maplesoft.com/support/help/view.aspx?path=assume for
more info on the Maple assumptions system.

The actual querying of facts seems to work well when you pass
assumptions to query().
In [1]: Assume(x, negative=True, positive=True)
AssertionError: ('inconsitency between facts', {'real': True,
'nonzero': True, 'commutative': True, 'nonpositive': False,
'positive': True, 'negative': False, 'nonnegative': True, 'zero':
False, 'complex': True, 'imaginary': False}, 'negative', True)

In [2]: query(x, real=True, assumptions=Assume(x, positive=True)) #
this always bothered me for not working in the old assumption system.
Out [2]: True

query() seems to be like the Maple is(). Will we also have something
like Maple's coulditbe()?

Aaron Meurer

Fabian Pedregosa

unread,
Jul 22, 2009, 3:10:35 AM7/22/09
to sympy-...@googlegroups.com
Aaron S. Meurer wrote:
> How do you actually attach assumptions to variables? The old style
> keyword argument to Symbol doesn't seem to work. I know that you can
> pass Assume objects to query(), but is there a way to globally define
> x as positive?
> In [1]: x = Symbol('x', positive=True)

Hi Aaron. There is a way to define global assumptions, although I
haven't used it much:

In [1]: register_global_assumptions(Assume(x, positive=True))

In [2]: query(x, positive=True)
Out[2]: True


you can then clear them with clear_global_assumptions(). I'll add this
info to doc/src/modules/queries.txt

>
> In [2]: query(x, positive=True)
> <returns None>
>
> In [3]: Assume(x, positive=True)
> Out[3]: Assume(x, positive=True)
>
> In [4]: query(x, positive=True)
> <returns None>
>
> In [5]: sqrt(x**2)
> Out[5]: x
>
> In [6]: sqrt(y**2)
> Out[6]:
> ⎽⎽⎽⎽
> ╱ 2
> ╲╱ y
>
> In [9]: Assume(y, positive=True)
> Out[9]: Assume(y, positive=True)
>
> In [10]: sqrt(y**2)
> Out[10]:
> ⎽⎽⎽⎽
> ╱ 2
> ╲╱ y
>

The new system won't reduce expressions based on assumptions. This will
be done by a function called refine (see mathematica's Refine)

> So the reduction of sqrt(x**2) comes from the old assumptions, not the
> new ones. I realize that not everything is implemented yet, but it
> seems that at least [4] should return True.

Yes, the price to pay in exchange is a small sacrifice in speed. That is
why methods in the core should not use query() directly. They should
test properties based on class membership and leave assumption-related
simplification to refine().
I am not familiar with Maple, but since query() returns None when it
can't say, I think coulditbe() is just:

In [1]: def coulditbe(*args, **kwargs):
...: _q = query(*args, **kwargs)
...: if (_q is True) or (_q is None): return True
...: return False


In [2]: register_global_assumptions(Assume(x, positive=True))

In [3]: coulditbe(x, negative=True)
Out[5]: False


If this is correct, then I don't think it is worth to implement coulditbe


Regards,

>
> Aaron Meurer
> On Jul 21, 2009, at 2:02 PM, Fabian Pedregosa wrote:
>
>> In this series of 4 patches, I implement a new query system.
>>
>> You can also pull from my repo, branch master:
>>
>> git pull http://fseoane.net/git/sympy.git master
>>
>>
>>
>
>
> >
>


--
http://fseoane.net/blog/

Aaron S. Meurer

unread,
Jul 22, 2009, 1:00:48 PM7/22/09
to sympy-...@googlegroups.com

On Jul 22, 2009, at 1:10 AM, Fabian Pedregosa wrote:

>
> Aaron S. Meurer wrote:
>> How do you actually attach assumptions to variables? The old style
>> keyword argument to Symbol doesn't seem to work. I know that you can
>> pass Assume objects to query(), but is there a way to globally define
>> x as positive?
>> In [1]: x = Symbol('x', positive=True)
>
> Hi Aaron. There is a way to define global assumptions, although I
> haven't used it much:
>
> In [1]: register_global_assumptions(Assume(x, positive=True))
>
> In [2]: query(x, positive=True)
> Out[2]: True
>

I see. Whenever we get this merged, will Symbol('x', positive=True)
call register_global_assumptions on x? If so, that will be fine.
See my link above for more info on Maple's assumptions system.
>
> In [1]: def coulditbe(*args, **kwargs):
> ...: _q = query(*args, **kwargs)
> ...: if (_q is True) or (_q is None): return True
> ...: return False
>
>
> In [2]: register_global_assumptions(Assume(x, positive=True))
>
> In [3]: coulditbe(x, negative=True)
> Out[5]: False
>
>
> If this is correct, then I don't think it is worth to implement
> coulditbe

coulditbe() returns True if there are any values of the variables that
make the expression true. Maple also has is(), which only returns
true if all values of the variables make the expression true. about()
will print the exact assumptions.
For example in Maple:
> assume(x, integer);
> coulditbe(x/2, integer);
true
> is(x/2, integer);
false
> about(x);
Originally x, renamed x~:
is assumed to be: integer

In your branch, query seems to take a middle approach. It returns
True if it is always True, but None if it is not always True, but not
always False either (or if it cannot determine), and False if it is
always False. Is this correct.

In [2]: query(x/2, integer=True, assumptions=Assume(x, integer=True))
<returns None>

It is also common have inequalities as arguments to coulditbe():
> assume(x, positive);
> coulditbe(x < 1);
true
> is(x < 1);
false
> coulditbe(x < 0);
false

query() doesn't seem to support this yet, unless I am doing it wrong:
In [3]: query(Ge(x, 1), assumptions=Assume(x, positive=True))
KeyError: 'popitem(): dictionary is empty'

I'm trying to think of an example of something that Maple could give
your more information with its two functions than your single query()
function. The only thing I can think of is the overloading of None in
query to mean both that it cannot determine and that it could be True
or False for different values. What do you think?

Aaron Meurer

Vinzent Steinberg

unread,
Jul 24, 2009, 2:57:20 PM7/24/09
to sympy-...@googlegroups.com
Looks fine, +1 if all tests pass.

Vinzent

Vinzent Steinberg

unread,
Jul 24, 2009, 3:10:04 PM7/24/09
to sympy-...@googlegroups.com
2009/7/21 Fabian Pedregosa <fab...@fseoane.net>:
What about a global_assumptions object with methods? I would prefer
this over this functional approach.

> +class Assume(Basic):
> +    """New-style assumptions
> +
> +#    >>> from sympy import Symbol, Assume
> +#    >>> x = Symbol('x')
> +#    >>> Assume(x, integer=True)
> +#    Assume( x, integer = True )
> +#    >>> Assume(x, integer=False)
> +#    Assume( x, integer = False )
> +#    >>> Assume( x > 1 )
> +#    Assume( x > 1, relational = True)

Why the additional spaces? ('( ', ' = ')
A doctest would be helpful, even if disabled.
Your work on assumptions is really shaping nicely!

Vinzent

Fabian Pedregosa

unread,
Jul 25, 2009, 4:51:44 AM7/25/09
to sympy-...@googlegroups.com
Yes, I also considered this approach, but for that I would need an
object GlobalAssumptions with methods .Add(), .Remove(), .Clean(). Plus,
this object should be a singleton of provide some way of preserving
data. I just felt that it was too complicated, while current approach is
much simpler (but I am willing to change it if there is a good reason to
do so).

>
> > +class Assume(Basic):
> > + """New-style assumptions
> > +
> > +# >>> from sympy import Symbol, Assume
> > +# >>> x = Symbol('x')
> > +# >>> Assume(x, integer=True)
> > +# Assume( x, integer = True )
> > +# >>> Assume(x, integer=False)
> > +# Assume( x, integer = False )
> > +# >>> Assume( x > 1 )
> > +# Assume( x > 1, relational = True)
>
> Why the additional spaces? ('( ', ' = ')
>

That's a bug, I'll correct it.

> > + """hat
indeed
Thanks!.

> Vinzent
>
> >

asmeurer

unread,
Jul 26, 2009, 1:02:40 AM7/26/09
to sympy-patches
By the way, I am also +1 for all 4, based on my pull from your github
branch.

Aaron Meurer

Vinzent Steinberg

unread,
Jul 26, 2009, 9:15:00 AM7/26/09
to sympy-...@googlegroups.com
2009/7/25 Fabian Pedregosa <fab...@fseoane.net>:

> Yes, I also considered this approach, but for that I would need an
> object GlobalAssumptions with methods .Add(), .Remove(), .Clean(). Plus,
> this object should be a singleton of provide some way of preserving
> data. I just felt that it was too complicated, while current approach is
> much simpler (but I am willing to change it if there is a good reason to
> do so).

I think an object would be much cleaner, because it does not pollute
the namespace. In my opinion it's not more complicated, I'd implement
it if you don't want to. ;)

Something along the lines

class GlobalAssumptions(set):
def clear():
...

Vinzent

Vinzent Steinberg

unread,
Jul 26, 2009, 10:36:10 AM7/26/09
to sympy-...@googlegroups.com
I assume every 'query' got renamed to 'ask'.

2009/7/21 Fabian Pedregosa <fab...@fseoane.net>:

2 colons?

> +
> +.. automethod:: sympy.queries.query
> +
> +Assumptions
> +===========
> +
> +query has a keyword argument assumptions. It's value should be a boolean
> +expression involving assumptions about objects in expr. Valid values include:
> +
> +    * Assume(x, integer=True)
> +    * Assume(x, integer=False)
> +    * Assume(x, integer=True) & Assume(x, positive=True)
> +    * etc.
> +
> +See documentation for the logic module for a complete list of valid boolean
> +expressions.
> +

What about lowercase 'assume'? For the use there is no difference
between ask() and assume(), and integrate() (at some point also
solve()) could also return a class, so this is maybe more consistent.

Dot?

Dot?

Dot?

So positive=True and negative=True is equivalent to nonzero=True?

> +
> +prime
> +-----
> +
> +Test that an expression represents a prime number.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> query(13, prime=True)
> +    True
> +
> +Remarks: Use sympy.ntheory.isprime for efficiently test numeric values
> +

Dot?

I think contradictory arguments should also be covered. (Things like
Assume(integer=False, odd=True).)

Are 2 colons necessary? I'm not sure...

> +
> +.. automethod:: sympy.queries.register_handler
> +
> +You can undo this operation by calling remove_handler.
> +
> +.. automethod:: sympy.queries.remove_handler
> +
> +You can support new types [1]_ by adding a handler to an existing key. In the
> +following example, we will create a new type MyType and extend the key 'prime'
> +to accept this type (and return True)

A dot?

Thank you.

Vinzent

Aaron S. Meurer

unread,
Jul 26, 2009, 1:09:58 PM7/26/09
to sympy-...@googlegroups.com
It looks like they are:
>>> Assume(integer=False, odd=True)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "./sympy/core/basic.py", line 305, in __new__
obj._learn_new_facts(assumptions)
File "./sympy/core/assumptions.py", line 336, in _learn_new_facts
self._assume_rules.deduce_all_facts(facts, base)
File "./sympy/core/facts.py", line 882, in deduce_all_facts
assert new_facts[k] == v, ('inconsitency between
facts',new_facts,k,v)
AssertionError: ('inconsitency between facts', {'nonzero': True,
'even': False, 'composite': False, 'prime': False, 'zero': False,
'integer': False, 'odd': False}, 'odd', True)

Aaron Meurer

Vinzent Steinberg

unread,
Jul 27, 2009, 4:50:28 AM7/27/09
to sympy-...@googlegroups.com
2009/7/26 Aaron S. Meurer <asme...@gmail.com>:

> It looks like they are:
>  >>> Assume(integer=False, odd=True)
> Traceback (most recent call last):
>   File "<console>", line 1, in <module>
>   File "./sympy/core/basic.py", line 305, in __new__
>     obj._learn_new_facts(assumptions)
>   File "./sympy/core/assumptions.py", line 336, in _learn_new_facts
>     self._assume_rules.deduce_all_facts(facts, base)
>   File "./sympy/core/facts.py", line 882, in deduce_all_facts
>     assert new_facts[k] == v, ('inconsitency between
> facts',new_facts,k,v)
> AssertionError: ('inconsitency between facts', {'nonzero': True,
> 'even': False, 'composite': False, 'prime': False, 'zero': False,
> 'integer': False, 'odd': False}, 'odd', True)

I meant the documentation. What do you think, should

>>> Assume(x, integer=True, positive=True)

raise an exception or should it return

Assume(x, integer=True) & Assume(x, positive=True)?


Vinzent

Ondrej Certik

unread,
Jul 27, 2009, 3:01:51 PM7/27/09
to sympy-...@googlegroups.com
I think this is fine. But I would like to test your whole branch first too.

O.

Ondrej Certik

unread,
Jul 27, 2009, 3:05:07 PM7/27/09
to sympy-...@googlegroups.com
On Tue, Jul 21, 2009 at 2:02 PM, Fabian Pedregosa<fab...@fseoane.net> wrote:
>

Those 4 patches are +1.


Ondrej

Aaron S. Meurer

unread,
Jul 27, 2009, 9:58:15 PM7/27/09
to sympy-...@googlegroups.com

I see what you mean:

>>> Assume(x, integer=True, positive=True)Traceback (most recent call

last):
File "<console>", line 1, in <module>

File "./sympy/assumptions/__init__.py", line 55, in __init__


raise ValueError('Wrong set of arguments')

ValueError: Wrong set of arguments

I think we should assume the and operator for multiple keyword
arguments. At any rate, I think "Wrong set of arguments" does not
explain clearly enough what the error was.

I had been working under the assumption that multiple arguments worked
like they do in the current assumptions system with my above example.
Trying Assume(x, integer=False) & Assume(x, odd=True) just returns
And(Assume(x, integer=False), Assume(x, odd=True)).

and Assume(x, integer=True, odd=True) just raises the same exception
as the example you give.

Is there supposed to be a function or method to reduce something like
And(Assume(x, integer=False), Assume(x, odd=True)) to an inconsistency
or something like And(Assume(x, integer=True), Assume(x, odd=False))
to Assume(x, even=True)? I couldn't find one.

Aaron Meurer

Fabian Pedregosa

unread,
Jul 29, 2009, 5:50:59 AM7/29/09
to sympy-...@googlegroups.com
If you implement it, I'll take if for sure :-)

>
> Vinzent
>
> >
>


--
http://fseoane.net/blog/

Fabian Pedregosa

unread,
Jul 29, 2009, 5:54:21 AM7/29/09
to sympy-...@googlegroups.com
Aaron S. Meurer wrote:
>
> On Jul 22, 2009, at 1:10 AM, Fabian Pedregosa wrote:
>
>> Aaron S. Meurer wrote:
>>> How do you actually attach assumptions to variables? The old style
>>> keyword argument to Symbol doesn't seem to work. I know that you can
>>> pass Assume objects to query(), but is there a way to globally define
>>> x as positive?
>>> In [1]: x = Symbol('x', positive=True)
>> Hi Aaron. There is a way to define global assumptions, although I
>> haven't used it much:
>>
>> In [1]: register_global_assumptions(Assume(x, positive=True))
>>
>> In [2]: query(x, positive=True)
>> Out[2]: True
>>
>
> I see. Whenever we get this merged, will Symbol('x', positive=True)
> call register_global_assumptions on x? If so, that will be fine.

I don't think that will be the case, because Symbol('x', positive=True)
gives the impression that assumptions are binded with symbols, but this
is not the case anymore.
I've been working with this branch for some time, and I did not feel the
need for an extra coulditbe function ...

>
> Aaron Meurer
>>
>> Regards,
>>
>>> Aaron Meurer
>>> On Jul 21, 2009, at 2:02 PM, Fabian Pedregosa wrote:
>>>
>>>> In this series of 4 patches, I implement a new query system.
>>>>
>>>> You can also pull from my repo, branch master:
>>>>
>>>> git pull http://fseoane.net/git/sympy.git master
>>>>
>>>>
>>>>
>>>
>>
>> --
>> http://fseoane.net/blog/
>>
>
>
> >
>


--
http://fseoane.net/blog/

Fabian Pedregosa

unread,
Jul 29, 2009, 6:06:46 AM7/29/09
to sympy-...@googlegroups.com
Thanks to all who helped review, that was really helpful.

However, showing my work to others in EuroSciPy revealed that the user
interface is a bit too verbose and can be much improved. I'll push now
patches 0 and 1, and before the end of the week I'll send a reworked
patch of 2 and 3.

Fabian


>
> Ondrej
>
> >
>


--
http://fseoane.net/blog/

Fabian Pedregosa

unread,
Jul 29, 2009, 6:20:26 AM7/29/09
to sympy-...@googlegroups.com
My intention was to use assumptions just as containers (no logic behind
it) so that they are light, fast objects. For multiple assumptions you
would do:

Assume(x, something=True) & Assume(x, otherthing=True) | Assume(x, ...) ...

which is much more expressive than Assume(x, something, other, ...).


The check that arguments are not contradictory is left to other methods,
like query, refine, etc.


BTW: it raises on Assume(integer=False, odd=True) because in inherits
from Basic which in turn inherits from AssumeMeths, but once the old
assumption system is removed, this will not raise anymore. Because of
this, I think it should raise when multiple keys are specified (i.e.
Assume(x, foo=True, bar=True) --> ValueError: Wrong set of arguments)
--
http://fseoane.net/blog/

Vinzent Steinberg

unread,
Jul 29, 2009, 11:27:49 AM7/29/09
to sympy-...@googlegroups.com
2009/7/29 Fabian Pedregosa <fab...@fseoane.net>:

> My intention was to use assumptions just as containers (no logic behind
> it) so that they are light, fast objects. For multiple assumptions you
> would do:

This is a nice concept, we can later implement helper methods that are
more conveniant to use.

Vinzent

Vinzent Steinberg

unread,
Jul 29, 2009, 11:32:32 AM7/29/09
to sympy-...@googlegroups.com
2009/7/29 Fabian Pedregosa <fab...@fseoane.net>:

> I don't think that will be the case, because Symbol('x', positive=True)
> gives the impression that assumptions are binded with symbols, but this
> is not the case anymore.

It would be a handy shortcut though.

Vinzent

Aaron S. Meurer

unread,
Jul 29, 2009, 12:36:53 PM7/29/09
to sympy-...@googlegroups.com
I agree.

Aaron Meurer

Ondrej Certik

unread,
Jul 29, 2009, 12:37:33 PM7/29/09
to sympy-...@googlegroups.com

Definitely. Let's get this in, we need to start getting rid of old
assumptions now.

Ondrej

Fabian Pedregosa

unread,
Jul 29, 2009, 12:53:51 PM7/29/09
to sympy-...@googlegroups.com
Maybe. Let's just implement them as I had in mind and later if someone
(you?) feels the need of this, just implement it. It should be easy

>
> Vinzent
>
> >
>


--
http://fseoane.net/blog/

Ondrej Certik

unread,
Aug 4, 2009, 1:33:06 AM8/4/09
to sympy-...@googlegroups.com
On Wed, Jul 29, 2009 at 10:53 AM, Fabian Pedregosa<fab...@fseoane.net> wrote:
>
> Vinzent Steinberg wrote:
>> 2009/7/29 Fabian Pedregosa <fab...@fseoane.net>:
>>> I don't think that will be the case, because Symbol('x', positive=True)
>>> gives the impression that assumptions are binded with symbols, but this
>>> is not the case anymore.
>>
>> It would be a handy shortcut though.
>
> Maybe. Let's just implement them as I had in mind and later if someone
> (you?) feels the need of this, just implement it. It should be easy

Yes, please do so. Let's merge now. If you could get things running
(=done:) till this Friday, it'd be awesome. Luke and Aaron will come,
so we can hack on this together.

Ondrej

Vinzent Steinberg

unread,
Aug 5, 2009, 3:06:05 PM8/5/09
to sympy-...@googlegroups.com
2009/8/4 Ondrej Certik <ond...@certik.cz>:

> Yes, please do so. Let's merge now. If you could get things running
> (=done:) till this Friday, it'd be awesome. Luke and Aaron will come,
> so we can hack on this together.

Yeah, let's get it merged. In the long run I would like such syntax:

Assume(x > 0)
Assume(x in RR) == Assume(x, rational=True)

Do you think the "in" syntax could replace the keyword argument
syntax? The latter one does not make much sense for relational
assumptions, e.g.:

Assume(x > y, positive=True)

But we can implement this before the interface gets stable (i.e.
before a release).

Vinzent

Fabian Pedregosa Izquierdo

unread,
Aug 5, 2009, 3:11:00 PM8/5/09
to sympy-...@googlegroups.com
Vinzent Steinberg wrote:
> 2009/8/4 Ondrej Certik <ond...@certik.cz>:
>> Yes, please do so. Let's merge now. If you could get things running
>> (=done:) till this Friday, it'd be awesome. Luke and Aaron will come,
>> so we can hack on this together.
>
> Yeah, let's get it merged. In the long run I would like such syntax:
>
> Assume(x > 0)
> Assume(x in RR) == Assume(x, rational=True)

That would be nice. For the first one, I think that could be done, only
that we would need to solve inequalities for the non-trivial examples.
for the "x in RR", I don't think there's the possibility to override
"in" in python

>
> Do you think the "in" syntax could replace the keyword argument
> syntax? The latter one does not make much sense for relational
> assumptions, e.g.:
>
> Assume(x > y, positive=True)
>
> But we can implement this before the interface gets stable (i.e.
> before a release).

Yes. I'm about to send some reworked patches of this with some of the
ideas we discussed in Leipzip.

>
> Vinzent
>
> >

Vinzent Steinberg

unread,
Aug 5, 2009, 3:29:48 PM8/5/09
to sympy-...@googlegroups.com
2009/8/5 Fabian Pedregosa Izquierdo <fab...@fseoane.net>:

> That would be nice. For the first one, I think that could be done, only
> that we would need to solve inequalities for the non-trivial examples.
> for the "x in RR", I don't think there's the possibility to override
> "in" in python

It is possible to overwrite __contains__ but sadly Python seems to
force booleans as a returned type.

Vinzent

Aaron S. Meurer

unread,
Aug 5, 2009, 3:32:51 PM8/5/09
to sympy-...@googlegroups.com

On Aug 5, 2009, at 1:11 PM, Fabian Pedregosa Izquierdo wrote:

>
> Vinzent Steinberg wrote:
>> 2009/8/4 Ondrej Certik <ond...@certik.cz>:
>>> Yes, please do so. Let's merge now. If you could get things running
>>> (=done:) till this Friday, it'd be awesome. Luke and Aaron will
>>> come,
>>> so we can hack on this together.
>>
>> Yeah, let's get it merged. In the long run I would like such syntax:
>>
>> Assume(x > 0)
>> Assume(x in RR) == Assume(x, rational=True)
>
> That would be nice. For the first one, I think that could be done,
> only
> that we would need to solve inequalities for the non-trivial examples.
> for the "x in RR", I don't think there's the possibility to override
> "in" in python
Isn't it just __contains__ (http://docs.python.org/reference/datamodel.html?highlight=__contains__#object.__contains__
)? We would have to have special QQ or RR objects that would return
something other than True or False for "x in QQ" (so it can be useful
to Assume), which would technically be a kind of hack, being against
Python standards, so the QQ and RR objects would have to be used
exclusively for that purpose. But I think that the syntax would be
technically possible in this way, unless Python absolutely fails
without a boolean return value. Maybe you could even then have it
temporarily set some kind of global variable somewhere that Assume
could pick up.

I definitely agree with having Assume(x > 0). Would Assume(x == 0) or
Assume(x = 0) work too? We should at least allow Assume(Eq(x, 0)).
Also, would Python let us do Assume(0>x>1), or would we have to do
Assume(x<0)&&Assume(x>1)? Maybe if we ever get a decent Interval
class, we could use that too.

Aaron Meurer

Fabian Pedregosa Izquierdo

unread,
Aug 5, 2009, 3:43:10 PM8/5/09
to sympy-...@googlegroups.com
Thanks for the info. I did not know about __contains__. Sadly, as
Vinzent pointed out, it seems to be converting arbitrary types to
boolean values (at least in python2.60):

>>> class A:
... pass
...
>>> class B:
... def __contains__(self, other):
... return A()
...
>>> 2 in B()
True

>
> I definitely agree with having Assume(x > 0). Would Assume(x == 0) or
> Assume(x = 0) work too? We should at least allow Assume(Eq(x, 0)).
> Also, would Python let us do Assume(0>x>1), or would we have to do
> Assume(x<0)&&Assume(x>1)? Maybe if we ever get a decent Interval
> class, we could use that too.

Those are nice ideas. I see the current system as a low-level interface
upon which we can implement some more fancy syntax. When we get that
merged we can start thinking of getting all this done.

Fabian

Ondrej Certik

unread,
Aug 5, 2009, 3:53:28 PM8/5/09
to sympy-...@googlegroups.com

I agree. But let's get it in now.

Ondrej

Fabian Pedregosa Izquierdo

unread,
Aug 5, 2009, 4:36:41 PM8/5/09
to sympy-...@googlegroups.com
I attach the reworked patches. You can also get it by pulling from my
ask branch:

git pull http://fseoane.net/git/sympy.git ask

Changes are done in the user interface. No behavior is expected to change:

- renamed query() to ask()
- less verbose syntax. no keyword arguments. ask takes two argument,
a sympy expression and a key, and optionally some assumptions as
optional third argument. No more need to specify assumptions using
assumptions=... See docs or tests for some examples.
0001-Fix-bug-in-Basic.is_number.patch
0002-New-assumptions-module.patch
0003-Implement-a-query-module.patch
0004-Documentation-for-the-queries-module.patch

Ondrej Certik

unread,
Aug 5, 2009, 4:53:50 PM8/5/09
to sympy-...@googlegroups.com
Looks good in general, but before we push this in, please improve the
doctest coverage to 100%:

$ bin/coverage_doctest.py sympy/assumptions/assume.py
----------------------------------------------------------------------
sympy/assumptions/assume.py

Missing documentation:
* expr(self)
* key(self)
* value(self)


Missing doctests:
* list_global_assumptions()
* remove_global_assumptions(*assump)
* clean_global_assumptions()
* eliminate_assume(expr, symbol=None)


Indirect doctest (function name doesn't occur in doctests):
* register_global_assumptions(*assump)

Use "# indirect doctest" in the docstring to surpress this warning
SCORE sympy/assumptions/assume.py: 12% (1 of 8)
----------------------------------------------------------------------



The same about the handlers/, do you think there should be no example
doctests? I think there should, at least in the classes, but I think
it should be in all methods. I have no idea how to use it without the
doctests.

Ondrej

On Wed, Aug 5, 2009 at 2:36 PM, Fabian Pedregosa
> From 0f41408ca233490ecd7c5a2967b0cf769ceca242 Mon Sep 17 00:00:00 2001
> From: Fabian Pedregosa <fab...@fseoane.net>
> Date: Tue, 21 Jul 2009 20:22:59 +0200
> Subject: [PATCH 1/4] Fix bug in Basic.is_number
>
> It used to return True with subinstances of Basic that had no
> arguments. See test added for a test case of the bug.
>
> I also squashed together two test cases that had the same name
> (and thus probably only one was getting run)
> ---
>  sympy/core/basic.py            |    8 +++++---
>  sympy/core/tests/test_basic.py |   23 +++++++++++------------
>  2 files changed, 16 insertions(+), 15 deletions(-)
>
> diff --git a/sympy/core/basic.py b/sympy/core/basic.py
> index b20ed06..35d39c4 100644
> --- a/sympy/core/basic.py
> +++ b/sympy/core/basic.py
> @@ -822,11 +822,13 @@ def is_number(self):
>            True
>
>         """
> +        result = False
>         for obj in self.iter_basic_args():
> -            if not obj.is_number:
> +            if obj.is_number:
> +                result = True
> +            else:
>                 return False
> -        else:
> -            return True
> +        return result
>
>     @property
>     def func(self):
> diff --git a/sympy/core/tests/test_basic.py b/sympy/core/tests/test_basic.py
> index 7c51702..238f144 100644
> --- a/sympy/core/tests/test_basic.py
> +++ b/sympy/core/tests/test_basic.py
> @@ -325,13 +325,6 @@ def test_doit():
>
>     assert (2*Integral(x, x)).doit() == x**2
>
> -def test_is_number():
> -    assert Rational(8).is_number
> -    assert not x.is_number
> -    assert (8+log(2)).is_number
> -    assert not (8+log(2)+x).is_number
> -    assert (1+x**2/x-x).is_number
> -
>  def test_attribute_error():
>     raises(AttributeError, "x.cos()")
>     raises(AttributeError, "x.sin()")
> @@ -525,19 +518,25 @@ def test_is_number():
>     assert Real(3.14).is_number == True
>     assert Integer(737).is_number == True
>     assert Rational(3, 2).is_number == True
> -
> +    assert Rational(8).is_number == True
>     assert x.is_number == False
>     assert (2*x).is_number == False
> -
>     assert (x + y).is_number == False
> -
>     assert log(2).is_number == True
>     assert log(x).is_number == False
> -
>     assert (2 + log(2)).is_number == True
> +    assert (8+log(2)).is_number == True
>     assert (2 + log(x)).is_number == False
> -
> +    assert (8+log(2)+x).is_number == False
>     assert (2*g).is_number == False
> +    assert (1+x**2/x-x).is_number == True
> +
> +    # test extensibility of .is_number
> +    # on subinstances of Basic
> +    class A(Basic):
> +        pass
> +    a = A()
> +    assert a.is_number == False
>
>
>  # TODO write more tests for as_coeff_factors
> --
> 1.6.4
>
>
> From 07a03fddc56998833d9292d330525bcf02d4d309 Mon Sep 17 00:00:00 2001
> From: Fabian Pedregosa <fab...@fseoane.net>
> Date: Tue, 21 Jul 2009 20:24:46 +0200
> Subject: [PATCH 2/4] New assumptions module.
>
> This is now independent from objects and out of the core. Assume is
> the basic object is this new model, and it is only a container
> (all logic is done by sympy.logic and sympy.queries).
> ---
>  sympy/__init__.py                             |    2 +-
>  sympy/assumptions/__init__.py                 |    2 +
>  sympy/assumptions/assume.py                   |   91 +++++++++++++++++++++++++
>  sympy/assumptions/tests/test_assumptions_2.py |   58 ++++++++++++++++
>  4 files changed, 152 insertions(+), 1 deletions(-)
>  create mode 100644 sympy/assumptions/__init__.py
>  create mode 100644 sympy/assumptions/assume.py
>  create mode 100644 sympy/assumptions/tests/test_assumptions_2.py
>
> diff --git a/sympy/__init__.py b/sympy/__init__.py
> index 3be16a4..c813490 100644
> --- a/sympy/__init__.py
> +++ b/sympy/__init__.py
> @@ -21,7 +21,7 @@ def __sympy_debug():
>
>  import symbol as stdlib_symbol
>  from sympy.core import *
> -
> +from assumptions import *
>  from polys import *
>  from series import *
>  from functions import *
> diff --git a/sympy/assumptions/__init__.py b/sympy/assumptions/__init__.py
> new file mode 100644
> index 0000000..bdd47c2
> --- /dev/null
> +++ b/sympy/assumptions/__init__.py
> @@ -0,0 +1,2 @@
> +from assume import Assume, register_global_assumptions, list_global_assumptions, \
> +    remove_global_assumptions, clean_global_assumptions
> diff --git a/sympy/assumptions/assume.py b/sympy/assumptions/assume.py
> new file mode 100644
> index 0000000..a1fa0eb
> --- /dev/null
> +++ b/sympy/assumptions/assume.py
> @@ -0,0 +1,91 @@
> +# doctests are disabled because of issue #1521
> +from sympy.core import Basic, Symbol
> +from sympy.core.relational import Relational
> +
> +__global_assumptions = []
> +
> +def register_global_assumptions(*assump):
> +    """Register an assumption as global
> +
> +    Examples:
> +#        >>> from sympy import *
> +#        >>> list_global()
> +#        []
> +#        >>> x = Symbol('x')
> +#        >>> register_global(Assume(x, real=True))
> +#        True
> +#        >>> list_global()
> +#        [Assume(x, real=True)]
> +
> +    You can undo this calling remove_global
> +    """
> +    __global_assumptions.extend(assump)
> +
> +def list_global_assumptions():
> +    """List all global assumptions"""
> +    return __global_assumptions[:] # make a copy
> +
> +def remove_global_assumptions(*assump):
> +    """Remove a global assumption. If argument is not
> +    a global assumption, it will raise  ValueError
> +    """
> +    for assumption in assump:
> +        __global_assumptions.remove(assumption)
> +
> +def clean_global_assumptions():
> +    """Remove all global assumptions"""
> +    global __global_assumptions
> +    __global_assumptions = []
> +
> +class Assume(Basic):
> +    """New-style assumptions
> +
> +#    >>> from sympy import Symbol, Assume
> +#    >>> x = Symbol('x')
> +#    >>> Assume(x, integer=True)
> +#    Assume( x, integer = True )
> +#    >>> Assume(x, integer=False)
> +#    Assume( x, integer = False )
> +#    >>> Assume( x > 1 )
> +#    Assume( x > 1, relational = True)
> +    """
> +
> +    def __init__(self, expr, key='relational', value=True):
> +        self._args = (expr, key, value)
> +
> +    is_Atom = True # do not attempt to decompose this
> +
> +    @property
> +    def expr(self):
> +        return self._args[0]
> +
> +    @property
> +    def key(self):
> +        return self._args[1]
> +
> +    @property
> +    def value(self):
> +        return self._args[2]
> +
> +    def __eq__(self, other):
> +        if type(other) == Assume:
> +            return self._args == other._args
> +        return False
> +
> +def eliminate_assume(expr, symbol=None):
> +    """
> +    Will convert an expression with assumptions to an equivalent with all assumptions
> +    replaced by symbols
> +    Assume(x, integer=True) --> integer
> +    Assume(x, integer=False) --> ~integer
> +    """
> +    if type(expr) == Assume:
> +        if symbol is not None:
> +            if not expr.expr.has(symbol): return
> +        if expr.value: return Symbol(expr.key)
> +        return ~Symbol(expr.key)
> +    args = []
> +    for a in expr.args:
> +        args.append(eliminate_assume(a))
> +    return type(expr)(*args)
> +
> diff --git a/sympy/assumptions/tests/test_assumptions_2.py b/sympy/assumptions/tests/test_assumptions_2.py
> new file mode 100644
> index 0000000..4c630bc
> --- /dev/null
> +++ b/sympy/assumptions/tests/test_assumptions_2.py
> @@ -0,0 +1,58 @@
> +"""rename this to test_assumptions.py when the old assumptions system is deleted"""
> +from sympy.core import symbols
> +from sympy.assumptions import Assume, register_global_assumptions, \
> +    list_global_assumptions, remove_global_assumptions, clean_global_assumptions
> +from sympy.assumptions.assume import eliminate_assume
> +from sympy.printing import pretty
> +
> +def test_assume():
> +    x = symbols('x')
> +    assump = Assume(x, 'integer')
> +    assert assump.expr == x
> +    assert assump.key == 'integer'
> +    assert assump.value == True
> +
> +def test_False():
> +    """Test Assume object with False keys"""
> +    x = symbols('x')
> +    assump = Assume(x, 'integer', False)
> +    assert assump.expr == x
> +    assert assump.key == 'integer'
> +    assert assump.value == False
> +
> +def test_equal():
> +    """Test for equality"""
> +    x = symbols('x')
> +    assert Assume(x, 'positive', True)  == Assume(x, 'positive', True)
> +    assert Assume(x, 'positive', True)  != Assume(x, 'positive', False)
> +    assert Assume(x, 'positive', False) == Assume(x, 'positive', False)
> +
> +def test_pretty():
> +    x = symbols('x')
> +    assert pretty(Assume(x, 'positive', True)) == 'Assume(x, positive, True)'
> +
> +def test_eliminate_assumptions():
> +    a, b, x, y = symbols('abxy')
> +    assert eliminate_assume(Assume(x, 'a', True))  == a
> +    assert eliminate_assume(Assume(x, 'a', True), symbol=x)  == a
> +    assert eliminate_assume(Assume(x, 'a', True), symbol=y)  == None
> +    assert eliminate_assume(Assume(x, 'a', False)) == ~a
> +    assert eliminate_assume(Assume(x, 'a', False), symbol=y) == None
> +    assert eliminate_assume(Assume(x, 'a', True) | Assume(x, 'b')) == a | b
> +    assert eliminate_assume(Assume(x, 'a', True) | Assume(x, 'b', False)) == a | ~b
> +
> +def test_global():
> +    """Test for global assumptions"""
> +    x, y = symbols('x y')
> +    register_global_assumptions(Assume(x>0))
> +    assert Assume(x>0) in list_global_assumptions()
> +    remove_global_assumptions(Assume(x>0))
> +    assert (Assume(x>0) in list_global_assumptions()) == False
> +
> +    # same with multiple of assumptions
> +    register_global_assumptions(Assume(x>0), Assume(y>0))
> +    assert Assume(x>0) in list_global_assumptions()
> +    assert Assume(y>0) in list_global_assumptions()
> +    clean_global_assumptions()
> +    assert (Assume(x>0) in list_global_assumptions()) == False
> +    assert (Assume(y>0) in list_global_assumptions()) == False
> --
> 1.6.4
>
>
> From ebbac3eb02645abbf85ef42edf2c977a9c4548e6 Mon Sep 17 00:00:00 2001
> From: Fabian Pedregosa <fab...@fseoane.net>
> Date: Tue, 21 Jul 2009 20:26:03 +0200
> Subject: [PATCH 3/4] Implement a query module
>  sympy/queries/__init__.py          |  170 +++++++
>  sympy/queries/handlers/__init__.py |   40 ++
>  sympy/queries/handlers/calculus.py |  143 ++++++
>  sympy/queries/handlers/ntheory.py  |  218 ++++++++
>  sympy/queries/handlers/order.py    |  175 +++++++
>  sympy/queries/handlers/sets.py     |  427 ++++++++++++++++
>  sympy/queries/tests/test_query.py  |  957 ++++++++++++++++++++++++++++++++++++
>  8 files changed, 2131 insertions(+), 0 deletions(-)
>  create mode 100644 sympy/queries/__init__.py
>  create mode 100644 sympy/queries/handlers/__init__.py
>  create mode 100644 sympy/queries/handlers/calculus.py
>  create mode 100644 sympy/queries/handlers/ntheory.py
>  create mode 100644 sympy/queries/handlers/order.py
>  create mode 100644 sympy/queries/handlers/sets.py
>  create mode 100644 sympy/queries/tests/test_query.py
>
> diff --git a/sympy/__init__.py b/sympy/__init__.py
> index c813490..e01ee96 100644
> --- a/sympy/__init__.py
> +++ b/sympy/__init__.py
> @@ -40,6 +40,7 @@ def __sympy_debug():
>     pprint_try_use_unicode, print_gtk, print_tree
>  from printing import ccode, latex, preview, view, pngview, pdfview, dviview
>  from printing import python, print_python, srepr, sstr, sstrrepr
> +from queries import Q, ask
>
>  evalf._create_evalf_table()
>
> diff --git a/sympy/queries/__init__.py b/sympy/queries/__init__.py
> new file mode 100644
> index 0000000..85a3a03
> --- /dev/null
> +++ b/sympy/queries/__init__.py
> @@ -0,0 +1,170 @@
> +import inspect
> +from sympy.core import Symbol, sympify
> +from sympy.utilities.source import get_class
> +from sympy.assumptions import list_global_assumptions
> +from sympy.assumptions.assume import eliminate_assume
> +from sympy.logic.boolalg import to_cnf, conjuncts, \
> +    compile_rule, Equivalent, And
> +from sympy.logic.algorithms.dpll import dpll_satisfiable
> +
> +class Q:
> +    """Supported ask keys"""
> +    bounded = 'bounded'
> +    commutative = 'commutative'
> +    complex = 'complex'
> +    composite = 'composite'
> +    even = 'even'
> +    extended_real = 'extended_real'
> +    imaginary = 'imaginary'
> +    infinitesimal = 'infinitesimal'
> +    integer = 'integer'
> +    irrational = 'irrational'
> +    rational = 'rational'
> +    negative = 'negative'
> +    nonzero = 'nonzero'
> +    positive = 'positive'
> +    prime = 'prime'
> +    real = 'real'
> +    odd = 'odd'
> +
> +def ask(expr, key, assumptions=[]):
> +    """
> +    Method for inferring properties about objects.
> +
> +    Syntax
> +
> +        * ask(expression, key)
> +
> +        * ask(expression, key, assumptions)
> +
> +            where expression is any SymPy expression
> +
> +    Examples
> +        >>> from sympy import *
> +        >>> x, y = symbols('x y')
> +        >>> ask(pi, Q.rational)
> +        False
> +        >>> ask(x*y, Q.even, Assume(x, Q.even) & Assume(y, Q.integer))
> +        True
> +        >>> ask(x*y, Q.prime, Assume(x, Q.integer) &  Assume(y, Q.integer))
> +        False
> +
> +    Remarks
> +        Relations in assumptions are not implemented (yet), so the following
> +        will not give a meaningful result.
> +        #>>> ask(x, positive=True, Assume(x>0))
> +        It is however a work in progress and should be available before
> +        the official release
> +    """
> +    expr = sympify(expr)
> +
> +    global_assump = list_global_assumptions()
> +    if assumptions:
> +        assumptions = And(assumptions, And(*global_assump))
> +    elif global_assump: assumptions = And(*global_assump)
> +    if not isinstance(assumptions, (list, tuple)):
> +        assumptions = conjuncts(to_cnf(assumptions))
> +
> +    # direct resolution method, no logic
> +    resolutors = []
> +    for handler in handlers_dict[key]:
> +        resolutors.append( get_class(handler) )
> +    res, _res = None, None
> +    mro = inspect.getmro(type(expr))
> +    for handler in resolutors:
> +        for subclass in mro:
> +            if hasattr(handler, subclass.__name__):
> +                res = getattr(handler, subclass.__name__)(expr, assumptions)
> +                if _res is None: _res = res
> +                elif _res != res: raise ValueError, 'incompatible resolutors'
> +                break
> +    if res is not None:
> +        return res
> +
> +    if assumptions: pass
> +    else: return
> +
> +    # use logic inference
> +    if not expr.is_Atom: return
> +    clauses = []
> +    for k, values in known_facts_dict.iteritems():
> +        for v in values:
> +            clauses.append(Equivalent(compile_rule(k), compile_rule(v)))
> +    result = None
> +
> +    # add assumptions to the knowledge base
> +    for assump in assumptions:
> +        conj = eliminate_assume(assump, symbol=expr)
> +        if conj: clauses.append(conj)
> +
> +    clauses.append(Symbol(key))
> +    # TODO: call dpll and avoid creating this object
> +    if not dpll_satisfiable(And(*clauses)):
> +        return False
> +    clauses[-1] = ~clauses[-1]
> +    if not dpll_satisfiable(And(*clauses)):
> +        # if the negation is satisfiable, it is entailed
> +        return True
> +    clauses.pop(-1)
> +
> +
> +def register_handler(key, handler):
> +    """Register a handler in the ask system. key must be a string and handler a
> +    class inheriting from AskHandler.
> +
> +        >>> from sympy.queries.handlers import AskHandler
> +        >>> class MersenneHandler(AskHandler):
> +        ...     # Mersenne numbers are in the form 2**n + 1, n integer
> +        ...     @staticmethod
> +        ...     def Integer(expr, assumptions):
> +        ...         import math
> +        ...         return ask(math.log(expr + 1, 2), 'integer')
> +        >>> register_handler('mersenne', MersenneHandler)
> +        >>> ask(7, 'mersenne')
> +        True
> +    """
> +    if key in handlers_dict:
> +        handlers_dict[key].append(handler)
> +    else:
> +        handlers_dict.update({key: [handler]})
> +
> +def remove_handler(key, handler):
> +    """Removes a handler from the ask system. Same syntax as register_handler"""
> +    handlers_dict[key].remove(handler)
> +
> +# handlers_dict tells us what ask handler we should use
> +# for a particular key
> +handlers_dict = {
> +    'bounded'        : ['sympy.queries.handlers.calculus.AskBoundedHandler'],
> +    'commutative'    : ['sympy.queries.handlers.AskCommutativeHandler'],
> +    'complex'        : ['sympy.queries.handlers.sets.AskComplexHandler'],
> +    'composite'      : ['sympy.queries.handlers.ntheory.AskCompositeHandler'],
> +    'even'           : ['sympy.queries.handlers.ntheory.AskEvenHandler'],
> +    'extended_real'  : ['sympy.queries.handlers.sets.AskExtendedRealHandler'],
> +    'imaginary'      : ['sympy.queries.handlers.sets.AskImaginaryHandler'],
> +    'infinitesimal'  : ['sympy.queries.handlers.calculus.AskInfinitesimalHandler'],
> +    'integer'        : ['sympy.queries.handlers.sets.AskIntegerHandler'],
> +    'irrational'     : ['sympy.queries.handlers.sets.AskIrrationalHandler'],
> +    'rational'       : ['sympy.queries.handlers.sets.AskRationalHandler'],
> +    'negative'       : ['sympy.queries.handlers.order.AskNegativeHandler'],
> +    'nonzero'        : ['sympy.queries.handlers.order.AskNonZeroHandler'],
> +    'positive'       : ['sympy.queries.handlers.order.AskPositiveHandler'],
> +    'prime'          : ['sympy.queries.handlers.ntheory.AskPrimeHandler'],
> +    'real'           : ['sympy.queries.handlers.sets.AskRealHandler'],
> +    'odd'            : ['sympy.queries.handlers.ntheory.AskOddHandler'],
> +}
> +
> +known_facts_dict = {
> +    'complex'       : ['real | complex_number_re_0'],
> +    'even'          : ['integer & ~odd'],
> +    'extended_real' : ['real | infinity'],
> +    'odd'           : ['integer & ~even'],
> +    'prime'         : ['integer & positive & ~composite'],
> +    'integer'       : ['rational & denominator_one'],
> +    'imaginary'     : ['complex & ~real'],
> +    'negative'      : ['real & ~positive & ~zero'],
> +    'nonzero'       : ['positive | negative'],
> +    'positive'      : ['real & ~negative & ~zero'],
> +    'rational'      : ['real & ~irrational'],
> +    'real'          : ['rational | irrational' ],
> +}
> diff --git a/sympy/queries/handlers/__init__.py b/sympy/queries/handlers/__init__.py
> new file mode 100644
> index 0000000..7f36e1b
> --- /dev/null
> +++ b/sympy/queries/handlers/__init__.py
> @@ -0,0 +1,40 @@
> +from sympy.queries import Q, ask
> +
> +class AskHandler(object):
> +    """Base class that all Ask Handlers must inherit"""
> +    pass
> +
> +class CommonHandler(AskHandler):
> +    """Defines some useful methods common to most Handlers """
> +
> +    @staticmethod
> +    def NaN(expr, assumptions):
> +        return False
> +
> +class AskCommutativeHandler(CommonHandler):
> +    """
> +    Handler for key 'commutative'
> +    """
> +
> +    @staticmethod
> +    def Symbol(expr, assumptions):
> +        """Objects are expected to be commutative unless otherwise stated"""
> +        for assump in assumptions:
> +            if assump.expr == expr and assump.key == 'commutative':
> +                return assump.value
> +        return True
> +
> +    @staticmethod
> +    def Basic(expr, assumptions):
> +        for arg in expr.args:
> +            if not ask(arg, Q.commutative, assumptions):
> +                return False
> +        return True
> +
> +    @staticmethod
> +    def Number(expr, assumptions):
> +        return True
> +
> +    @staticmethod
> +    def NaN(expr, assumptions):
> +        return True
> diff --git a/sympy/queries/handlers/calculus.py b/sympy/queries/handlers/calculus.py
> new file mode 100644
> index 0000000..17449db
> --- /dev/null
> +++ b/sympy/queries/handlers/calculus.py
> @@ -0,0 +1,143 @@
> +"""
> +This module contains query handlers resposible for calculus queries:
> +infinitesimal, bounded, etc.
> +"""
> +from sympy.queries import Q, ask
> +from sympy.queries.handlers import CommonHandler
> +
> +class AskInfinitesimalHandler(CommonHandler):
> +    """
> +    Handler for key 'infinitesimal'
> +    Test that a given expression is equivalent to an infinitesimal
> +    number
> +    """
> +
> +    @staticmethod
> +    def _number(expr, assumptions):
> +        # helper method
> +        return expr.evalf() == 0
> +
> +    @staticmethod
> +    def Basic(expr, assumptions):
> +        if expr.is_number:
> +            return AskInfinitesimalHandler._number(expr, assumptions)
> +
> +    @staticmethod
> +    def Mul(expr, assumptions):
> +        """
> +        Infinitesimal*Bounded -> Infinitesimal
> +        """
> +        if expr.is_number:
> +            return AskInfinitesimalHandler._number(expr, assumptions)
> +        result = False
> +        for arg in expr.args:
> +            if ask(arg, Q.infinitesimal, assumptions):
> +                result = True
> +            elif ask(arg, Q.bounded, assumptions):
> +                continue
> +            else: break
> +        else:
> +            return result
> +
> +    Add, Pow = Mul, Mul
> +
> +    @staticmethod
> +    def Number(expr, assumptions):
> +        return expr == 0
> +
> +    NumberSymbol = Number
> +
> +    @staticmethod
> +    def ImaginaryUnit(expr, assumptions):
> +        return False
> +
> +
> +class AskBoundedHandler(CommonHandler):
> +    """
> +    Handler for key 'bounded'
> +    Test that an expression is bounded respect to all its variables
> +    """
> +
> +    @staticmethod
> +    def Symbol(expr, assumptions):
> +        for assump in assumptions:
> +            if assump.expr == expr and assump.key == 'bounded':
> +                return assump.value
> +        return False
> +
> +    @staticmethod
> +    def Add(expr, assumptions):
> +        """
> +        Bounded + Bounded     -> Bounded
> +        Unbounded + Bounded   -> Unbounded
> +        Unbounded + Unbounded -> ?
> +        """
> +        result = True
> +        for arg in expr.args:
> +            _bounded = ask(arg, Q.bounded, assumptions)
> +            if _bounded: continue
> +            elif _bounded is None: return
> +            elif _bounded is False:
> +                if result: result = False
> +                else: return
> +        return result
> +
> +    Mul = Add
> +
> +    @staticmethod
> +    def Pow(expr, assumptions):
> +        """
> +        Unbounded ** Whatever -> Unbounded
> +        Bounded ** Unbounded -> Unbounded if base > 1
> +        Bounded ** Unbounded -> Unbounded if base < 1
> +        """
> +        base_bounded = ask(expr.base, Q.bounded, assumptions)
> +        if not base_bounded: return base_bounded
> +        if ask(expr.exp, Q.bounded, assumptions) \
> +            and base_bounded: return True
> +        if base_bounded and expr.base.is_number:
> +            # We need to implement relations for this
> +            if abs(expr.base) > 1:
> +                return False
> +            return True
> +
> +    @staticmethod
> +    def log(expr, assumptions):
> +        return ask(expr.args[0], Q.bounded, assumptions)
> new file mode 100644
> index 0000000..772a9bd
> --- /dev/null
> +++ b/sympy/queries/handlers/ntheory.py
> @@ -0,0 +1,218 @@
> +"""
> +Handlers for keys related to number theory: prime, even, odd, etc.
> +"""
> +from sympy.queries import Q, ask
> +from sympy.queries.handlers import CommonHandler
> +from sympy.ntheory import isprime
> +
> +class AskPrimeHandler(CommonHandler):
> +    """
> +    Handler for key 'prime'
> +    Test that an expression represents a prime number
> +    """
> +
> +    @staticmethod
> +    def _number(expr, assumptions):
> +        # helper method
> +        if (expr.as_real_imag()[1] == 0) and int(expr.evalf()) == expr:
> +            return isprime(expr.evalf(1))
> +        return False
> +
> +    @staticmethod
> +    def Basic(expr, assumptions):
> +        # Just use int(expr) once
> +        # http://code.google.com/p/sympy/issues/detail?id=1462
> +        # is solved
> +        if expr.is_number:
> +            return AskPrimeHandler._number(expr, assumptions)
> +
> +    @staticmethod
> +    def Mul(expr, assumptions):
> +        if expr.is_number:
> +            return AskPrimeHandler._number(expr, assumptions)
> +        for arg in expr.args:
> +            if ask(arg, Q.integer, assumptions):
> +                pass
> +            else: break
> +        else:
> +            # a product of integers can't be a prime
> +            return False
> +
> +    @staticmethod
> +    def Pow(expr, assumptions):
> +        """
> +        Integer**Integer     -> !Prime
> +        """
> +        if expr.is_number:
> +            return AskPrimeHandler._number(expr, assumptions)
> +        if ask(expr.exp, Q.integer, assumptions) and \
> +                ask(expr.base, Q.integer, assumptions):
> +            return False
> +
> +    @staticmethod
> +    def Integer(expr, assumptions):
> +        return isprime(expr)
> +
> +    @staticmethod
> +    def Rational(expr, assumptions):
> +        return False
> +
> +    @staticmethod
> +    def Real(expr, assumptions):
> +        return AskPrimeHandler._number(expr, assumptions)
> +
> +    @staticmethod
> +    def Infinity(expr, assumptions):
> +        return False
> +
> +    @staticmethod
> +    def NegativeInfinity(expr, assumptions):
> +        return False
> +
> +    @staticmethod
> +    def ImaginaryUnit(expr, assumptions):
> +        return False
> +
> +    @staticmethod
> +    def NumberSymbol(expr, assumptions):
> +        return AskPrimeHandler._number(expr, assumptions)
> +
> +class AskCompositeHandler(CommonHandler):
> +
> +    @staticmethod
> +    def Basic(expr, assumptions):
> +        _positive = ask(expr, Q.positive, assumptions)
> +        if _positive:
> +            _integer = ask(expr, Q.integer, assumptions)
> +            if _integer:
> +                _prime = ask(expr, Q.prime, assumptions)
> +                if _prime is None: return
> +                return not _prime
> +            else: return _integer
> +        else: return _positive
> +
> +class AskEvenHandler(CommonHandler):
> +
> +    @staticmethod
> +    def _number(expr, assumptions):
> +        # helper method
> +        if (expr.as_real_imag()[1] == 0) and expr.evalf(1) == expr:
> +            return float(expr.evalf()) % 2 == 0
> +        else: return False
> +
> +    @staticmethod
> +    def Basic(expr, assumptions):
> +        if expr.is_number:
> +            return AskEvenHandler._number(expr, assumptions)
> +
> +    @staticmethod
> +    def Mul(expr, assumptions):
> +        """
> +        Even * Integer -> Even
> +        Even * Odd     -> Even
> +        Integer * Odd  -> ?
> +        Odd * Odd      -> Odd
> +        """
> +        if expr.is_number:
> +            return AskEvenHandler._number(expr, assumptions)
> +        even, odd, irrational = False, 0, False
> +        for arg in expr.args:
> +            # check for all integers and at least one even
> +            if ask(arg, Q.integer, assumptions):
> +                if ask(arg, Q.even, assumptions):
> +                    even = True
> +                elif ask(arg, Q.odd, assumptions):
> +                    odd += 1
> +            elif ask(arg, Q.irrational, assumptions):
> +                # one irrational makes the result False
> +                # two makes it undefined
> +                if irrational:
> +                    break
> +                irrational = True
> +            else: break
> +        else:
> +            if irrational: return False
> +            if even: return True
> +            if odd == len(expr.args): return False
> +
> +    @staticmethod
> +    def Add(expr, assumptions):
> +        """
> +        Even + Odd  -> Odd
> +        Even + Even -> Even
> +        Odd  + Odd  -> Even
> +
> +        TODO: remove float() when issue
> +        http://code.google.com/p/sympy/issues/detail?id=1473
> +        is solved
> +        """
> +        if expr.is_number:
> +            return AskEvenHandler._number(expr, assumptions)
> +        _result = True
> +        for arg in expr.args:
> +            if ask(arg, Q.even, assumptions):
> +                pass
> +            elif ask(arg, Q.odd, assumptions):
> +        return AskEvenHandler._number(expr, assumptions)
> +
> +    @staticmethod
> +    def ImaginaryUnit(expr, assumptions):
> +        return False
> +
> +    @staticmethod
> +    def abs(expr, assumptions):
> +        if ask(expr.args[0], Q.real, assumptions):
> +            return ask(expr.args[0], Q.even, assumptions)
> +
> +    @staticmethod
> +    def re(expr, assumptions):
> +        if ask(expr.args[0], Q.real, assumptions):
> +            return ask(expr.args[0], Q.even, assumptions)
> +
> +    @staticmethod
> +    def im(expr, assumptions):
> +        if ask(expr.args[0], Q.real, assumptions):
> +            return True
> +
> +class AskOddHandler(CommonHandler):
> +    """
> +    Handler for key 'odd'
> +    Test that an expression represents an odd number
> +    """
> +
> +    @staticmethod
> +    def Basic(expr, assumptions):
> +        _integer = ask(expr, Q.integer, assumptions)
> +        if _integer:
> +            _even = ask(expr, Q.even, assumptions)
> +            if _even is None: return None
> +            return not _even
> +        return _integer
> +
> diff --git a/sympy/queries/handlers/order.py b/sympy/queries/handlers/order.py
> new file mode 100644
> index 0000000..5b3a976
> --- /dev/null
> +++ b/sympy/queries/handlers/order.py
> @@ -0,0 +1,175 @@
> +"""
> +AskHandlers related to order relations: positive, negative, etc.
> +"""
> +from sympy.queries import Q, ask
> +from sympy.queries.handlers import CommonHandler
> +
> +
> +class AskNegativeHandler(CommonHandler):
> +    """
> +    Handler for key 'negative'
> +    Test that an expression is less (strict) than zero
> +    """
> +
> +    @staticmethod
> +    def _number(expr, assumptions):
> +        if not expr.as_real_imag()[1]:
> +            return expr.evalf() < 0
> +        else: return False
> +
> +    @staticmethod
> +    def Basic(expr, assumptions):
> +        if expr.is_number:
> +            return AskNegativeHandler._number(expr, assumptions)
> +
> +    @staticmethod
> +    def Add(expr, assumptions):
> +        """
> +        Positive + Positive -> Positive,
> +        Negative + Negative -> Negative
> +        """
> +        if expr.is_number:
> +            return AskNegativeHandler._number(expr, assumptions)
> +        for arg in expr.args:
> +            if not ask(arg, Q.negative, assumptions):
> +                break
> +        else:
> +            # if all argument's are negative
> +            return True
> +
> +    @staticmethod
> +    def Mul(expr, assumptions):
> +        if expr.is_number:
> +            return AskNegativeHandler._number(expr, assumptions)
> +        result = None
> +        for arg in expr.args:
> +            if result is None: result = False
> +            if ask(arg, Q.negative, assumptions):
> +                result = not result
> +            elif ask(arg, Q.positive, assumptions):
> +                pass
> +            else: return
> +        return result
> +
> +    @staticmethod
> +    def Pow(expr, assumptions):
> +        if expr.is_number:
> +            return AskNegativeHandler._number(expr, assumptions)
> +        if ask(expr.base, Q.negative, assumptions):
> +            if ask(expr.exp, Q.odd, assumptions):
> +                return True
> +            if ask(expr.exp, Q.even, assumptions):
> +                return False
> +        elif ask(expr.base, Q.positive, assumptions):
> +            if ask(expr.exp, Q.real, assumptions):
> +                return False
> +
> +    @staticmethod
> +    def ImaginaryUnit(expr, assumptions):
> +        return False
> +
> +    @staticmethod
> +    def abs(expr, assumptions):
> +        return False
> +
> +class AskNonZeroHandler(CommonHandler):
> +    """
> +    Handler for key 'zero'
> +    Test that an expression is not identically zero
> +    """
> +
> +    @staticmethod
> +    def Basic(expr, assumptions):
> +        if expr.is_number:
> +            # if there are no symbols just evalf
> +            return expr.evalf() != 0
> +
> +    @staticmethod
> +    def Add(expr, assumptions):
> +        if all([ask(x, Q.positive, assumptions) for x in expr.args]) \
> +            or all([ask(x, Q.negative, assumptions) for x in expr.args]):
> +            return True
> +
> +    @staticmethod
> +    def Mul(expr, assumptions):
> +        for arg in expr.args:
> +            result = ask(arg, Q.nonzero, assumptions)
> +            if result: continue
> +            return result
> +        return True
> +
> +    @staticmethod
> +    def Pow(expr, assumptions):
> +        return ask(expr.base, Q.nonzero, assumptions)
> +
> +    @staticmethod
> +    def NaN(expr, assumptions):
> +        return True
> +
> +    @staticmethod
> +    def abs(expr, assumptions):
> +        return ask(expr.args[0], Q.nonzero, assumptions)
> +
> +class AskPositiveHandler(CommonHandler):
> +    """
> +    Handler for key 'positive'
> +    Test that an expression is greater (strict) than zero
> +    """
> +
> +    @staticmethod
> +    def _number(expr, assumptions):
> +        if not expr.as_real_imag()[1]:
> +            return expr.evalf() > 0
> +        else: return False
> +
> +    @staticmethod
> +    def Basic(expr, assumptions):
> +        if expr.is_number:
> +            return AskPositiveHandler._number(expr, assumptions)
> +
> +    @staticmethod
> +    def Mul(expr, assumptions):
> +        if expr.is_number:
> +            return AskPositiveHandler._number(expr, assumptions)
> +        result = True
> +        for arg in expr.args:
> +            if ask(arg, Q.positive, assumptions): continue
> +            elif ask(arg, Q.negative, assumptions):
> +                result = result ^ True
> +            else: return
> +        return result
> +
> +    @staticmethod
> +    def Add(expr, assumptions):
> +        if expr.is_number:
> +            return AskPositiveHandler._number(expr, assumptions)
> +        for arg in expr.args:
> +            if ask(arg, Q.positive, assumptions) is not True:
> +                break
> +        else:
> +            # if all argument's are positive
> +            return True
> +
> +    @staticmethod
> +    def Pow(expr, assumptions):
> +        if expr.is_number: return expr.evalf() > 0
> +        if ask(expr.base, Q.positive, assumptions):
> +            return True
> +        if ask(expr.base, Q.negative, assumptions):
> +            if ask(expr.exp, Q.even, assumptions):
> +                return True
> +            if ask(expr.exp, Q.even, assumptions):
> +                return False
> +
> +    @staticmethod
> +    def exp(expr, assumptions):
> +        if ask(expr.args[0], Q.real, assumptions):
> +            return True
> +
> +    @staticmethod
> +    def ImaginaryUnit(expr, assumptions):
> +        return False
> +
> +    @staticmethod
> +    def abs(expr, assumptions):
> +        return ask(expr, Q.nonzero, assumptions)
> diff --git a/sympy/queries/handlers/sets.py b/sympy/queries/handlers/sets.py
> new file mode 100644
> index 0000000..23de759
> --- /dev/null
> +++ b/sympy/queries/handlers/sets.py
> @@ -0,0 +1,427 @@
> +"""
> +Handlers for keys related to set membership: integer, rational, etc.
> +"""
> +from sympy.queries import Q, ask
> +from sympy.queries.handlers import CommonHandler
> +
> +class AskIntegerHandler(CommonHandler):
> +    """
> +    Handler for key 'integer'
> +    Test that an expression belongs to the field of integer numbers
> +    """
> +
> +    @staticmethod
> +    def _number(expr, assumptions):
> +        # helper method
> +        if expr.as_real_imag()[1] == 0:
> +            return expr.evalf(1) == expr
> +        return False
> +
> +    @staticmethod
> +    def Add(expr, assumptions):
> +        """
> +        Integer + Integer       -> Integer
> +        Integer + !Integer      -> !Integer
> +        !Integer + !Integer -> ?
> +        """
> +        if expr.is_number:
> +            return AskIntegerHandler._number(expr, assumptions)
> +        return test_closed_group(expr, assumptions, 'integer')
> +
> +    @staticmethod
> +    def Mul(expr, assumptions):
> +        """
> +        Integer*Integer      -> Integer
> +        Integer*Irrational   -> !Integer
> +        Odd/Even             -> !Integer
> +        Integer*Rational     -> ?
> +        """
> +        if expr.is_number:
> +            return AskIntegerHandler._number(expr, assumptions)
> +        _output = True
> +        for arg in expr.args:
> +            if not ask(arg, Q.integer, assumptions):
> +                if arg.is_Rational:
> +                    if arg.q == 2:
> +                        return ask(2*expr, Q.even, assumptions)
> +                    if arg.q % 2 == 1:
> +                        return None
> +                elif ask(arg, Q.irrational, assumptions):
> +        return ask(expr.args[0], Q.integer, assumptions)
> +
> +class AskRationalHandler(CommonHandler):
> +    """
> +    Handler for key 'rational'
> +    Test that an expression belongs to the field of rational numbers
> +    """
> +
> +    @staticmethod
> +    def Add(expr, assumptions):
> +        """
> +        Rational + Rational     -> Rational
> +        Rational + !Rational    -> !Rational
> +        !Rational + !Rational   -> ?
> +        """
> +        if expr.is_number:
> +            if expr.as_real_imag()[1]:
> +                return False
> +        return test_closed_group(expr, assumptions, 'rational')
> +
> +    Mul = Add
> +
> +    @staticmethod
> +    def Pow(expr, assumptions):
> +        """
> +        Rational ** Integer      -> Rational
> +        Irrational ** Rational   -> Irrational
> +        Rational ** Irrational   -> ?
> +        """
> +        if ask(expr.exp, Q.integer, assumptions):
> +            return ask(expr.base, Q.rational, assumptions)
> +        elif ask(expr.exp, Q.rational, assumptions):
> +            if ask(expr.base, Q.prime, assumptions):
> +                return False
> +
> +    @staticmethod
> +class AskIrrationalHandler(CommonHandler):
> +
> +    @staticmethod
> +    def Basic(expr, assumptions):
> +        _real = ask(expr, Q.real, assumptions)
> +        if _real:
> +            _rational = ask(expr, Q.rational, assumptions)
> +            if _rational is None: return None
> +            return not _rational
> +        else: return _real
> +
> +class AskRealHandler(CommonHandler):
> +    """
> +    Handler for key 'real'
> +    Test that an expression belongs to the field of real numbers
> +    """
> +
> +    @staticmethod
> +    def _number(expr, assumptions):
> +        return not expr.as_real_imag()[1]
> +
> +    @staticmethod
> +    def Add(expr, assumptions):
> +        """
> +        Real + Real              -> Real
> +        Real + (Complex & !Real) -> !Real
> +        """
> +        if expr.is_number:
> +            return AskRealHandler._number(expr, assumptions)
> +        return test_closed_group(expr, assumptions, 'real')
> +
> +    @staticmethod
> +    def Mul(expr, assumptions):
> +        """
> +        Real*Real               -> Real
> +        Real*Imaginary          -> !Real
> +        Imaginary*Imaginary     -> Real
> +        """
> +        if expr.is_number:
> +            return AskRealHandler._number(expr, assumptions)
> +        result = True
> +        for arg in expr.args:
> +            if ask(arg, Q.real, assumptions):
> +                pass
> +            elif ask(arg, Q.imaginary, assumptions):
> +                result = result ^ True
> +            else:
> +                break
> +        else:
> +            return result
> +
> +    @staticmethod
> +    def Pow(expr, assumptions):
> +        """
> +        Real**Integer         -> Real
> +        Positive**Real        -> Real
> +        Real**(Integer/Even)  -> Real if base is nonnegative
> +        Real**(Integer/Odd)   -> Real
> +        """
> +        if expr.is_number:
> +            return AskRealHandler._number(expr, assumptions)
> +        if ask(expr.base, Q.real, assumptions):
> +            if ask(expr.exp, Q.integer, assumptions):
> +                return True
> +            elif expr.exp.is_Rational:
> +                if (expr.exp.q % 2 == 0):
> +                    return ask(expr.base, Q.real, assumptions) and \
> +                       not ask(expr.base, Q.negative, assumptions)
> +                else: return True
> +            elif ask(expr.exp, Q.real, assumptions):
> +                if ask(expr.base, Q.positive, assumptions):
> +                    return True
> +
> +    @staticmethod
> +    def Rational(expr, assumptions):
> +        if ask(expr.args[0], Q.real, assumptions):
> +            return True
> +
> +    cos, exp = sin, sin
> +
> +class AskExtendedRealHandler(AskRealHandler):
> +    """
> +    Handler for key 'extended_real'
> +    Test that an expression belongs to the field of extended real numbers,
> +    that is real numbers union {Infinity, -Infinity}
> +    """
> +
> +    @staticmethod
> +    def Add(expr, assumptions):
> +        return test_closed_group(expr, assumptions, 'extended_real')
> +
> +    Mul, Pow = Add, Add
> +
> +    @staticmethod
> +    def Infinity(expr, assumptions):
> +        return True
> +
> +    @staticmethod
> +    def NegativeInfinity(expr, assumptions):
> +        return True
> +
> +class AskComplexHandler(CommonHandler):
> +class AskImaginaryHandler(CommonHandler):
> +    """
> +    Handler for key 'imaginary'
> +    Test that an expression belongs to the field of imaginary numbers,
> +    that is, numbers in the form x*I, where x is real
> +    """
> +
> +    @staticmethod
> +    def _number(expr, assumptions):
> +        # helper method
> +        return not expr.as_real_imag()[0]
> +
> +    @staticmethod
> +    def Add(expr, assumptions):
> +        """
> +        Imaginary + Imaginary -> Imaginary
> +        Imaginary + Complex   -> ?
> +        Imaginary + Real      -> !Imaginary
> +        """
> +        if expr.is_number:
> +            return AskImaginaryHandler._number(expr, assumptions)
> +        reals = 0
> +        for arg in expr.args:
> +            if ask(arg, Q.imaginary, assumptions):
> +                pass
> +            elif ask(arg, Q.real, assumptions):
> +                reals += 1
> +            else:
> +                break
> +        else:
> +            if reals == 0:
> +                return True
> +            if reals == 1 or (len(expr.args) == reals):
> +                # two reals could sum 0 thus giving an imaginary
> +                return False
> +
> +    @staticmethod
> +    def Mul(expr, assumptions):
> +        """
> +        Real*Imaginary      -> Imaginary
> +        Imaginary*Imaginary -> Real
> +        """
> +        if expr.is_number:
> +            return AskImaginaryHandler._number(expr, assumptions)
> +        result = False
> +        reals = 0
> +        for arg in expr.args:
> +            if ask(arg, Q.imaginary, assumptions):
> +                result = result ^ True
> +            elif not ask(arg, Q.real, assumptions):
> +                break
> +        else:
> +            if reals == len(expr.args):
> +                return False
> +            return result
> +
> +    Pow = Add
> +
> +    @staticmethod
> +    def Number(expr, assumptions):
> +        return not (expr.as_real_imag()[1] == 0)
> +
> +    NumberSymbol = Number
> +
> +    @staticmethod
> +    def ImaginaryUnit(expr, assumptions):
> +        return True
> +
> +
> +#### Helper methods
> +
> +def test_closed_group(expr, assumptions, key):
> +    """
> +    Test for membership in a group with respect
> +    to the current operation
> +    """
> +    result = True
> +    for arg in expr.args:
> +        _out = ask(arg, key, assumptions)
> +        if _out is None: break
> +        elif _out is False:
> +            if result: result = False
> +            else: break
> +    else:
> +        return result
> +
> diff --git a/sympy/queries/tests/test_query.py b/sympy/queries/tests/test_query.py
> new file mode 100644
> index 0000000..8c6bf9b
> --- /dev/null
> +++ b/sympy/queries/tests/test_query.py
> @@ -0,0 +1,957 @@
> +from sympy.core import Symbol, symbols, S, Rational, Integer
> +from sympy.functions import exp, log, sin, cos, sign, re, im, sqrt
> +from sympy.assumptions import Assume, register_global_assumptions, \
> +    clean_global_assumptions
> +from sympy.queries import Q, ask, register_handler, remove_handler
> +from sympy.queries.handlers import AskHandler
> +from sympy.utilities.pytest import raises, XFAIL
> +
> +def test_int_1():
> +    z = 1
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == True
> +    assert ask(z, Q.rational)         == True
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == False
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == True
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == True
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == True
> +
> +def test_float_1():
> +    z = 1.0
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == True
> +    assert ask(z, Q.rational)         == True
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == False
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == True
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == True
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == True
> +
> +    z = 7.2123
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == False
> +    assert ask(z, Q.rational)         == True
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == False
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == True
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +def test_zero_0():
> +    z = Integer(0)
> +    assert ask(z, Q.nonzero)          == False
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == True
> +    assert ask(z, Q.rational)         == True
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == False
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == True
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == True
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +def test_negativeone():
> +    z = Integer(-1)
> +    assert ask(z, Q.nonzero)          == True
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == True
> +    assert ask(z, Q.rational)         == True
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == False
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == False
> +    assert ask(z, Q.negative)         == True
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == True
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +def test_infinity():
> +    oo = S.Infinity
> +    assert ask(oo, Q.commutative)     == True
> +    assert ask(oo, Q.integer)         == False
> +    assert ask(oo, Q.rational)        == False
> +    assert ask(oo, Q.real)            == False
> +    assert ask(oo, Q.extended_real)   == True
> +    assert ask(oo, Q.complex)         == False
> +    assert ask(oo, Q.irrational)      == False
> +    assert ask(oo, Q.imaginary)       == False
> +    assert ask(oo, Q.positive)        == True
> +    assert ask(oo, Q.negative)        == False
> +    assert ask(oo, Q.even)            == False
> +    assert ask(oo, Q.odd)             == False
> +    assert ask(oo, Q.bounded)         == False
> +    assert ask(oo, Q.infinitesimal)   == False
> +    assert ask(oo, Q.prime)           == False
> +    assert ask(oo, Q.composite)       == False
> +
> +def test_neg_infinity():
> +    mm = S.NegativeInfinity
> +    assert ask(mm, Q.commutative)    == True
> +    assert ask(mm, Q.integer)        == False
> +    assert ask(mm, Q.rational)       == False
> +    assert ask(mm, Q.real)           == False
> +    assert ask(mm, Q.extended_real)  == True
> +    assert ask(mm, Q.complex)        == False
> +    assert ask(mm, Q.irrational)     == False
> +    assert ask(mm, Q.imaginary)      == False
> +    assert ask(mm, Q.positive)       == False
> +    assert ask(mm, Q.negative)       == True
> +    assert ask(mm, Q.even)           == False
> +    assert ask(mm, Q.odd)            == False
> +    assert ask(mm, Q.bounded)        == False
> +    assert ask(mm, Q.infinitesimal)  == False
> +    assert ask(mm, Q.prime)          == False
> +    assert ask(mm, Q.composite)      == False
> +
> +def test_nan():
> +    nan = S.NaN
> +    assert ask(nan, Q.commutative)   == True
> +    assert ask(nan, Q.integer)       == False
> +    assert ask(nan, Q.rational)      == False
> +    assert ask(nan, Q.real)          == False
> +    assert ask(nan, Q.extended_real) == False
> +    assert ask(nan, Q.complex)       == False
> +    assert ask(nan, Q.irrational)    == False
> +    assert ask(nan, Q.imaginary)     == False
> +    assert ask(nan, Q.positive)      == False
> +    assert ask(nan, Q.nonzero)       == True
> +    assert ask(nan, Q.even)          == False
> +    assert ask(nan, Q.odd)           == False
> +    assert ask(nan, Q.bounded)       == False
> +    assert ask(nan, Q.infinitesimal) == False
> +    assert ask(nan, Q.prime)         == False
> +    assert ask(nan, Q.composite)     == False
> +
> +def test_Rational_number():
> +    r = Rational(3,4)
> +    assert ask(r, Q.commutative)      == True
> +    assert ask(r, Q.integer)          == False
> +    assert ask(r, Q.rational)         == True
> +    assert ask(r, Q.real)             == True
> +    assert ask(r, Q.complex)          == True
> +    assert ask(r, Q.irrational)       == False
> +    assert ask(r, Q.imaginary)        == False
> +    assert ask(r, Q.positive)         == True
> +    assert ask(r, Q.negative)         == False
> +    assert ask(r, Q.even)             == False
> +    assert ask(r, Q.odd)              == False
> +    assert ask(r, Q.bounded)          == True
> +    assert ask(r, Q.infinitesimal)    == False
> +    assert ask(r, Q.prime)            == False
> +    assert ask(r, Q.composite)        == False
> +
> +    r = Rational(1,4)
> +    assert ask(r, Q.positive)         == True
> +    assert ask(r, Q.negative)         == False
> +
> +    r = Rational(5,4)
> +    assert ask(r, Q.negative)         == False
> +    assert ask(r, Q.positive)         == True
> +
> +    r = Rational(5,3)
> +    assert ask(r, Q.positive)         == True
> +    assert ask(r, Q.negative)         == False
> +
> +    r = Rational(-3,4)
> +    assert ask(r, Q.positive)         == False
> +    assert ask(r, Q.negative)         == True
> +
> +    r = Rational(-1,4)
> +    assert ask(r, Q.positive)         == False
> +    assert ask(r, Q.negative)         == True
> +
> +    r = Rational(-5,4)
> +    assert ask(r, Q.negative)         == True
> +    assert ask(r, Q.positive)         == False
> +
> +    r = Rational(-5,3)
> +    assert ask(r, Q.positive)         == False
> +    assert ask(r, Q.negative)         == True
> +
> +def test_sqrt_2():
> +    z = sqrt(2)
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == False
> +    assert ask(z, Q.rational)         == False
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == True
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == True
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +def test_pi():
> +    z = S.Pi
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == False
> +    assert ask(z, Q.rational)         == False
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == True
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == True
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +    z = S.Pi + 1
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == False
> +    assert ask(z, Q.rational)         == False
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == True
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == True
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +    z = 2*S.Pi
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == False
> +    assert ask(z, Q.rational)         == False
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == True
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == True
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +    z = S.Pi ** 2
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == False
> +    assert ask(z, Q.rational)         == False
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == True
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == True
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +    z = (1+S.Pi) ** 2
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == False
> +    assert ask(z, Q.rational)         == False
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == True
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == True
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +def test_E():
> +    z = S.Exp1
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == False
> +    assert ask(z, Q.rational)         == False
> +    assert ask(z, Q.real)             == True
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == True
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == True
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +def test_I():
> +    I = S.ImaginaryUnit
> +    z = I
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == False
> +    assert ask(z, Q.rational)         == False
> +    assert ask(z, Q.real)             == False
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == False
> +    assert ask(z, Q.imaginary)        == True
> +    assert ask(z, Q.positive)         == False
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +    z = 1 + I
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == False
> +    assert ask(z, Q.rational)         == False
> +    assert ask(z, Q.real)             == False
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == False
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == False
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +    z = I*(1+I)
> +    assert ask(z, Q.commutative)      == True
> +    assert ask(z, Q.integer)          == False
> +    assert ask(z, Q.rational)         == False
> +    assert ask(z, Q.real)             == False
> +    assert ask(z, Q.complex)          == True
> +    assert ask(z, Q.irrational)       == False
> +    assert ask(z, Q.imaginary)        == False
> +    assert ask(z, Q.positive)         == False
> +    assert ask(z, Q.negative)         == False
> +    assert ask(z, Q.even)             == False
> +    assert ask(z, Q.odd)              == False
> +    assert ask(z, Q.bounded)          == True
> +    assert ask(z, Q.infinitesimal)    == False
> +    assert ask(z, Q.prime)            == False
> +    assert ask(z, Q.composite)        == False
> +
> +def test_bounded():
> +    x, y = symbols('xy')
> +    assert ask(x, Q.bounded) == False
> +    assert ask(x, Q.bounded, Assume(x, Q.bounded)) == True
> +    assert ask(x, Q.bounded, Assume(y, Q.bounded)) == False
> +    assert ask(x, Q.bounded, Assume(x, Q.complex)) == False
> +
> +    assert ask(x+1, Q.bounded) == False
> +    assert ask(x+1, Q.bounded, Assume(x, Q.bounded)) == True
> +    assert ask(x+y, Q.bounded) == None
> +    assert ask(x+y, Q.bounded, Assume(x, Q.bounded)) == False
> +    assert ask(x+1, Q.bounded, Assume(x, Q.bounded) & \
> +                Assume(y, Q.bounded)) == True
> +
> +    assert ask(2*x, Q.bounded) == False
> +    assert ask(2*x, Q.bounded, Assume(x, Q.bounded)) == True
> +    assert ask(x*y, Q.bounded) == None
> +    assert ask(x*y, Q.bounded, Assume(x, Q.bounded)) == False
> +    assert ask(x*y, Q.bounded, Assume(x, Q.bounded) & \
> +                Assume(y, Q.bounded)) == True
> +
> +    assert ask(x**2, Q.bounded) == False
> +    assert ask(2**x, Q.bounded) == False
> +    assert ask(2**x, Q.bounded, Assume(x, Q.bounded)) == True
> +    assert ask(x**x, Q.bounded) == False
> +    assert ask(Rational(1,2) ** x, Q.bounded) == True
> +    assert ask(x ** Rational(1,2), Q.bounded) == False
> +
> +    # sign function
> +    assert ask(sign(x), Q.bounded) == True
> +    assert ask(sign(x), Q.bounded, Assume(x, Q.bounded, False)) == True
> +
> +    # exponential functions
> +    assert ask(log(x), Q.bounded) == False
> +    assert ask(log(x), Q.bounded, Assume(x, Q.bounded)) == True
> +    assert ask(exp(x), Q.bounded) == False
> +    assert ask(exp(x), Q.bounded, Assume(x, Q.bounded)) == True
> +    assert ask(exp(2), Q.bounded) == True
> +
> +    # trigonometric functions
> +    assert ask(sin(x), Q.bounded) == True
> +    assert ask(sin(x), Q.bounded, Assume(x, Q.bounded, False)) == True
> +    assert ask(cos(x), Q.bounded) == True
> +    assert ask(cos(x), Q.bounded, Assume(x, Q.bounded, False)) == True
> +    assert ask(2*sin(x), Q.bounded) == True
> +    assert ask(sin(x)**2, Q.bounded) == True
> +    assert ask(cos(x)**2, Q.bounded) == True
> +    assert ask(cos(x) + sin(x), Q.bounded) == True
> +
> +@XFAIL
> +def test_bounded_xfail():
> +    """We need to support relations in ask for this to work"""
> +    x = Symbol('x')
> +    assert ask(sin(x)**x, Q.bounded) == True
> +    assert ask(cos(x)**x, Q.bounded) == True
> +    assert ask(sin(x) ** x, Q.bounded) == True
> +
> +def test_commutative():
> +    """By default objects are Q.commutative that is why it returns True
> +    for both key=True and key=False"""
> +    x, y = symbols('xy')
> +    assert ask(x, Q.commutative) == True
> +    assert ask(x, Q.commutative, Assume(x, Q.commutative, False)) == False
> +    assert ask(x, Q.commutative, Assume(x, Q.complex)) == True
> +    assert ask(x, Q.commutative, Assume(x, Q.imaginary)) == True
> +    assert ask(x, Q.commutative, Assume(x, Q.real)) == True
> +    assert ask(x, Q.commutative, Assume(x, Q.positive)) == True
> +    assert ask(x, Q.commutative, Assume(y, Q.commutative, False))  == True
> +
> +    assert ask(2*x, Q.commutative) == True
> +    assert ask(2*x, Q.commutative, Assume(x, Q.commutative, False)) == False
> +
> +    assert ask(x + 1, Q.commutative) == True
> +    assert ask(x + 1, Q.commutative, Assume(x, Q.commutative, False)) == False
> +
> +    assert ask(x**2, Q.commutative) == True
> +    assert ask(x**2, Q.commutative, Assume(x, Q.commutative, False)) == False
> +
> +    assert ask(log(x), Q.commutative) == True
> +
> +def test_complex():
> +    x, y = symbols('xy')
> +    assert ask(x, Q.complex) == None
> +    assert ask(x, Q.complex, Assume(x, Q.complex)) == True
> +    assert ask(x, Q.complex, Assume(y, Q.complex)) == None
> +    assert ask(x, Q.complex, Assume(x, Q.complex, False)) == False
> +    assert ask(x, Q.complex, Assume(x, Q.real)) == True
> +    assert ask(x, Q.complex, Assume(x, Q.real, False)) == None
> +    assert ask(x, Q.complex, Assume(x, Q.rational)) == True
> +    assert ask(x, Q.complex, Assume(x, Q.irrational)) == True
> +    assert ask(x, Q.complex, Assume(x, Q.positive)) == True
> +    assert ask(x, Q.complex, Assume(x, Q.imaginary)) == True
> +
> +    # a+b
> +    assert ask(x+1, Q.complex, Assume(x, Q.complex)) == True
> +    assert ask(x+1, Q.complex, Assume(x, Q.real)) == True
> +    assert ask(x+1, Q.complex, Assume(x, Q.rational)) == True
> +    assert ask(x+1, Q.complex, Assume(x, Q.irrational)) == True
> +    assert ask(x+1, Q.complex, Assume(x, Q.imaginary)) == True
> +    assert ask(x+1, Q.complex, Assume(x, Q.integer))  == True
> +    assert ask(x+1, Q.complex, Assume(x, Q.even))  == True
> +    assert ask(x+1, Q.complex, Assume(x, Q.odd))  == True
> +    assert ask(x+y, Q.complex, Assume(x, Q.complex) & Assume(y, Q.complex)) == True
> +    assert ask(x+y, Q.complex, Assume(x, Q.real) & Assume(y, Q.imaginary)) == True
> +
> +    # a*x +b
> +    assert ask(2*x+1, Q.complex, Assume(x, Q.complex)) == True
> +    assert ask(2*x+1, Q.complex, Assume(x, Q.real)) == True
> +    assert ask(2*x+1, Q.complex, Assume(x, Q.positive)) == True
> +    assert ask(2*x+1, Q.complex, Assume(x, Q.rational)) == True
> +    assert ask(2*x+1, Q.complex, Assume(x, Q.irrational)) == True
> +    assert ask(2*x+1, Q.complex, Assume(x, Q.imaginary)) == True
> +    assert ask(2*x+1, Q.complex, Assume(x, Q.integer))  == True
> +    assert ask(2*x+1, Q.complex, Assume(x, Q.even))  == True
> +    assert ask(2*x+1, Q.complex, Assume(x, Q.odd))  == True
> +
> +    # x**2
> +    assert ask(x**2, Q.complex, Assume(x, Q.complex)) == True
> +    assert ask(x**2, Q.complex, Assume(x, Q.real)) == True
> +    assert ask(x**2, Q.complex, Assume(x, Q.positive)) == True
> +    assert ask(x**2, Q.complex, Assume(x, Q.rational)) == True
> +    assert ask(x**2, Q.complex, Assume(x, Q.irrational)) == True
> +    assert ask(x**2, Q.complex, Assume(x, Q.imaginary)) == True
> +    assert ask(x**2, Q.complex, Assume(x, Q.integer))  == True
> +    assert ask(x**2, Q.complex, Assume(x, Q.even))  == True
> +    assert ask(x**2, Q.complex, Assume(x, Q.odd))  == True
> +
> +    # 2**x
> +    assert ask(2**x, Q.complex, Assume(x, Q.complex)) == True
> +    assert ask(2**x, Q.complex, Assume(x, Q.real)) == True
> +    assert ask(2**x, Q.complex, Assume(x, Q.positive)) == True
> +    assert ask(2**x, Q.complex, Assume(x, Q.rational)) == True
> +    assert ask(2**x, Q.complex, Assume(x, Q.irrational)) == True
> +    assert ask(2**x, Q.complex, Assume(x, Q.imaginary)) == True
> +    assert ask(2**x, Q.complex, Assume(x, Q.integer))  == True
> +    assert ask(2**x, Q.complex, Assume(x, Q.even))  == True
> +    assert ask(2**x, Q.complex, Assume(x, Q.odd))  == True
> +    assert ask(x**y, Q.complex, Assume(x, Q.complex) & \
> +                     Assume(y, Q.complex)) == True
> +
> +    # trigonometric expressions
> +    assert ask(sin(x), Q.complex) == True
> +    assert ask(sin(2*x + 1), Q.complex) == True
> +    assert ask(cos(x), Q.complex) == True
> +    assert ask(cos(2*x+1), Q.complex) == True
> +
> +    # exponential
> +    assert ask(exp(x), Q.complex) == True
> +    assert ask(exp(x), Q.complex) == True
> +
> +    # Q.complexes
> +    assert ask(abs(x), Q.complex) == True
> +    assert ask(re(x),  Q.complex) == True
> +    assert ask(im(x),  Q.complex) == True
> +
> +def test_even():
> +    x, y, z, t = symbols('x y z t')
> +    assert ask(x, Q.even) == None
> +    assert ask(x, Q.even, Assume(x, Q.integer)) == None
> +    assert ask(x, Q.even, Assume(x, Q.integer, False)) == False
> +    assert ask(x, Q.even, Assume(x, Q.rational)) == None
> +    assert ask(x, Q.even, Assume(x, Q.positive)) == None
> +
> +    assert ask(2*x, Q.even) == None
> +    assert ask(2*x, Q.even, Assume(x, Q.integer)) == True
> +    assert ask(2*x, Q.even, Assume(x, Q.even)) == True
> +    assert ask(2*x, Q.even, Assume(x, Q.irrational)) == False
> +    assert ask(2*x, Q.even, Assume(x, Q.odd)) == True
> +    assert ask(2*x, Q.even, Assume(x, Q.integer, False)) == None
> +    assert ask(3*x, Q.even, Assume(x, Q.integer)) == None
> +    assert ask(3*x, Q.even, Assume(x, Q.even)) == True
> +    assert ask(3*x, Q.even, Assume(x, Q.odd)) == False
> +
> +    assert ask(x+1, Q.even, Assume(x, Q.odd)) == True
> +    assert ask(x+1, Q.even, Assume(x, Q.even)) == False
> +    assert ask(x+2, Q.even, Assume(x, Q.odd)) == False
> +    assert ask(x+2, Q.even, Assume(x, Q.even)) == True
> +    assert ask(7-x, Q.even, Assume(x, Q.odd)) == True
> +    assert ask(7+x, Q.even, Assume(x, Q.odd)) == True
> +    assert ask(x+y, Q.even, Assume(x, Q.odd) & Assume(y, Q.odd)) == True
> +    assert ask(x+y, Q.even, Assume(x, Q.odd) & Assume(y, Q.even)) == False
> +    assert ask(x+y, Q.even, Assume(x, Q.even) & Assume(y, Q.even)) == True
> +
> +    assert ask(2*x + 1, Q.even, Assume(x, Q.integer)) == False
> +    assert ask(2*x*y, Q.even, Assume(x, Q.rational) & Assume(x, Q.rational)) == None
> +    assert ask(2*x*y, Q.even, Assume(x, Q.irrational) & Assume(x, Q.irrational)) == None
> +
> +    assert ask(x+y+z, Q.even, Assume(x, Q.odd) & Assume(y, Q.odd) & \
> +                     Assume(z, Q.even)) == True
> +    assert ask(x+y+z+t, Q.even, Assume(x, Q.odd) & Assume(y, Q.odd) & \
> +                     Assume(z, Q.even) & Assume(t, Q.integer)) == None
> +
> +    assert ask(abs(x), Q.even, Assume(x, Q.even)) == True
> +    assert ask(abs(x), Q.even, Assume(x, Q.even, False)) == None
> +    assert ask(re(x),  Q.even, Assume(x, Q.even)) == True
> +    assert ask(re(x),  Q.even, Assume(x, Q.even, False)) == None
> +    assert ask(im(x),  Q.even, Assume(x, Q.even)) == True
> +    assert ask(im(x),  Q.even, Assume(x, Q.real)) == True
> +
> +def test_xtended_real():
> +    x = symbols('x')
> +    assert ask(x, Q.extended_real, Assume(x, Q.positive)) == True
> +    assert ask(-x, Q.extended_real, Assume(x, Q.positive)) == True
> +    assert ask(-x, Q.extended_real, Assume(x, Q.negative)) == True
> +
> +    assert ask(x+S.Infinity, Q.extended_real, Assume(x, Q.real)) == True
> +
> +def test_rational():
> +    x, y = symbols('xy')
> +    assert ask(x, Q.rational, Assume(x, Q.integer)) == True
> +    assert ask(x, Q.rational, Assume(x, Q.irrational)) == False
> +    assert ask(x, Q.rational, Assume(x, Q.real)) == None
> +    assert ask(x, Q.rational, Assume(x, Q.positive)) == None
> +    assert ask(x, Q.rational, Assume(x, Q.negative)) == None
> +    assert ask(x, Q.rational, Assume(x, Q.nonzero)) == None
> +
> +    assert ask(2*x, Q.rational, Assume(x, Q.rational)) == True
> +    assert ask(2*x, Q.rational, Assume(x, Q.integer)) == True
> +    assert ask(2*x, Q.rational, Assume(x, Q.even)) == True
> +    assert ask(2*x, Q.rational, Assume(x, Q.odd)) == True
> +    assert ask(2*x, Q.rational, Assume(x, Q.irrational)) == False
> +
> +    assert ask(x/2, Q.rational, Assume(x, Q.rational)) == True
> +    assert ask(x/2, Q.rational, Assume(x, Q.integer)) == True
> +    assert ask(x/2, Q.rational, Assume(x, Q.even)) == True
> +    assert ask(x/2, Q.rational, Assume(x, Q.odd)) == True
> +    assert ask(x/2, Q.rational, Assume(x, Q.irrational)) == False
> +
> +    assert ask(1/x, Q.rational, Assume(x, Q.rational)) == True
> +    assert ask(1/x, Q.rational, Assume(x, Q.integer)) == True
> +    assert ask(1/x, Q.rational, Assume(x, Q.even)) == True
> +    assert ask(1/x, Q.rational, Assume(x, Q.odd)) == True
> +    assert ask(1/x, Q.rational, Assume(x, Q.irrational)) == False
> +
> +    assert ask(2/x, Q.rational, Assume(x, Q.rational)) == True
> +    assert ask(2/x, Q.rational, Assume(x, Q.integer)) == True
> +    assert ask(2/x, Q.rational, Assume(x, Q.even)) == True
> +    assert ask(2/x, Q.rational, Assume(x, Q.odd)) == True
> +    assert ask(2/x, Q.rational, Assume(x, Q.irrational)) == False
> +
> +    # with multiple symbols
> +    assert ask(x*y, Q.rational, Assume(x, Q.irrational) & \
> +        Assume(y, Q.irrational)) == None
> +    assert ask(y/x, Q.rational, Assume(x, Q.rational) & \
> +        Assume(y, Q.rational)) == True
> +    assert ask(y/x, Q.rational, Assume(x, Q.integer) & \
> +        Assume(y, Q.rational)) == True
> +    assert ask(y/x, Q.rational, Assume(x, Q.even) & \
> +        Assume(y, Q.rational)) == True
> +    assert ask(y/x, Q.rational, Assume(x, Q.odd) & \
> +        Assume(y, Q.rational)) == True
> +    assert ask(y/x, Q.rational, Assume(x, Q.irrational) & \
> +        Assume(y, Q.rational)) == False
> +
> +def test_imaginary():
> +    x, y, z = symbols('x y z')
> +    I = S.ImaginaryUnit
> +    assert ask(x, Q.imaginary) == None
> +    assert ask(x, Q.imaginary, Assume(x, Q.real)) == False
> +    assert ask(x, Q.imaginary, Assume(x, Q.prime)) == False
> +
> +    assert ask(x+1, Q.imaginary, Assume(x, Q.real)) == False
> +    assert ask(x+1, Q.imaginary, Assume(x, Q.imaginary)) == False
> +    assert ask(x+I, Q.imaginary, Assume(x, Q.real)) == False
> +    assert ask(x+I, Q.imaginary, Assume(x, Q.imaginary)) == True
> +    assert ask(x+y, Q.imaginary, Assume(x, Q.imaginary) & \
> +                     Assume(y, Q.imaginary)) == True
> +    assert ask(x+y, Q.imaginary, Assume(x, Q.real) & \
> +                     Assume(y, Q.real)) == False
> +    assert ask(x+y, Q.imaginary, Assume(x, Q.imaginary) & \
> +                     Assume(y, Q.real)) == False
> +    assert ask(x+y, Q.imaginary, Assume(x, Q.complex) & \
> +                     Assume(y, Q.real)) == None
> +
> +    assert ask(I*x, Q.imaginary, Assume(x, Q.real)) == True
> +    assert ask(I*x, Q.imaginary, Assume(x, Q.imaginary)) == False
> +    assert ask(I*x, Q.imaginary, Assume(x, Q.complex)) == None
> +    assert ask(x*y, Q.imaginary, Assume(x, Q.imaginary) & \
> +                 Assume(y, Q.real)) == True
> +
> +    assert ask(x+y+z, Q.imaginary, Assume(x, Q.real) & \
> +                     Assume(y, Q.real) & Assume(z, Q.real)) == False
> +    assert ask(x+y+z, Q.imaginary, Assume(x, Q.real) & \
> +                     Assume(y, Q.real) & Assume(z, Q.imaginary)) == None
> +    assert ask(x+y+z, Q.imaginary, Assume(x, Q.real) & \
> +                     Assume(y, Q.imaginary) & Assume(z, Q.imaginary)) == False
> +
> +def test_infinitesimal():
> +    x, y = symbols('x y')
> +    assert ask(x, Q.infinitesimal) == None
> +    assert ask(x, Q.infinitesimal, Assume(x, Q.infinitesimal)) == True
> +
> +    assert ask(2*x, Q.infinitesimal, Assume(x, Q.infinitesimal)) == True
> +    assert ask(x*y, Q.infinitesimal, Assume(x, Q.infinitesimal)) == None
> +    assert ask(x*y, Q.infinitesimal, Assume(x, Q.infinitesimal) & \
> +                     Assume(y, Q.infinitesimal)) == True
> +    assert ask(x*y, Q.infinitesimal, Assume(x, Q.infinitesimal) & \
> +                     Assume(y, Q.bounded)) == True
> +
> +    assert ask(x**2, Q.infinitesimal, Assume(x, Q.infinitesimal)) == True
> +
> +def test_integer():
> +    x = symbols('x')
> +    assert ask(x, Q.integer) == None
> +    assert ask(x, Q.integer, Assume(x, Q.integer)) == True
> +    assert ask(x, Q.integer, Assume(x, Q.integer, False)) == False
> +    assert ask(x, Q.integer, Assume(x, Q.real, False)) == False
> +    assert ask(x, Q.integer, Assume(x, Q.positive, False)) == None
> +
> +    assert ask(2*x, Q.integer, Assume(x, Q.integer)) == True
> +    assert ask(2*x, Q.integer, Assume(x, Q.even)) == True
> +    assert ask(2*x, Q.integer, Assume(x, Q.prime)) == True
> +    assert ask(2*x, Q.integer, Assume(x, Q.rational)) == None
> +    assert ask(2*x, Q.integer, Assume(x, Q.real)) == None
> +
> +    assert ask(x/2, Q.integer, Assume(x, Q.odd)) == False
> +    assert ask(x/2, Q.integer, Assume(x, Q.even)) == True
> +    assert ask(x/3, Q.integer, Assume(x, Q.odd)) == None
> +    assert ask(x/3, Q.integer, Assume(x, Q.even)) == None
> +
> +def test_negative():
> +    x, y = symbols('xy')
> +    assert ask(x, Q.negative, Assume(x, Q.negative)) == True
> +    assert ask(x, Q.negative, Assume(x, Q.positive)) == False
> +    assert ask(x, Q.negative, Assume(x, Q.real, False)) == False
> +    assert ask(x, Q.negative, Assume(x, Q.prime)) == False
> +    assert ask(x, Q.negative, Assume(x, Q.prime, False)) == None
> +
> +    assert ask(-x, Q.negative, Assume(x, Q.positive)) == True
> +    assert ask(-x, Q.negative, Assume(x, Q.positive, False)) == None
> +    assert ask(-x, Q.negative, Assume(x, Q.negative)) == False
> +    assert ask(-x, Q.negative, Assume(x, Q.positive)) == True
> +
> +    assert ask(x-1, Q.negative, Assume(x, Q.negative)) == True
> +    assert ask(x+y, Q.negative) == None
> +    assert ask(x+y, Q.negative, Assume(x, Q.negative)) == None
> +    assert ask(x+y, Q.negative, Assume(x, Q.negative) &\
> +                     Assume(y, Q.negative)) == True
> +
> +    assert ask(x*y, Q.negative) == None
> +    assert ask(x*y, Q.negative, Assume(x, Q.positive) & \
> +                     Assume(y, Q.positive)) == False
> +    assert ask(x*y, Q.negative, Assume(x, Q.positive) & \
> +                     Assume(y, Q.negative)) == True
> +    assert ask(x*y, Q.negative, Assume(x, Q.complex) & \
> +                     Assume(y, Q.complex)) == None
> +
> +    assert ask(x**y, Q.negative) == None
> +    assert ask(x**y, Q.negative, Assume(x, Q.negative) & \
> +                     Assume(y, Q.even)) == False
> +    assert ask(x**y, Q.negative, Assume(x, Q.negative) & \
> +                     Assume(y, Q.odd)) == True
> +    assert ask(x**y, Q.negative, Assume(x, Q.positive) & \
> +                     Assume(y, Q.integer)) == False
> +
> +    assert ask(abs(x), Q.negative) == False
> +
> +def test_nonzero():
> +    x, y = symbols('xy')
> +    assert ask(x, Q.nonzero) == None
> +    assert ask(x, Q.nonzero, Assume(x, Q.real)) == None
> +    assert ask(x, Q.nonzero, Assume(x, Q.positive)) == True
> +    assert ask(x, Q.nonzero, Assume(x, Q.negative)) == True
> +
> +    assert ask(x+y, Q.nonzero) == None
> +    assert ask(x+y, Q.nonzero, Assume(x, Q.positive) & Assume(y, Q.positive)) == True
> +    assert ask(x+y, Q.nonzero, Assume(x, Q.positive) & Assume(y, Q.negative)) == None
> +    assert ask(x+y, Q.nonzero, Assume(x, Q.negative) & Assume(y, Q.negative)) == True
> +
> +    assert ask(2*x, Q.nonzero) == None
> +    assert ask(2*x, Q.nonzero, Assume(x, Q.positive)) == True
> +    assert ask(2*x, Q.nonzero, Assume(x, Q.negative)) == True
> +    assert ask(x*y, Q.nonzero, Assume(x, Q.nonzero)) == None
> +    assert ask(x*y, Q.nonzero, Assume(x, Q.nonzero) & Assume(y, Q.nonzero)) == True
> +
> +    assert ask(abs(x), Q.nonzero) == None
> +    assert ask(abs(x), Q.nonzero, Assume(x, Q.nonzero)) == True
> +
> +def test_odd():
> +    x, y, z, t = symbols('x y z t')
> +    assert ask(x, Q.odd) == None
> +    assert ask(x, Q.odd, Assume(x, Q.odd)) == True
> +    assert ask(x, Q.odd, Assume(x, Q.integer)) == None
> +    assert ask(x, Q.odd, Assume(x, Q.integer, False)) == False
> +    assert ask(x, Q.odd, Assume(x, Q.rational)) == None
> +    assert ask(x, Q.odd, Assume(x, Q.positive)) == None
> +
> +    assert ask(-x, Q.odd, Assume(x, Q.odd)) == True
> +
> +    assert ask(2*x, Q.odd) == None
> +    assert ask(2*x, Q.odd, Assume(x, Q.integer)) == False
> +    assert ask(2*x, Q.odd, Assume(x, Q.odd)) == False
> +    assert ask(2*x, Q.odd, Assume(x, Q.irrational)) == False
> +    assert ask(2*x, Q.odd, Assume(x, Q.integer, False)) == None
> +    assert ask(3*x, Q.odd, Assume(x, Q.integer)) == None
> +
> +    assert ask(x/3, Q.odd, Assume(x, Q.odd)) == None
> +    assert ask(x/3, Q.odd, Assume(x, Q.even)) == None
> +
> +    assert ask(x+1, Q.odd, Assume(x, Q.even)) == True
> +    assert ask(x+2, Q.odd, Assume(x, Q.even)) == False
> +    assert ask(x+2, Q.odd, Assume(x, Q.odd))  == True
> +    assert ask(3-x, Q.odd, Assume(x, Q.odd))  == False
> +    assert ask(3-x, Q.odd, Assume(x, Q.even))  == True
> +    assert ask(3+x, Q.odd, Assume(x, Q.odd))  == False
> +    assert ask(3+x, Q.odd, Assume(x, Q.even))  == True
> +    assert ask(x+y, Q.odd, Assume(x, Q.odd) & Assume(y, Q.odd)) == False
> +    assert ask(x+y, Q.odd, Assume(x, Q.odd) & Assume(y, Q.even)) == True
> +    assert ask(x-y, Q.odd, Assume(x, Q.even) & Assume(y, Q.odd)) == True
> +    assert ask(x-y, Q.odd, Assume(x, Q.odd) & Assume(y, Q.odd)) == False
> +
> +    assert ask(x+y+z, Q.odd, Assume(x, Q.odd) & Assume(y, Q.odd) & \
> +                     Assume(z, Q.even)) == False
> +    assert ask(x+y+z+t, Q.odd, Assume(x, Q.odd) & Assume(y, Q.odd) & \
> +                     Assume(z, Q.even) & Assume(t, Q.integer)) == None
> +
> +    assert ask(2*x + 1, Q.odd, Assume(x, Q.integer)) == True
> +    assert ask(2*x + y, Q.odd, Assume(x, Q.integer) & Assume(y, Q.odd)) == True
> +    assert ask(2*x + y, Q.odd, Assume(x, Q.integer) & Assume(y, Q.even)) == False
> +    assert ask(2*x + y, Q.odd, Assume(x, Q.integer) & Assume(y, Q.integer)) == None
> +    assert ask(x*y,   Q.odd, Assume(x, Q.odd) & Assume(y, Q.even)) == False
> +    assert ask(x*y,   Q.odd, Assume(x, Q.odd) & Assume(y, Q.odd)) == True
> +    assert ask(2*x*y, Q.odd, Assume(x, Q.rational) & Assume(x, Q.rational)) == None
> +    assert ask(2*x*y, Q.odd, Assume(x, Q.irrational) & Assume(x, Q.irrational)) == None
> +
> +    assert ask(abs(x), Q.odd, Assume(x, Q.odd)) == True
> +
> +def test_prime():
> +    x, y = symbols('x y')
> +    assert ask(x, Q.prime, Assume(x, Q.prime)) == True
> +    assert ask(x, Q.prime, Assume(x, Q.prime, False)) == False
> +    assert ask(x, Q.prime, Assume(x, Q.integer)) == None
> +    assert ask(x, Q.prime, Assume(x, Q.integer, False)) == False
> +
> +    assert ask(2*x, Q.prime, Assume(x, Q.integer)) == False
> +    assert ask(x*y, Q.prime) == None
> +    assert ask(x*y, Q.prime, Assume(x, Q.prime)) == None
> +    assert ask(x*y, Q.prime, Assume(x, Q.integer) & \
> +                     Assume(y, Q.integer)) == False
> +
> +    assert ask(x**2, Q.prime, Assume(x, Q.integer)) == False
> +    assert ask(x**2, Q.prime, Assume(x, Q.prime)) == False
> +    assert ask(x**y, Q.prime, Assume(x, Q.integer) & \
> +                     Assume(y, Q.integer)) == False
> +
> +def test_positive():
> +    x, y, z, w = symbols('xyzw')
> +    assert ask(x, Q.positive, Assume(x, Q.positive)) == True
> +    assert ask(x, Q.positive, Assume(x, Q.negative)) == False
> +    assert ask(x, Q.positive, Assume(x, Q.nonzero)) == None
> +
> +    assert ask(-x, Q.positive, Assume(x, Q.positive)) == False
> +    assert ask(-x, Q.positive, Assume(x, Q.negative)) == True
> +
> +    assert ask(x+y, Q.positive, Assume(x, Q.positive) & \
> +                     Assume(y, Q.positive)) == True
> +    assert ask(x+y, Q.positive, Assume(x, Q.positive) & \
> +                     Assume(y, Q.negative)) == None
> +
> +    assert ask(2*x,  Q.positive, Assume(x, Q.positive)) == True
> +    assumptions =  Assume(x, Q.positive) & Assume(y, Q.negative) & \
> +                    Assume(z, Q.negative) & Assume(w, Q.positive)
> +    assert ask(x*y*z,  Q.positive)  == None
> +    assert ask(x*y*z,  Q.positive, assumptions) == True
> +    assert ask(-x*y*z, Q.positive, assumptions) == False
> +
> +    assert ask(x**2, Q.positive, Assume(x, Q.positive)) == True
> +    assert ask(x**2, Q.positive, Assume(x, Q.negative)) == True
> +
> +    #exponential
> +    assert ask(exp(x),     Q.positive, Assume(x, Q.real)) == True
> +    assert ask(x + exp(x), Q.positive, Assume(x, Q.real)) == None
> +
> +    #absolute value
> +    assert ask(abs(x), Q.positive) == None # abs(0) = 0
> +    assert ask(abs(x), Q.positive, Assume(x, Q.positive)) == True
> +
> +@XFAIL
> +def test_positive_xfail():
> +    assert ask(1/(1 + x**2), Q.positive, Assume(x, Q.real)) == True
> +
> +def test_real():
> +    x, y = symbols('x y')
> +    assert ask(x, Q.real) == None
> +    assert ask(x, Q.real, Assume(x, Q.real)) == True
> +    assert ask(x, Q.real, Assume(x, Q.nonzero)) == True
> +    assert ask(x, Q.real, Assume(x, Q.positive)) == True
> +    assert ask(x, Q.real, Assume(x, Q.negative)) == True
> +    assert ask(x, Q.real, Assume(x, Q.integer)) == True
> +    assert ask(x, Q.real, Assume(x, Q.even)) == True
> +    assert ask(x, Q.real, Assume(x, Q.prime)) == True
> +
> +    assert ask(x/sqrt(2), Q.real, Assume(x, Q.real)) == True
> +    assert ask(x/sqrt(-2), Q.real, Assume(x, Q.real)) == False
> +
> +    I = S.ImaginaryUnit
> +    assert ask(x+1, Q.real, Assume(x, Q.real)) == True
> +    assert ask(x+I, Q.real, Assume(x, Q.real)) == False
> +    assert ask(x+I, Q.real, Assume(x, Q.complex)) == None
> +
> +    assert ask(2*x, Q.real, Assume(x, Q.real)) == True
> +    assert ask(I*x, Q.real, Assume(x, Q.real)) == False
> +    assert ask(I*x, Q.real, Assume(x, Q.imaginary)) == True
> +    assert ask(I*x, Q.real, Assume(x, Q.complex)) == None
> +
> +    assert ask(x**2, Q.real, Assume(x, Q.real)) == True
> +    assert ask(sqrt(x), Q.real, Assume(x, Q.negative)) == False
> +    assert ask(x**y, Q.real, Assume(x, Q.real) & Assume(y, Q.integer)) == True
> +    assert ask(x**y, Q.real, Assume(x, Q.real) & Assume(y, Q.real)) == None
> +    assert ask(x**y, Q.real, Assume(x, Q.positive) & \
> +                     Assume(y, Q.real)) == True
> +
> +    # trigonometric functions
> +    assert ask(sin(x), Q.real) == None
> +    assert ask(cos(x), Q.real) == None
> +    assert ask(sin(x), Q.real, Assume(x, Q.real)) == True
> +    assert ask(cos(x), Q.real, Assume(x, Q.real)) == True
> +
> +    # exponential function
> +    assert ask(exp(x), Q.real) == None
> +    assert ask(exp(x), Q.real, Assume(x, Q.real)) == True
> +    assert ask(x + exp(x), Q.real, Assume(x, Q.real)) == True
> +
> +    # Q.complexes
> +    assert ask(re(x), Q.real) == True
> +    assert ask(im(x), Q.real) == True
> +
> +
> +
> +def test_global():
> +    """Test ask with global assumptions"""
> +    x = symbols('x')
> +    assert ask(x, Q.integer) == None
> +    register_global_assumptions(Assume(x, Q.integer))
> +    assert ask(x, Q.integer) == True
> +    clean_global_assumptions()
> +    assert ask(x, Q.integer) == None
> +
> +def test_incompatible_resolutors():
> +    x = symbols('x')
> +    class Prime2AskHandler(AskHandler):
> +        @staticmethod
> +        def Number(expr, assumptions):
> +            return True
> +    register_handler('prime', Prime2AskHandler)
> +    raises(ValueError, 'ask(4, Q.prime)')
> +
> +def test_key_extensibility():
> +    """test that you can add keys to the ask system at runtime"""
> +    x = Symbol('x')
> +    # make sure thie key is not defined
> +    raises(KeyError, "ask(x, 'my_key')")
> +    class MyAskHandler(AskHandler):
> +        @staticmethod
> +        def Symbol(expr, assumptions):
> +            return True
> +    register_handler('my_key', MyAskHandler)
> +    assert ask(x, 'my_key') == True
> +    assert ask(x+1, 'my_key') == None
> +    remove_handler('my_key', MyAskHandler)
> +
> +def test_type_extensibility():
> +    """test that new types can be added to the ask system at runtime
> +    We create a custom type MyType, and override ask Q.prime=True with handler
> +    MyAskHandler for this type
> +
> +    TODO: test incompatible resolutors
> +    """
> +    from sympy.core import Basic
> +
> +    class MyType(Basic):
> +        pass
> +
> +    class MyAskHandler(AskHandler):
> +        @staticmethod
> +        def MyType(expr, assumptions):
> +            return True
> +
> +    a = MyType()
> +    register_handler(Q.prime, MyAskHandler)
> +    assert ask(a, Q.prime) == True
> --
> 1.6.4
>
>
> From d95fb5eef2ee91d9e9cd82e7a511c18af2b48043 Mon Sep 17 00:00:00 2001
> From: Fabian Pedregosa <fab...@fseoane.net>
> Date: Tue, 21 Jul 2009 20:27:20 +0200
> Subject: [PATCH 4/4] Documentation for the queries module
>
> ---
>  doc/src/modules.txt         |    5 +-
>  doc/src/modules/queries.txt |  389 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 392 insertions(+), 2 deletions(-)
> index 0000000..4362218
> --- /dev/null
> +++ b/doc/src/modules/queries.txt
> @@ -0,0 +1,389 @@
> +Query module
> +============
> +
> +.. module:: sympy.queries
> +
> +Queries are used to ask information about expression. Main method in this
> +module is ask():
> +
> +.. automethod:: sympy.queries.ask
> +
> +Assumptions
> +===========
> +
> +ask's optional second argument should be a boolean
> +expression involving assumptions about objects in expr. Valid values include:
> +
> +    * Assume(x, Q.integer)
> +    * Assume(x, Q.positive)
> +    * Assume(x, Q.integer) & Assume(x, Q.positive)
> +    * etc.
> +
> +Q is a class in sympy.queries holding valid assumptions.
> +
> +See documentation for the logic module for a complete list of valid boolean
> +expressions.
> +
> +You can also define global assumptions so you don't have to pass that argument
> +each time to function ask(). This is done calling register_global_assumptions()
> +from module sympy.assumptions. You can then clear global assumptions with
> +clean_global_assumptions()
> +
> +     >>> from sympy import *
> +     >>> x = Symbol('x')
> +     >>> register_global_assumptions(Assume(x, Q.positive))
> +     None
> +     >>> ask(x, Q.positive)
> +     True
> +     >>> clean_global_assumptions()
> +     None
> +
> +
> +Supported queries
> +=================
> +
> +bounded
> +-------
> +
> +Test that a function is bounded with respect to it's variables. For example,
> +sin(x) is a bounded functions, but exp(x) is not.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> x = Symbol('x')
> +    >>> ask(exp(x), Q.bounded)
> +    False
> +    >>> ask(exp(x), Q.bounded , Assume(x, Q.bounded))
> +    True
> +    >>> ask(sin(x), Q.bounded)
> +    True
> +
> +
> +commutative
> +-----------
> +
> +Test that objects are commutative. By default, symbols in SymPy are considered
> +commutative except otherwise stated.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> x, y = symbols('x y')
> +    >>> ask(x, Q.commutative)
> +    True
> +    >>> ask(x, Q.commutative, Assume(x, Q.commutative, False))
> +    False
> +    >>> ask(x*y, Q.commutative, Assume(x, Q.commutative, False))
> +    False
> +
> +
> +complex
> +-------
> +
> +Test that expression belongs to the field of complex numbers.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> ask(2, Q.complex)
> +    True
> +    >>> ask(I, Q.complex)
> +    True
> +    >>> x, y = symbols('x y')
> +    >>> ask(x+I*y, Q.complex, Assume(x, Q.real) & Assume(y, Q.real))
> +    True
> +
> +
> +even
> +----
> +
> +Test that expression represents an even number, that is, an number that
> +can be written in the form 2*n, n integer.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> ask(2, Q.even)
> +    True
> +    >>> n = Symbol('n')
> +    >>> ask(2*n, Q.even, Assume(n, Q.integer))
> +    True
> +
> +
> +extended_real
> +-------------
> +
> +Test that an expression belongs to the field of extended real numbers, that is, real
> +numbers union {Infinity, -Infinity}.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> ask(oo, Q.extended_real)
> +    True
> +    >>> ask(2, Q.extended_real)
> +    True
> +    >>> ask(x, Q.extended_real, Assume(x, Q.real))
> +    True
> +
> +
> +imaginary
> +---------
> +
> +Test that an expression belongs to the field of imaginary numbers, that is,
> + it can be written as x*I, where x is real and I is the imaginary unit.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> ask(2*I, Q.imaginary)
> +    True
> +    >>> x = Symbol('x')
> +    >>> ask(x*I, Q.imaginary, Assume(x, Q.real))
> +    True
> +
> +
> +infinitesimal
> +-------------
> +
> +Test that an expression is equivalent to an infinitesimal number.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> ask(1/oo, Q.infinitesimal)
> +    True
> +    >>> x, y = symbols('x y')
> +    >>> ask(2*x, Q.infinitesimal, Assume(x, Q.infinitesimal))
> +    True
> +    >>> ask(x*y, Q.infinitesimal, Assume(x, Q.infinitesimal) & Assume(y, Q.bounded))
> +    True
> +
> +
> +integer
> +-------
> +
> +Test that an expression belongs to the field of integer numbers.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> ask(2, Q.integer)
> +    True
> +    >>> ask(sqrt(2), Q.integer)
> +    False
> +    >>> x = Symbol('x')
> +    >>> ask(x/2, Q.integer, Assume(x, Q.even))
> +    True
> +
> +
> +irrational
> +----------
> +
> +Test that an expression represents an irrational number.
> +
> +Examples::
> +
> +     >>> from sympy import *
> +     >>> ask(pi, Q.irrational)
> +     True
> +     >>> ask(sqrt(2), Q.irrational)
> +     True
> +     >>> ask(x*sqrt(2), Q.irrational, Assume(x, Q.rational))
> +     True
> +
> +
> +rational
> +--------
> +
> +Test that an expression represents a rational number.
> +
> +Examples::
> +
> +     >>> from sympy import *
> +     >>> ask(Rational(3, 4), Q.rational)
> +     True
> +     >>> x, y = symbols('x y')
> +     >>> ask(x/2, Q.rational, Assume(x, Q.integer))
> +     True
> +     >>> ask(x/y, Q.rational, Assume(x, Q.integer) & Assume(y, Q.integer))
> +     True
> +
> +
> +negative
> +--------
> +
> +Test that an expression is less (strict) than zero.
> +
> +Examples::
> +
> +     >>> from sympy import *
> +     >>> ask(0.3, Q.negative)
> +     False
> +     >>> x = Symbol('x')
> +     >>> ask(-x, Q.negative, Assume(x, Q.positive))
> +     True
> +
> +Remarks
> +^^^^^^^
> +negative numbers are defined as real numbers that are not zero nor positive, so
> +complex numbers (with nontrivial imaginary coefficients) will return False
> +in this ask. The same applies to ask positive.
> +
> +
> +positive
> +--------
> +
> +Test that a given expression is greater (strict) than zero.
> +
> +Examples::
> +
> +     >>> from sympy import *
> +     >>> ask(0.3, Q.positive)
> +     True
> +     >>> x = Symbol('x')
> +     >>> ask(-x, Q.positive, Assume(x, Q.negative))
> +     True
> +
> +Remarks
> +^^^^^^^
> +see Remarks for negative
> +
> +
> +prime
> +-----
> +
> +Test that an expression represents a prime number.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> ask(13, Q.prime)
> +    True
> +
> +Remarks: Use sympy.ntheory.isprime for efficiently test numeric values.
> +
> +
> +real
> +----
> +
> +Test that an expression belongs to the field of real numbers.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> ask(sqrt(2), Q.real)
> +    True
> +    >>> x, y = symbols('x y')
> +    >>> ask(x*y, Q.real, Assume(x, Q.real) & Assume(y, Q.real))
> +    True
> +
> +
> +odd
> +---
> +
> +Test that an expression represents an odd number.
> +
> +Examples::
> +
> +    >>> from sympy import *
> +    >>> ask(3, Q.odd)
> +    True
> +    >>> n = Symbol('n')
> +    >>> ask(2*n + 1, Q.odd, Assume(n, Q.integer))
> +    True
> +
> +
> +nonzero
> +-------
> +
> +Test that an expression is not zero.
> +
> +Examples::
> +
> +     >>> from sympy import *
> +     >>> x = Symbol('x')
> +     >>> ask(x, Q.nonzero, Assume(x, Q.positive) | Assume(x, Q.negative))
> +     True
> +
> +
> +Design
> +======
> +
> +Each time ask is called, the appropriate Handler for the current key is called. This is
> +always a subclass of sympy.queries.AskHandler. It's classmethods have the name's of the classes
> +it supports. For example, a (simplified) AskHandler for the ask 'positive' would
> +look like this::
> +
> +    class AskPositiveHandler(CommonHandler):
> +
> +        def Mul(self):
> +            # return True if all argument's in self.expr.args are positive
> +            ...
> +
> +        def Add(self):
> +            for arg in self.expr.args:
> +                if not ask(arg, positive, self.assumptions):
> +                    break
> +            else:
> +                # if all argument's are positive
> +                return True
> +        ...
> +
> +The .Mul() method is called when self.expr is an instance of Mul, the Add method
> +would be called when self.expr is an instance of Add and so on.
> +
> +
> +Extensibility
> +=============
> +
> +You can define new queries or support new types by subclassing sympy.queries.AskHandler
> + and registering that handler for a particular key by calling register_handler:
> +
> +.. automethod:: sympy.queries.register_handler
> +
> +You can undo this operation by calling remove_handler.
> +
> +.. automethod:: sympy.queries.remove_handler
> +
> +You can support new types [1]_ by adding a handler to an existing key. In the
> +following example, we will create a new type MyType and extend the key 'prime'
> +to accept this type (and return True)
> +
> +.. parsed-literal::
> +
> +    >>> from sympy.core import Basic
> +    >>> from sympy.queries import register_handler
> +    >>> from sympy.queries.handlers import AskHandler
> +    >>> class MyType(Basic):
> +    ...     pass
> +    >>> class MyAskHandler(AskHandler):
> +    ...     @staticmethod
> +    ...     def MyType(expr, assumptions):
> +    ...         return True
> +    >>> a = MyType()
> +    >>> register_handler('prime', MyAskHandler)
> +    None
> +    >>> ask(a, Q.prime)
> +    True
> +
> +
> +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 (http://en.wikipedia.org/wiki/Truth_maintenance_system) could be implemented.
> +
> +Misc
> +====
> +
> +You can find more examples in the in the form of test under directory sympy/queries/tests/
> +
> +.. [1] New type must inherit from Basic, otherwise an exception will be raised.
> +   This is a bug and should be fixed.
> --
> 1.6.4
>
>
>

Vinzent Steinberg

unread,
Aug 5, 2009, 5:22:32 PM8/5/09
to sympy-...@googlegroups.com
Many thanks for the patch, Fabian, I really appreciate the new syntax,
which is much more user-friendly.

2009/8/5 Ondrej Certik <ond...@certik.cz>:


>
> Looks good in general, but before we push this in, please improve the
> doctest coverage to 100%:
>
> $ bin/coverage_doctest.py sympy/assumptions/assume.py
> ----------------------------------------------------------------------
> sympy/assumptions/assume.py
>
> Missing documentation:
>         * expr(self)
>         * key(self)
>         * value(self)
>
>
> Missing doctests:
>         * list_global_assumptions()
>         * remove_global_assumptions(*assump)
>         * clean_global_assumptions()
>         * eliminate_assume(expr, symbol=None)
>
>
> Indirect doctest (function name doesn't occur in doctests):
>         * register_global_assumptions(*assump)
>
> Use "# indirect doctest" in the docstring to surpress this warning
> SCORE sympy/assumptions/assume.py: 12% (1 of 8)
> ----------------------------------------------------------------------
>
>
>
> The same about the handlers/, do you think there should be no example
> doctests? I think there should, at least in the classes, but I think
> it should be in all methods. I have no idea how to use it without the
> doctests.

I'd like to remove all the global assumptions functions and replace it
with an ordinary Python set of assumptions, for simplicity's sake. (It
already has add(), remove(), clear(), copy() and other stuff which
could be nice when working with different "contexts" of assumptions.)
If you agree, I'll go for it. :)

Vinzent

Ondrej Certik

unread,
Aug 5, 2009, 5:34:12 PM8/5/09
to sympy-...@googlegroups.com

Do you mean the old assumptions, or something else?

Ondrej

Vinzent Steinberg

unread,
Aug 5, 2009, 5:38:04 PM8/5/09
to sympy-...@googlegroups.com
2009/8/5 Ondrej Certik <ond...@certik.cz>:

> Do you mean the old assumptions, or something else?

I meant these methods in the new assumptions branch:

* list_global_assumptions()
* remove_global_assumptions(*assump)
* clean_global_assumptions()

Vinzent

Ondrej Certik

unread,
Aug 5, 2009, 5:39:05 PM8/5/09
to sympy-...@googlegroups.com

Yes, then I am definitely +1. But let's wait for Fabian.

Ondrej

Fabian Pedregosa Izquierdo

unread,
Aug 5, 2009, 5:45:54 PM8/5/09
to sympy-...@googlegroups.com
yes, please do it. I am just finishing doctest for this module, I hope
to be done soon (today).

> Vinzent
>
> >

Ondrej Certik

unread,
Aug 5, 2009, 5:58:11 PM8/5/09
to sympy-...@googlegroups.com

Cool, looking forward.

Ondrej

Fabian Pedregosa Izquierdo

unread,
Aug 5, 2009, 6:12:46 PM8/5/09
to sympy-...@googlegroups.com
Ondrej Certik wrote:
> Looks good in general, but before we push this in, please improve the
> doctest coverage to 100%:
>
> $ bin/coverage_doctest.py sympy/assumptions/assume.py
> ----------------------------------------------------------------------
> sympy/assumptions/assume.py
>
> Missing documentation:
> * expr(self)
> * key(self)
> * value(self)
>
>
> Missing doctests:
> * list_global_assumptions()
> * remove_global_assumptions(*assump)
> * clean_global_assumptions()
> * eliminate_assume(expr, symbol=None)
>
>
> Indirect doctest (function name doesn't occur in doctests):
> * register_global_assumptions(*assump)
>
> Use "# indirect doctest" in the docstring to surpress this warning
> SCORE sympy/assumptions/assume.py: 12% (1 of 8)
> ----------------------------------------------------------------------
>
>

ok, I agree. I raised it to 100% (it's on my ask branch)

>
> The same about the handlers/, do you think there should be no example
> doctests? I think there should, at least in the classes, but I think
> it should be in all methods. I have no idea how to use it without the
> doctests.
>

the handlers are all example-tested in doc/src/modules/queries.txt, so
I'm not sure if it's worth duplicating those test in the classes.
Although I agree that the handlers need some documentation, the user
should not use then directly. I will do some developer-oriented docs for
the handlers, but that will take some time. Maybe we can push this and
then I'll start doing that.

Ondrej Certik

unread,
Aug 5, 2009, 6:21:17 PM8/5/09
to sympy-...@googlegroups.com
What is the purpose of the

#assume.py#

file?

Ondrej Certik

unread,
Aug 5, 2009, 6:25:08 PM8/5/09
to sympy-...@googlegroups.com
Besides that, I am ok with that, but:

let's put all the docstrings into the classes and just use sphinx
ability to include those docstrings. This is really important, so that
people can just read docstrings and understand what things are doing.

I don't want to hold it anymore, so if you are all ok to push it in,
let's do it now. After you explain the purpose of #assume.py#.

Ondrej

Fabian Pedregosa Izquierdo

unread,
Aug 5, 2009, 6:32:40 PM8/5/09
to sympy-...@googlegroups.com
Ondrej Certik wrote:
> What is the purpose of the
>
> #assume.py#

That's an emacs backup file. Shouldn't be there.

>
> file?
>
> >

Ondrej Certik

unread,
Aug 5, 2009, 6:36:23 PM8/5/09
to sympy-...@googlegroups.com
So please remove it, add my signatue to all patches and push it in.

Thanks,
Ondrej

Fabian Pedregosa Izquierdo

unread,
Aug 5, 2009, 6:54:38 PM8/5/09
to sympy-...@googlegroups.com
Ondrej Certik wrote:
> So please remove it, add my signatue to all patches and push it in.
>

Great. It's in. I'll keep an eye on the buildbots and make documentation
for the handlers.

Ondrej Certik

unread,
Aug 5, 2009, 7:12:35 PM8/5/09
to sympy-...@googlegroups.com
On Wed, Aug 5, 2009 at 4:54 PM, Fabian Pedregosa

Izquierdo<fab...@fseoane.net> wrote:
>
> Ondrej Certik wrote:
>> So please remove it, add my signatue to all patches and push it in.
>>
>
> Great. It's in. I'll keep an eye on the buildbots and make documentation
> for the handlers.

Thanks!

Ondrej

Reply all
Reply to author
Forward
0 new messages