Default value for Symbol

41 views
Skip to first unread message

Stewart Wadsworth

unread,
Jul 30, 2014, 11:24:29 AM7/30/14
to sy...@googlegroups.com
Hello,

I'm planning to use sympy for a project I'm working on and I have a few questions...

Basically I want to be able to associate a value with a symbol and then be able to evaluate any function using that symbol for the value it's been given. This would allow me to define properties in my classes as symbolic functions but also be able to get the numeric value for the function at the value specified for each symbol.

Question 1: Is there already a built in way to do this without having to call .subs() and .evalf() all over the place? (I'm pretty sure the answer is "no" but I could have overlooked something....)

Question 2: If not does this seem generally useful? Like something worth incorporating into sympy?

Question 3a: If it DOES seem like something worth incorporating: how can I help? (I'm somewhat new to programming and don't have any formal training...should I do a pull request and just do what I think is right?)

Question 3b: If it DOES NOT seem like something worth incorporating: I implemented this functionality by creating my own Symbol class and Monkey patching the Expr class (copied the code below). Am I missing something important here? I don't think this will break sympy... Is there a better way to approach this? I'm a beginner so any feedback would be appreciated!



CODE:

class dSymbol(Symbol):
    """
    Add a default value to Symbols
    """

    def __new__(cls, name, value, **assumptions):
        return super().__new__(cls, name, **assumptions)

    def __init__(self, name, value, **assumptions):
        self.default = value

"""
Monkey patch the Expr class (inherited by Mul, Add,... all the function classes in sympy i'm interested in using)
Add methods:
symvalue
value
"""

def symvalue(self):
    """
    returns the expression evaluated at the default value for each dSymbol
    the result is still symbolic in that pi will be displayed as 'pi' not '3.14159'...
    """
    s = self.atoms(dSymbol)
    for i in s:
        self = self.subs(i, i.default)
    return self

def value(self, *args, **kwargs):
    """
    returns the expression evaluated at the default value for each dSymbol
    the result will be numeric (assuming it doesn't contain any 'Symbol') 
    """
    return self.symvalue().evalf(*args, **kwargs)

Expr.symvalue = symvalue
Expr.value = value

Aaron Meurer

unread,
Jul 30, 2014, 8:05:32 PM7/30/14
to sy...@googlegroups.com
Don't monkeypatch Expr. If you're doing that, you're either doing
something wrong, or there's something that needs to be added to SymPy.

All you need to do is define _eval_evalf, and then calling evalf on an
expression containing your subclass will call that method and use the
result. I don't know if there is any documentation for it, but the
signature is _eval_evalf(self, prec), where prec is the precision in
decimal digits.

If you want to replace it with an exact value, rather than a numerical
value, you can define a method called doit() that returns that value.
Then call doit() on the top-level expression.

Aaron Meurer
> --
> You received this message because you are subscribed to the Google Groups
> "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sympy+un...@googlegroups.com.
> To post to this group, send email to sy...@googlegroups.com.
> Visit this group at http://groups.google.com/group/sympy.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sympy/b12b7e28-aff2-4168-a3a2-c9f5ee67e1ad%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Stewart Wadsworth

unread,
Aug 10, 2014, 9:58:27 PM8/10/14
to sy...@googlegroups.com
Aaron,

Thanks for the tip. _eval_evalf made it a lot simpler.

The problem I'm having now is I'm trying to do some multiple inheritance where I inherit from Symbol and another class that I've written.

The issue I'm having is that Symbol overrides __new__ so (it feels like) I'm basically forced into using the same signature for __new__ in my other class which is not really desirable.

I noticed that the only class that implements __new__ that Symbol inherits from is Basic (and it inherits? from a few meta classs which implement __init__ ... but that's getting pretty far over my head) I don't think I can get away with not having a __new__ or __init__ in the other class I'm trying to inherit from

Could you point me in the right direction for getting around this? I'm fine with always inheriting from sympy Basic if that would some how take care of it.

Or do I need to implement __new_stage2__ in the other class or something?

Aaron Meurer

unread,
Aug 13, 2014, 7:45:55 PM8/13/14
to sy...@googlegroups.com
On Sun, Aug 10, 2014 at 8:58 PM, Stewart Wadsworth <stewart....@gmail.com> wrote:
Aaron,

Thanks for the tip. _eval_evalf made it a lot simpler.

The problem I'm having now is I'm trying to do some multiple inheritance where I inherit from Symbol and another class that I've written.

The issue I'm having is that Symbol overrides __new__ so (it feels like) I'm basically forced into using the same signature for __new__ in my other class which is not really desirable.

I noticed that the only class that implements __new__ that Symbol inherits from is Basic (and it inherits? from a few meta classs which implement __init__ ... but that's getting pretty far over my head) I don't think I can get away with not having a __new__ or __init__ in the other class I'm trying to inherit from

Don't mind the metaclasses. A metaclass's __init__ gets called before the class's __new__. 

I'm not sure if you can reasonably change the __new__ constructor. Stackoverflow will probably provide more wisdom than I can. You'll need to make fortuitous use of super() most likely.  Understanding how classes work in Python is a good start. I saw a good PyCon talk metaclasses that's a good introduction to both classes and metaclasses. I think https://www.youtube.com/watch?v=ANhTacigaf8 is the one.

 

Could you point me in the right direction for getting around this? I'm fine with always inheriting from sympy Basic if that would some how take care of it.

That should work too. From a philosophical perspective, you shouldn't subclass from Symbol unless you actually want to use the same interface, which includes the argument to the constructor. 
 

Or do I need to implement __new_stage2__ in the other class or something?

I don't know what that does. I've never seen a subclass implement it. I think it has something to do with making assumptions work correctly. Ugh, I don't like this old assumptions metaclass nonsense in the core that no one can understand. 

Aaron Meurer

Reply all
Reply to author
Forward
0 new messages