This is indeed a very interesting application of SymPy. Here we see one example of the power of symbolic computer algebra systems, which is that symbolic preprocessing, even very simple preprocessing like what we have here, can greatly optimize arbitrary code execution.
If your expressions are complicated enough (like polynomials or rational functions in your functions), you could probably optimize them even further by applying simplification functions to expressions. And for your use case, cse() could be a useful optimization. Aaron Meurer On Jun 2, 2011, at 9:03 AM, luke wrote: > Oh, thanks a lot. Now it's working fine. > Now the only problem is that the code is evaluated when calling > sympify, and not when calling evalf. > Could I ask you what is the way to keep the function lazy? I explain > myself better. Since the function SUM has to operate on a database if > I have something like that: > >>>> SUM('field') + SUM('field') + SUM('field') #not lazy, computes immediately >>>> three queries >>>> 1234 > > I'm doing the same operation three times and this is not very good in > terms of performances, what I expected would have been: > >>>> a = SUM('field') + SUM('field') + SUM('field') -> 3SUM('field') # one >>>> single query >>>> print a >>>> 3*SUM('field') >>>> print N(a) >>>> 1234 > > just like other functions work. e.g. > >>>> log(10)+log(10)+log(10) >>>> 3*log(10) > > On Jun 2, 9:38 am, Mateusz Paprocki <matt...@gmail.com> wrote: >> Hi, >> >> On 2 June 2011 09:07, luke <luca.giaco...@gmail.com> wrote: >> >> >> >> >> >> >> >> >> >>> Hi eveyone, >>> I'm developing an web application which has to interact with "user- >>> defined formulas" of some financial kpis. >>> I decided to use sympy to have a more solid math engine. >>> Basically the input I reiceve is very simple, it might be in the worst >>> case something like: >> >>> kpi -> "(log(sum('production'))*count('sales')/min('spread')" (this >>> formula is totally made-up) >> >>> I defined some functions to interact with the database according to >>> the official docs and they seem to be working: >> >>> For example defining >> >>> from sympy.core.function import Function >> >>> class SUM(Function): >>> nargs = 2 >>> @classmethod >>> def eval(cls, arg): >>> map = Code("""function () { >>> emit("sum",{%(field)s:this.%(field)s}); >>> }""" % {'field':arg}) >>> reduce = Code(""" >>> function(key, values) { >>> var sum = 0; >>> values.forEach(function(doc) { >>> if (doc.%(field)s != undefined){ >>> sum += doc.%(field)s; >>> } >>> }); >>> return {%(field)s:sum}; >>> };""" % {'field':arg}) >>> result = db.people.map_reduce(map, reduce, "myresults") >>> return result.find_one()['value'][unicode(arg)] >> >>> #EOF >> >>> Then from the command line I can type: >> >>>>>> print SUM("field") >>>>>> 1923 >> >> Very interesting application. I'm not sure if you are familiar with this, >> but staying on the safe side note here that SUM("field") doesn't do exactly >> what you expect, but the outcome is fine. Usually, SymPy's functions don't >> accept raw string arguments, but sympify() them: >> >> In [1]: class fun(Function): >> ...: nargs = 1 >> ...: @classmethod >> ...: def eval(cls, arg): >> ...: print type(arg) >> ...: >> ...: >> >> In [2]: fun('abc') >> <class 'sympy.core.symbol.Symbol'> >> Out[2]: fun(abc) >> >> So in eval() you got a symbol not string 'abc', but as str() of a Symbol is >> simply the name of the symbol, then this (and your code) works as expected: >> >> In [3]: print "---%s---" % Symbol('abc') >> ---abc--- >> >> >> >>> But when I try to use sympify my function doesn't evaluate.. >> >>>>>> print sympify("SUM('field')").evalf() >>>>>> SUM(field) >>>>>> N("SUM('field')") >>>>>> SUM(field) >> >> The problem here is that SymPy, precisely speaking sympify(), doesn't know >> what SUM() is, because SUM() resides in the global namespace of the >> interpreter, which is unknown to sympify(), e.g.: >> >> In [4]: sympify("whatever(10)") >> Out[4]: whatever(10) >> >> whatever() is unknown to sympify(), so a new Function object is constructed >> for it. The same for fun() which I defined above: >> >> In [6]: sympify("fun(10)") >> Out[6]: fun(10) >> >> To overcome this, pass globals() to sympify(), e.g.: >> >> In [7]: sympify("fun(10)", globals()) >> <class 'sympy.core.numbers.Integer'> >> Out[7]: fun(10) >> >> (in your case this will be sympify("SUM('field')", globals())). >> >> >> >>> Am I doing anything wrong? >>> Thanks in advance! >> >>> -- >>> You received this message because you are subscribed to the Google Groups >>> "sympy" group. >>> To post to this group, send email to sympy@googlegroups.com. >>> To unsubscribe from this group, send email to >>> sympy+unsubscr...@googlegroups.com. >>> For more options, visit this group at >>> http://groups.google.com/group/sympy?hl=en. >> >> Mateusz > > -- > You received this message because you are subscribed to the Google Groups > "sympy" group. > To post to this group, send email to sympy@googlegroups.com. > To unsubscribe from this group, send email to > sympy+unsubscr...@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/sympy?hl=en. > -- You received this message because you are subscribed to the Google Groups "sympy" group. To post to this group, send email to sympy@googlegroups.com. To unsubscribe from this group, send email to sympy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sympy?hl=en.