New Member Introduction

121 views
Skip to first unread message

BHASKAR JOSHI

unread,
Sep 14, 2020, 1:36:46 PM9/14/20
to sympy
Hello,
I am Bhaskar Joshi, and I am currently a second-year Computer Science Undergraduate at IIIT Hyderabad. I want to make contributions to this organization and would love to continue contributing for GSoC 2021. I would request the mentors and experienced developers to please guide me throughout the process. 
Thanks

Mann Patel

unread,
Sep 16, 2020, 10:48:26 AM9/16/20
to sympy
Hello,
My name is Mann Patel currently pursuing Computer Science in Indus University 2nd year.i want to contribute in this organization and i am familiar with python for almost one year and have created projects on python like web development and data analysis projects and i would like to continue contributing for GsoC 2021.I request the Mentors to please guide me so i can contribute for Gsoc 2021.

David Bailey

unread,
Sep 19, 2020, 3:46:04 PM9/19/20
to sy...@googlegroups.com

Dear All,

I was hoping to use SymPy patterns to perform a transformation equivalent to this Mathematica code:

f[a + 2*b + c] /. f[x_] -> g[x]

      g[a + 2 b + c]

I.e. I wanted to replace calls to the (undefined) function f with calls to the function g with the same arguments.

I tried the following, with f and g set up as undefined functions:

patt=Wild("p1")

f(a+2*b+c).subs(f(patt),g(patt))

     f(a + 2*b + c)

Is there a way to do this?

David

    







Davide Sandona'

unread,
Sep 19, 2020, 3:51:06 PM9/19/20
to sy...@googlegroups.com
Hello David,
in Sympy there are three substitution methods:
1. subs: it is the most generic.
2. xreplace: it only replace the exact expression you provide.
3. replace: this is the most powerful, as it allows for "pattern matching operations".

In your case, I would do something like this:

f, g = symbols("f, g", cls=Function)
a, b, c = symbols("a:c")
expr = f(a + 2 * b + c)
expr.replace(f, g)

Davide.


--
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 view this discussion on the web visit https://groups.google.com/d/msgid/sympy/87d22d50-3fd2-101e-7dc2-ad90843b06ca%40dbailey.co.uk.

David Bailey

unread,
Sep 19, 2020, 6:35:07 PM9/19/20
to sy...@googlegroups.com
On 19/09/2020 20:50, Davide Sandona' wrote:
Hello David,
in Sympy there are three substitution methods:
1. subs: it is the most generic.
2. xreplace: it only replace the exact expression you provide.
3. replace: this is the most powerful, as it allows for "pattern matching operations".

In your case, I would do something like this:

f, g = symbols("f, g", cls=Function)
a, b, c = symbols("a:c")
expr = f(a + 2 * b + c)
expr.replace(f, g)

Thanks for that quick response! Unfortunately I don't think your solution really generalises. I mean suppose I wanted to replace

f(anything) by g(5*anything**2)

(again that would be easy in Mathematica - the transformation would be f[x_] -> g[5*x^2] )

I mean, clearly those patterns are there to solve problems like that, and I can't figure out how to use them effectively.

David

Oscar Benjamin

unread,
Sep 19, 2020, 6:43:45 PM9/19/20
to sympy
On Sat, 19 Sep 2020 at 23:35, David Bailey <da...@dbailey.co.uk> wrote:
>
> On 19/09/2020 20:50, Davide Sandona' wrote:
>
> Hello David,
> in Sympy there are three substitution methods:
> 1. subs: it is the most generic.
> 2. xreplace: it only replace the exact expression you provide.
> 3. replace: this is the most powerful, as it allows for "pattern matching operations".
>
> In your case, I would do something like this:
>
> f, g = symbols("f, g", cls=Function)
> a, b, c = symbols("a:c")
> expr = f(a + 2 * b + c)
> expr.replace(f, g)
>
> Thanks for that quick response! Unfortunately I don't think your solution really generalises. I mean suppose I wanted to replace
>
> f(anything) by g(5*anything**2)

