On Tue, Jun 10, 2014 at 8:13 AM, Anton Akhmerov <anton.akhme...@gmail.com> wrote: > Hi Ondrej and Aaron, > > Thanks for the replies. > > > On Tuesday, June 10, 2014 8:38:15 AM UTC+2, Ondřej Čertík wrote: >> >> Agreed, we should do that. >> >> In C++, which allows even less freedom than Python, >> I just created a FunctionSymbol class in CSymPy, you use it like: >> FunctionSymbol("a", b). The string "a" represents the name of the >> function, and you apply >> it to "b". The idea behind naming is that Symbol is "b", so >> FunctionSymbol is the function >> symbol "a". >> >> Ondrej > > > I have a question about the implementation details (and pardon my ignorance > about the overall sympy structure). I can imagine two alternative > representations of function calls: > * The original function object or its copy with args attribute set. As far > as I understand from the fact that the function name is stored as a string, > this is the implementation that Ondrej described. > * A container storing both the function and its arguments. > > I cannot easily figure out which one is more logical. A python container (C > reference) seems to be easier to maintain from the programming side: since > there is no copying involved, changing the function assumptions or > implementation would ensure that all of its calls will be updated as well. > > Several aspects that aren't as easy for me to evaluate are the interaction > of each implementation with the following: > * Built-in functions, including the basic ones like Add > * Differentiation/integration > * Assumptions > * Printing
The key thing is that the function is rebuildable from its func and its args (see below). The printing uses the name of the class to dispatch, so that may need to be modified if it doesn't work properly (I'm not sure how it works exactly). > > Another aspect that I wonder about is the interface of Expr object or even > that of Basic. Both of those have properties func and args, so they actually > implement everything that's needed from a FunctionCall (a container that I > suggested above). The only extra convention that is used (and that's what > generates all the headache with the function calls) is that the type of any > instance of expression is the same as its func property. It seems that > removing the convention that type(x) == x.func would simplify a lot of > things. This actually isn't the convention. It's only what is used 99% of the time. The convention is that expr.func(*expr.args) == expr. There is actually some debate about certain aspects of this (see https://github.com/sympy/sympy/wiki/Args-Invariant), but I think the func and args part is not debated. There is only one instance I know of in SymPy currently where expr.func != type(expr), and that is for AppliedPredicate (like Q.positive(x)). Aaron Meurer > > Anton > >> >> > >> > I guess it would break backwards compatibility. We could put the a >> > part in the .func of the FunctionCall to keep .args as just [b], and >> > also just assert that the specifics of AppliedUndef and >> > UndefinedFunction are private API, since they aren't exported with >> > from sympy import *. I guess we could alias AppliedUndef = >> > FunctionCall to keep isinstance and atoms(AppliedUndef) (see below) >> > working. >> > >> > There are no doubt other issues at stake (well one issue is that not >> > all code uses .func instead of __class__ or type correctly when >> > rebuilding expressions). >> > >> >> >> >> Does the above make sense? >> >> On a more practical note, what is 'the official' way to get all the >> >> free >> >> symbols from an expression, including functions? There's >> >> expr.atoms(Function), but it's rather hard to parse, and the closest I >> >> got >> >> to get the name from a(b).func.__name__ and check if type(type(a(b)) is >> >> and >> >> UndefinedFunction. >> > >> > You can use atoms(AppliedUndef). When you do Function('f'), that >> > creates a new class f that subclasses from AppliedUndef, itself a >> > subclass of Function. Its metaclass is UndefinedFunction. >> > >> > In [5]: f.__mro__ >> > Out[5]: >> > (f, >> > sympy.core.function.AppliedUndef, >> > sympy.core.function.Function, >> > sympy.core.function.Application, >> > sympy.core.expr.Expr, >> > sympy.core.basic.Basic, >> > sympy.core.evalf.EvalfMixin, >> > object) >> > >> > In [7]: type(f) >> > Out[7]: sympy.core.function.UndefinedFunction >> > >> > In [8]: UndefinedFunction.__mro__ >> > Out[8]: >> > (sympy.core.function.UndefinedFunction, >> > sympy.core.function.FunctionClass, >> > sympy.core.assumptions.ManagedProperties, >> > sympy.core.core.BasicMeta, >> > sympy.core.core.BasicType, >> > type, >> > object) >> > >> > free_symbols is typically better than atoms(Symbol), but I can't think >> > of any instances where a dummy variable is allowed to be a function. >> > So you may want to take the union of free_symbols and >> > atoms(AppliedUndef). >> > >> > Aaron Meurer >> > >> >> >> >> Best, >> >> Anton Akhmerov >> >> >> >> On Monday, October 28, 2013 6:16:16 PM UTC+1, Aaron Meurer wrote: >> >>> >> >>> This is correct. type() in Python basically means "class of". >> >>> Function('x') creates a class, called "x". When you apply it to t, it >> >>> creates an instance of that class. The class of the class (i.e., >> >>> metaclass) >> >>> is UndefinedFunction. >> >>> >> >>> Aaron Meurer >> >>> >> >>> On Oct 28, 2013, at 11:01 AM, Jason Moore <moore...@gmail.com> wrote: >> >>> >> >>> I'm curious why x(t) in the following code doesn't display any type: >> >>> >> >>> In [9]: x = sympy.symbols('x', cls=sympy.Function) >> >>> >> >>> In [10]: type(x) >> >>> Out[10]: sympy.core.function.UndefinedFunction >> >>> >> >>> In [11]: t = sympy.symbols('t') >> >>> >> >>> In [12]: t >> >>> Out[12]: t >> >>> >> >>> In [13]: type(x(t)) >> >>> Out[13]: x >> >>> >> >>> Jason >> >>> moorepants.info >> >>> +01 530-601-9791 >> >>> >> >>> -- >> >>> 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. >> >>> For more options, visit https://groups.google.com/groups/opt_out. >> >> >> >> -- >> >> 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/7fc55a01-a8e5-4e22-abc0-64e423a4107e%40googlegroups.com. >> >> For more options, visit https://groups.google.com/d/optout. >> > >> > -- >> > 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/CAKgW%3D6LV2oqsq8bLZ8T%2B0RaNFoZwkRC2%3Dk%3DoyzFLjP2Ju%2Bz3QA%40mail.gmail.com. >> > For more options, visit https://groups.google.com/d/optout. > > -- > 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+unsubscr...@googlegroups.com. > To post to this group, send email to sympy@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/d93dccfc-9258-46a3-a9c1-4742b1d44c68%40googlegroups.com. > > For more options, visit https://groups.google.com/d/optout. -- 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+unsubscr...@googlegroups.com. To post to this group, send email to sympy@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/CAKgW%3D6LDMje7nDOwN-id3fJgt0ZJ9BicPkz7h7kRNwHWyXXqRg%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.