On Fri, Jan 23, 2009 at 3:38 AM, Fabian Seoane <fabian...@gmail.com> wrote:
>
> In this email, I'll expose some design ideas for the new assumptions system.
> It would be great if I get some feedback and we agree on a clear design that
> we can implement.
First of all, many thanks for all the work you have done lately, it's
really helpful and also thanks for pushing these assumptions forward.
I have also concentrated on this lately, here is what I think:
The main problem I can see with your model is, that compared to
Mathematica below, it is a more complex, compare the one liner in
mathematica and 2 or more lines in sympy:
> Comparison with Mathematica's assumption system
> ================================================
>
> What would the examples from mathematica's web page [2] look like ?
>
> M = Mathematica
> S = Sympy
>
> M: Simplify[1/Sqrt[x] - Sqrt[1/x], x > 0]
> S: x = Symbol('x', assumptions=IsPositive)
> symplify(1/sqrt(x) - sqrt(1/x))
>
> M: FunctionExpand[Log[x y], x > 0 && y > 0]
> S: x, y = Symbol('x', assumptions=IsPositive), Symbol('y',
> assumptions=IsPositive)
> log(x*y).expand()
>
> M: Simplify[Sin[n Pi], n \[Element] Integers]
> S: n = Symbol('n', assumptions=IsInteger)
> simplify(sin(n*pi))
>
> M: FunctionExpand[
> EulerPhi[m n], {m, n} \[Element] Integers && GCD[m, n] == 1]
> S: n = Symbol('n', assumptions=IsInteger)
> m = Symbol('m', assumptions=IsInteger)
> n.assumptions.add(Eq(gcd(m, n) - 1))
> euler_phi(m, n)
Also I don't like that the assumptions are assigned to the symbols
directly. See also the issue #1047 for some arguments against it.
For example, if that is possible, I'd like to have the core really
simple, so that we can easily hook our Cython core into sympy.
However, thinking about it, your model can in fact be also transformed
into my idea how things could work, let me show it on the examples
above first:
M ... Mathematica
S1 .... SymPy, your approach
S2 .... SymPy, my approach
M: Simplify[1/Sqrt[x] - Sqrt[1/x], x > 0]
S1: x = Symbol('x', assumptions=IsPositive)
simplify(1/sqrt(x) - sqrt(1/x))
S2: simplify(1/sqrt(x) - sqrt(1/x), Assumptions(x>0))
M: FunctionExpand[Log[x y], x > 0 && y > 0]
S1: x, y = Symbol('x', assumptions=IsPositive), Symbol('y',
assumptions=IsPositive)
log(x*y).expand()
S2: log(x*y).expand(Assumptions([x>0, y>0]))
M: Simplify[Sin[n Pi], n \[Element] Integers]
S1: n = Symbol('n', assumptions=IsInteger)
simplify(sin(n*pi))
S2: simplify(sin(n*pi), Assumptions(Element(n, Integer)))
# we can talk about the syntax of Element(n, Integer)
M: FunctionExpand[
EulerPhi[m n], {m, n} \[Element] Integers && GCD[m, n] == 1]
S1: n = Symbol('n', assumptions=IsInteger)
m = Symbol('m', assumptions=IsInteger)
n.assumptions.add(Eq(gcd(m, n) - 1))
euler_phi(m, n)
S2: euler_phi(m, n).expand(Assumptions([Element(n, Integer),
Element(m, Integer), Eq(gcd(m, n) - 1)]))
# again we can talk about the syntax of Element(n, Integer)
I started to implement that as well. Pull from:
http://github.com/certik/sympy/tree/assume
And use like:
In [1]: from sympy import var, Assumptions, sqrt
In [3]: var("x y z")
Out[3]: (x, y, z)
In [5]: e = abs(x)
In [6]: print e
abs(x)
In [7]: print e.refine(Assumptions(x>0))
x
In [8]: print e.refine(Assumptions(x<0))
-x
What do you think?
Ondrej
Good question. I created:
http://wiki.sympy.org/wiki/Assumptions
So far I added your suggested solution to it. How would you write the
following in your system:
e = abs(x)
print e.refine(Assumptions(x>0))
print e.refine(Assumptions(x<0))
(feel free to edit the wiki)
Ondrej
Good question. I created:
>>
>> Also I don't like that the assumptions are assigned to the symbols
>> directly. See also the issue #1047 for some arguments against it.
>
> yeah, I too think now that assumptions should not be assigned to symbols.
>
> taken from test_assumptions.py:
>
> x = Symbol('x',real=True, integer=True)
> assert x.is_real == True
>
> How could this be translated into your assumption system?
>
> x = Symbol('x')
> assert IsElement(x, Real, assumptions=Element(x, Real))
http://wiki.sympy.org/wiki/Assumptions
So far I added your suggested solution to it. How would you write the
following in your system:
e = abs(x)
print e.refine(Assumptions(x>0))(feel free to edit the wiki)
print e.refine(Assumptions(x<0))
Ondrej
I agree. Could you please fill in the last two cases for S1 and M?
Ondrej
or just assume(x>0), and it will return an Assumptions() instance. Or
maybe assuming() to return an instance, and assume() to set global
assumptions.
>
> I think it could be combined with Fabian's approach to allow user-
> defined assumptions.
>
> We could try to abuse the generator syntax to allow
>
> e = (sin(x) for x in R)
>
> or similar.
>
> Sometimes it's probably better to store assumptions in symbols (for
> instance when x is real all the time).
I think that could be something like a global assumption. But it's
true that I am still not convinced we need global assumptions.
Ondrej
Thanks for joining the discussion.
> If x refers to a real in a whole session, I think it would be really
> fastidious to use 'assume(x in R)' or something like that in every
> calculation.
That's right, but once we start to have anything global, it means that
you can never be sure what happens if you write abs(x**2) anymore,
becuase you simply don't know what global assumptions the user has.
If, on the other hand, we don't have global assumptions, I don't think
you need to use 'assume(x in R)' at every step. All you have to do is
to refine the final answer, e.g. one command.
Technically, I have nothing against global assumptions as long as they
are made explicit, e.g. if you call
e.refine()
it would consult the global assumptions and refine the answer, but if
you type abs(x**2), I think it can be quite dangerous --- but I know
that a lot of other systems do that, so we might do that as well. In
anycase, as a first step, we should implement local assumptions using
refine() and when we get this working correctly, we may think if we
want to do this globally and automagically.
Ondrej
Thanks for joining the discussion.
On Mon, Jan 26, 2009 at 2:34 PM, nico <nicolas....@gmail.com> wrote:
>
>
>> I think that could be something like a global assumption. But it's
>> true that I am still not convinced we need global assumptions.
>
> I agree with Vinzent about global assumptions.
That's right, but once we start to have anything global, it means that
> If x refers to a real in a whole session, I think it would be really
> fastidious to use 'assume(x in R)' or something like that in every
> calculation.
you can never be sure what happens if you write abs(x**2) anymore,
becuase you simply don't know what global assumptions the user has.
If, on the other hand, we don't have global assumptions, I don't think
you need to use 'assume(x in R)' at every step. All you have to do is
to refine the final answer, e.g. one command.
Technically, I have nothing against global assumptions as long as they
are made explicit, e.g. if you call
e.refine()
it would consult the global assumptions and refine the answer, but if
you type abs(x**2), I think it can be quite dangerous --- but I know
that a lot of other systems do that, so we might do that as well. In
anycase, as a first step, we should implement local assumptions using
refine() and when we get this working correctly, we may think if we
want to do this globally and automagically.
Ondrej
That's interesting, because at least for me it is actually very
intuitive to just write the equation and only then worry about
domains/assumptions, if that is needed.
Anyway, I think we can have both ways.
Ondrej
But you are a physicist ;-) (so am I)
In some ways I agree, but the typical mathematics textbook does tend
to start like this...
Let x, y and z be elements of ..... and assume that x>0. Then if, ....
I haven't been following the discussion to closely, but here is my gut feelings.
1. Avoid anything global if at all possible. What if I want to use
my sympy code with yours, but we need different global assumptions.
Ahhhhh!
2. The with statement actually gives a very nice way of expressing an
assumption that should be applied to a set of expressions. Nice idea!
+1
Cheers,
Brian