Hi David,

You can do this using replace but instead of replacing f with g you
can ask to replace all instances of f with a function that will
process the argument(s) that f had. It is convenient to do this in
Python using a lambda function:

In [7]: f = Function('f')

In [8]: g = Function('g')

In [9]: expr = f(1 + sqrt(2))

In [10]: expr.replace(f, lambda arg: g(5*arg**2))
Out[10]:
⎛ 2⎞
g⎝5⋅(1 + √2) ⎠

I'm not sure how well that displays in the email. It looks pretty
screwy in gmail as I write it but I think it does what you want!

Oscar

Oscar Benjamin

unread,
Sep 20, 2020, 6:57:57 AM9/20/20
to David Bailey, sympy
On Sun, 20 Sep 2020 at 10:42, David Bailey <da...@dbailey.co.uk> wrote:
> Thanks Oscar,
>
> Wow - that is ingenious, and it will take me a while to think out how much of Mathematica's pattern functionality can be achieved this way.
>
> However, I am curious, What are the patterns produced by the Wild function actually used for - or are these an attempt to reproduce Mathematica's pattern functionality (which is really neat) that is yet to be finished?

Hi David (CCing the list),

I haven't used Mathematica's pattern functionality myself so I'm
interested to hear how it compares.

The patterns made with Wild are used to extract the components of the
expression that match the Wild symbols so that you can use them for
other things. Suppose that I want to test if an expression is of the
form sin(a*x + b) and if so identify a and b so that I can use them to
build another expression. Then I can do:

In [7]: a = Wild('a')

In [8]: b = Wild('b')

In [9]: x = Symbol('x')

In [10]: expr = sin(sqrt(2)*x - 1)

In [11]: pattern = sin(a*x + b)

In [12]: expr.match(pattern)
Out[12]: {a: √2, b: -1}

In [13]: m = expr.match(pattern)

In [14]: cos(m[a]*x + m[b])
Out[14]: cos(√2⋅x - 1)

Of course you might want to do something more complicated than just
replace sin with cos so it is useful to be able to extract the values
m[a] and m[b]. For example if m[a] was equal to 2 you could apply the
double angle formula or something like that.

You can also use the Wild symbols with replace like:

In [7]: expr.replace(sin(a*x + b), cos(a*x + b))
Out[7]: cos(√2⋅x - 1)

You can also use a Wild pattern with find to extract sub-expressions
matching a pattern:

In [7]: expr = Integral(1 + sin(2*x + 1) + sin(3*x), x)

In [8]: expr
Out[8]:

⎮ (sin(3⋅x) + sin(2⋅x + 1) + 1) dx


In [9]: expr.find(sin(a*x + b))
Out[9]: {sin(3⋅x), sin(2⋅x + 1)}

This basically calls match recursively on all subtrees of the
expression so it can be quite inefficient for larger expressions. If
the objective was just to find all examples of sin then atoms is more
efficient:

In [10]: expr.atoms(sin)
Out[10]: {sin(3⋅x), sin(2⋅x + 1)}


Oscar

David Bailey

unread,
Sep 20, 2020, 7:02:28 AM9/20/20
to sy...@googlegroups.com
On 19/09/2020 23:46, Oscar Benjamin wrote:

Thanks Oscar,

Wow - that is ingenious, and it will take me a while to think out how much of Mathematica's pattern functionality can be achieved this way.

However, I am curious, What are the patterns produced by the Wild function actually used for - or are these an attempt to reproduce Mathematica's pattern matching functionality (which is really neat) that is yet to be finished?

David

David Bailey

unread,
Sep 20, 2020, 7:40:07 AM9/20/20
to sy...@googlegroups.com
Hi David (CCing the list),

Yes, I know - I need to remember to press"Reply List" rather than "Reply" in Thunderbird!


