2

If I have a simple variable, I can specify the assumptions or type as follows:

import sympy as sy

k = sy.Symbol('k', integer=True)

assert k.is_integer
assert k.is_real

What if I want to do the the same for an IndexedBase or a Function:

f = sy.Function('f', integer=True)
t = sy.Symbol('t')
assert f(t).is_integer  # AssertionError
from sympy.tensor import IndexedBase, Idx
i = Idx('i')
A = IndexedBase('A', integer=True)
#  __new__() got an unexpected keyword argument 'integer'
assert A[i].is_integer

But neither of these work. Is this possible?

Eric
  • 95,302
  • 53
  • 242
  • 374

2 Answers2

1

The old-style assumptions are implemented in the class constructor of the SymPy object through various mechanisms. This should be implemented for every SymPy class separately. Some classes simply do not have this implementation available and you can't use it.

I suggest to use the new-style assumptions, where predicates are not declared on object construction:

In [1]: A = IndexedBase("A")

In [2]: with assuming(Q.positive(A[i])):
   ...:     print ask(Q.real(A[i]))
   ...:     
True

In [3]: with assuming(Q.positive(f(x))):
   ...:     print ask(Q.real(f(x)))
   ...:     
True

That is, you create a with assuming( ... ) block, inside of it the assumptions declared inside assuming are assumed to hold. The assumptions in ask( ... ) are then queried by logical deduction.

Unfortunately the new-style assumptions are not yet implemented in many of SymPy's algorithms (for example, solve will probably ignore them).

Francesco Bonazzi
  • 1,917
  • 9
  • 10
1

There's no syntactic sugar for Function or Indexed, but you can still add assumptions by subclassing them. Function('f') creates a subclass of Function called f. You can use

class f(Function):
    is_integer = True

to create a subclass with is_integer set to True.

For IndexedBase, you'll want to subclass Indexed, which is the class that gets created when you do A[i].

In [11]: i = Idx('i')

In [12]: class IntegerIndexed(Indexed):
   ....:     is_integer = True
   ....:

In [13]: IntegerIndexed("A", i)
Out[13]: A[i]

In [14]: IntegerIndexed("A", i).is_integer
Out[14]: True
asmeurer
  • 86,894
  • 26
  • 169
  • 240
  • This doesn't work, because `is_indexed` is just a property that resolves to a lookup in the `._assumptions` member dictionary, so there's no guarantee that internal code will see the extra member – Eric Jun 25 '16 at 07:18
  • And setting `_assumptions` manually is not a great idea, because if you set `integer=True` you also have to set `real=True` and `rational=True`, plus whatever else that may imply – Eric Jun 25 '16 at 07:19
  • @Eric no you don't. You can check yourself, for objects above, `is_real` is set to True automatically. – asmeurer Jun 25 '16 at 22:43