I haven't used Mathematica's pattern functionality myself so I'm
interested to hear how it compares.

Sure - to use your example:


In[2]:= Sin[a*x + b] /. Sin[x*p1_. + p2_.] -> Cos[x*p1 + p2]

Out[2]= Cos[b + a x]

p1_ matches anything and p1_. also matches nothing by default in the context of multiplication (i.e.  1). Since p2_. is used in the context of addition, it matches zero by default. On the RHS there are referred to as p1 and p2 (which implies some rather complicated scoping rules that only apply within the replacement operation.

Here I make use of both the defaults (p1=1 and p2=0)

In[5]:= Sin[x] /. Sin[x*p1_. + p2_.] -> Cos[x*p1 + p2]unwanted

Out[5]= Cos[x]

These replacements do not have to be at the top level:

In[6]:= Exp[Sin[a*x + b]] /. Sin[x*p1_ + p2_.] -> Cos[x*p1 + p2]

Out[6]= E^Cos[b + a x]

There is also a variant of ->, :> which suppressed certain possible evaluations, but My Mathematica is fairly rusty.

Of course every Mathematica operator - such as '->' and '/.' has a long form which avoids remembering all the various operator precedences.

The sheer compactness of these replacements makes replacement operations very popular for algebraic manipulations.

Because you do actually extract the values taken on by the patterns in those examples, I rather wonder if something more like Mathematica replacements could be constructed out of what is already available in SymPy?

David

Oscar Benjamin

unread,
Sep 20, 2020, 12:26:15 PM9/20/20
to sympy
On Sun, 20 Sep 2020 at 12:40, David Bailey <da...@dbailey.co.uk> wrote:
>
> Hi David (CCing the list),
>
> Yes, I know - I need to remember to press"Reply List" rather than "Reply" in Thunderbird!

The reply-to header for the list is set to go back to the list so when
I use reply it always goes to the list.

> I haven't used Mathematica's pattern functionality myself so I'm
> interested to hear how it compares.
>
> Sure - to use your example:
>
>
> In[2]:= Sin[a*x + b] /. Sin[x*p1_. + p2_.] -> Cos[x*p1 + p2]
>
> Out[2]= Cos[b + a x]

This can be done with replace:

In [37]: x, a, b = symbols('x, a, b')

In [38]: p1 = Wild('p1')

In [39]: p2 = Wild('p2')

In [40]: sin(a*x + b).replace(sin(p1*x + p2), cos(p1*x + p2))
Out[40]: cos(a⋅x + b)

> p1_ matches anything and p1_. also matches nothing by default in the context of multiplication (i.e. 1). Since p2_. is used in the context of addition, it matches zero by default. On the RHS there are referred to as p1 and p2 (which implies some rather complicated scoping rules that only apply within the replacement operation.
>
> Here I make use of both the defaults (p1=1 and p2=0)
>
> In[5]:= Sin[x] /. Sin[x*p1_. + p2_.] -> Cos[x*p1 + p2]unwanted
>
> Out[5]= Cos[x]

It is possible to match with values of 1 or 0 for the wild symbols:

In [47]: sin(x).match(sin(p1*x + p2))
Out[47]: {p₁: 1, p₂: 0}

I'm not sure why that doesn't carry through to replace when p2 should
be zero (possibly a bug):

In [49]: sin(x).replace(sin(p1*x + p2), cos(p1*x + p2))
Out[49]: sin(x)

In [50]: sin(2*x).replace(sin(p1*x + p2), cos(p1*x + p2))
Out[50]: sin(2⋅x)

In [51]: sin(x + 1).replace(sin(p1*x + p2), cos(p1*x + p2))
Out[51]: cos(x + 1)

> These replacements do not have to be at the top level:
>
> In[6]:= Exp[Sin[a*x + b]] /. Sin[x*p1_ + p2_.] -> Cos[x*p1 + p2]
>
> Out[6]= E^Cos[b + a x]

That's also the case with replace:

In [52]: exp(sin(a*x + b)).replace(sin(p1*x + p2), cos(p1*x + p2))
Out[52]:
cos(a⋅x + b)


> There is also a variant of ->, :> which suppressed certain possible evaluations, but My Mathematica is fairly rusty.
>
> Of course every Mathematica operator - such as '->' and '/.' has a long form which avoids remembering all the various operator precedences.
>
> The sheer compactness of these replacements makes replacement operations very popular for algebraic manipulations.

The main difference as far as I tell compared to replace is the need
to create the Wild symbols explicitly. Maybe we could add a bunch of
those to sympy.abc with names like p1_ and p2_ (are those names
standardised?).

> Because you do actually extract the values taken on by the patterns in those examples, I rather wonder if something more like Mathematica replacements could be constructed out of what is already available in SymPy?

I think so. What more would you want compared to the replace examples
above? SymPy itself is embedded within the Python programming language
and so direct use of sympy can not invent syntactic operators like /.
because those aren't legal Python syntax. Within the constraints of
Python though what would make the wildcard matching more palatable?

I haven't used this at all myself but you might be interested by mathics:
http://mathics.github.io/
""
Mathics is a free, general-purpose online computer algebra system
featuring Mathematica-compatible syntax and functions. It is backed by
highly extensible Python code, relying on SymPy for most mathematical
tasks.
"""
Since mathics is implemented in Python but allows users to write code
in another language it can give users whatever syntax it wants. I
don't know if the /. syntax is supported.

Oscar

David Bailey

unread,
Sep 20, 2020, 4:13:44 PM9/20/20
to sy...@googlegroups.com
On 20/09/2020 17:29, Oscar Benjamin wrote:

The main difference as far as I tell compared to replace is the need
to create the Wild symbols explicitly. Maybe we could add a bunch of
those to sympy.abc with names like p1_ and p2_ (are those names
standardised?).

Those examples are a revelation! I think they should be added to the documentation of replace and Wild(). I must admit I thought I'd tried something like that with replace, but without success - maybe I hit a bug?

Of course I realise that SymPy can't start defining operators like /. -> etc. In any case, one irritation with Mathematica, is that there are just too many operator precedences to remember!

The only thing that is standard about the names is the _ on the end, the rest of the name is chosen by the user, if you named the pattern variables with a trailing _ in abc , then I think it would be really friendly - I mean I think a CAS needs to be easy to use.

Given that functionality, the pattern matching looks pretty good. One other thing is that Mathematica also has a way to define a pattern that only matches if a predicate returns True when applied to it, for example:

p1_?Even

There are also some more obscure things that can be done with Mathematica patterns, but probably these are of lesser importance. Also patterns are used in some other contexts, for example a user defined function is written with pattern variables as arguments. This allows for overloaded functions.

It sounds as if the real thing that needs doing is documenting these features!

I haven't used this at all myself but you might be interested by mathics:
http://mathics.github.io/
""
Mathics is a free, general-purpose online computer algebra system
featuring Mathematica-compatible syntax and functions. It is backed by
highly extensible Python code, relying on SymPy for most mathematical
tasks.
"""

I did consider  this, but it became clear that it isn't being actively supported. For example, it required a specific (out of date) version of Python. I'd certainly not get anything like the support that your group offer! Besides, by now, I have got somewhat under the hood of SymPy.

David

Oscar Benjamin

unread,
Sep 20, 2020, 6:19:02 PM9/20/20
to sympy
On Sun, 20 Sep 2020 at 21:13, David Bailey <da...@dbailey.co.uk> wrote:
>
> On 20/09/2020 17:29, Oscar Benjamin wrote:
>
> The main difference as far as I tell compared to replace is the need
> to create the Wild symbols explicitly. Maybe we could add a bunch of
> those to sympy.abc with names like p1_ and p2_ (are those names
> standardised?).
>
> Those examples are a revelation! I think they should be added to the documentation of replace and Wild(). I must admit I thought I'd tried something like that with replace, but without success - maybe I hit a bug?
>
> Of course I realise that SymPy can't start defining operators like /. -> etc. In any case, one irritation with Mathematica, is that there are just too many operator precedences to remember!
>
> The only thing that is standard about the names is the _ on the end, the rest of the name is chosen by the user, if you named the pattern variables with a trailing _ in abc , then I think it would be really friendly - I mean I think a CAS needs to be easy to use.

We could add a bunch of a_, b_ etc. It's common in the sympy codebase
to create a Wild with something like Wild('a', exclude=[x]). The
reason is that you might want to exclude some kinds of matches:

In [1]: x = Symbol('x')

In [2]: a = Wild('a')

In [3]: ax = Wild('ax', exclude=[x])

In [4]: sin(x**2).match(sin(a*x))
Out[4]: {a: x}

In [5]: sin(x**2).match(sin(ax*x))

In [6]: print(sin(x**2).match(sin(ax*x)))
None

If we had Wilds in abc then they wouldn't have those kinds of
exclusion patterns.

> Given that functionality, the pattern matching looks pretty good. One other thing is that Mathematica also has a way to define a pattern that only matches if a predicate returns True when applied to it, for example:
>
> p1_?Even

This can also be done with Wild using properties:

In [12]: ae = Wild('ae', properties=[lambda a: a.is_even])

In [13]: print(cos(2*x).match(cos(ae*x)))
{ae_: 2}

In [14]: print(cos(3*x).match(cos(ae*x)))
None

> There are also some more obscure things that can be done with Mathematica patterns, but probably these are of lesser importance. Also patterns are used in some other contexts, for example a user defined function is written with pattern variables as arguments. This allows for overloaded functions.
>
> It sounds as if the real thing that needs doing is documenting these features!

Yes, I guess so. I have actually been writing some docs for the old
assumptions since the last thread but they are not yet complete:
https://github.com/sympy/sympy/pull/20090
https://github.com/sympy/sympy/pull/20090/files

> I haven't used this at all myself but you might be interested by mathics:
> http://mathics.github.io/
> ""
> Mathics is a free, general-purpose online computer algebra system
> featuring Mathematica-compatible syntax and functions. It is backed by
> highly extensible Python code, relying on SymPy for most mathematical
> tasks.
> """
>
> I did consider this, but it became clear that it isn't being actively supported. For example, it required a specific (out of date) version of Python. I'd certainly not get anything like the support that your group offer! Besides, by now, I have got somewhat under the hood of SymPy.

The reason I know of mathics is because mathics contributors have
raised issues with sympy on github so I think there is some
maintenance going on. I just followed the installation instructions
with Python 3.8 and got an error when I tried to run mathics. With
Python 3.7 it worked though. With that I get:

$ mathics

Mathics 1.0
on CPython 3.7.6 (default, Jan 8 2020, 13:42:34)
using SymPy 1.0, mpmath 1.1.0

Copyright (C) 2011-2016 The Mathics Team.
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions.
See the documentation for the full license.

Quit by pressing CONTROL-D

In[1]:= Sin[a*x + b] /. Sin[x*p1_. + p2_.] -> Cos[x*p1 + p2]
Out[1]= Cos[a x + b]


Oscar

David Bailey

unread,
Sep 20, 2020, 6:54:32 PM9/20/20
to sy...@googlegroups.com
On 20/09/2020 23:22, Oscar Benjamin wrote:

If we had Wilds in abc then they wouldn't have those kinds of
exclusion patterns.

True, but this is analogous to the fact that 'f' is defined as an ordinary symbol in abc, even though you may want to redefine it as a function symbol. Defining things in abc doesn't in any way stop people redefining them - it just provides for the most typical situations - which helps to get people started.

Thanks for the help today - you have just disentangled a number of issues for me!

David

Reply all
Reply to author
Forward
0 new messages