automatically defining variables names

1 view
Skip to first unread message

William Stein

unread,
Nov 17, 2009, 10:51:41 PM11/17/09
to sage-devel, sage-notebook, Fernando Perez
Hi,

Dozens of times over the years, people have complained because in Sage
symbolic variables names don't magically spring into existence, and
also about object-oriented method call notation. We have defended
this design forever, not even considering providing a non-default
optional mode what variables do spring into existence etc. Well not
anymore.

sage: automatic_names(True)
sage: x + y + z + wxy
wxy + x + y + z
sage: y(y=10)
10
sage: type(y)
<class 'sagenb.misc.support.AutomaticVariable'>
sage: trig_expand((2*x + 4*y + sin(2*theta))^2)
4*(sin(theta)*cos(theta) + x + 2*y)^2

Try this now at http://alpha.sagenb.org

Also see the ticket with a patch that needs review:

http://trac.sagemath.org/sage_trac/ticket/7482

First there is a little simple demo code so one can play with this.
Then there is a real much more carefully thought through patch.


Can somebody referee this? It's mainly code in the *notebook* --
it doesn't seem possible to do something like the above on the command
line without some deep internal change to Ipython.

Let me know if you're interesting in refereeing this but find the
combination of messing with the sagenb code and sage library too
daunting.


--
William Stein
Associate Professor of Mathematics
University of Washington
http://wstein.org

Fernando Perez

unread,
Nov 18, 2009, 4:23:23 AM11/18/09
to sage-n...@googlegroups.com, sage-devel, Fernando Perez
On Tue, Nov 17, 2009 at 7:51 PM, William Stein <wst...@gmail.com> wrote:
> Can somebody referee this?     It's mainly code in the *notebook* --
> it doesn't seem possible to do something like the above on the command
> line without some deep internal change to Ipython.
>

Actually no, not that hard: ipython executes all user code inside a
dict created at initialization time. One could replace this (today a
plain python dict) with another dict that would implement the
requested behavior. This would spring variables into existence when a
KeyError was about to occur.

The command-line doesn't have the notion of a cell (yet, that will
hopefully change soon) but it could be toggled with a function call.

It's basically a matter of instantiating the initial ipython with a
custom user_ns dict that does the above, that should be all. And
providing a magic (or even plain) function in the global namespace to
toggle this behavior on/off at runtime.

The attached file (run it as 'ipauto.py') shows how it could work, I
didn't implement the toggling and it's a quick hack, but the basic
idea is there. Here it is in action:

In [1]: %autocall 0
Automatic calling is: OFF

In [2]: x+y
Injecting x
Injecting y
Out[2]: x + y

In [3]: type(x)
Out[3]: <class 'sympy.core.symbol.Symbol'>

In [4]: x+3
Out[4]: 3 + x

In [5]: x**2+x*x
Out[5]: 2*x**2

In [6]: x+z**3
Injecting z
Out[6]: x + z**3


A couple of notes:

- It's key to disable autocalling for this to work, otherwise too many
false positives are triggered. If this idea proves to have wings, it
will be one more argument in favor of disabling autocalling (it just
has too many uncontrollable side effects).

- Unfortunately IPython as shipped needs a tiny patch for this to
work, due to a really silly omission. The patch is a trivial 2-liner,
in case anyone wants to take this further for Sage:

(ipython-0.10)maqroll[0.10]> bzr diff
=== modified file 'IPython/Shell.py'
--- IPython/Shell.py 2009-04-14 20:12:02 +0000
+++ IPython/Shell.py 2009-11-18 09:03:01 +0000
@@ -1230,7 +1230,7 @@


# This is the one which should be called by external code.
-def start(user_ns = None):
+def start(user_ns = None, user_global_ns = None):
"""Return a running shell instance, dealing with threading options.

This is a factory function which will instantiate the proper IPython shell
@@ -1238,7 +1238,7 @@
different GUI toolkits require different thread handling details."""

shell = _select_shell(sys.argv)
- return shell(user_ns = user_ns)
+ return shell(user_ns = user_ns, user_global_ns = user_global_ns)

# Some aliases for backwards compatibility
IPythonShell = IPShell



Cheers,

f
ipauto.py

William Stein

unread,
Nov 18, 2009, 4:34:25 AM11/18/09
to sage-n...@googlegroups.com, sage-devel, Fernando Perez
On Wed, Nov 18, 2009 at 1:23 AM, Fernando Perez <fpere...@gmail.com> wrote:
> On Tue, Nov 17, 2009 at 7:51 PM, William Stein <wst...@gmail.com> wrote:
>> Can somebody referee this?     It's mainly code in the *notebook* --
>> it doesn't seem possible to do something like the above on the command
>> line without some deep internal change to Ipython.
>>
>
> Actually no, not that hard: ipython executes all  user  code inside a

Awesome. I've made a new ticket for doing a command-line version for Sage:

http://trac.sagemath.org/sage_trac/ticket/7486

and I've posted your email and code there.

I will also try using a dictionary instead catching NameError's. I
don't know if that will robustly work in all cases for the notebook,
but we'll see.
In Sage autocall is disabled by default, since it is too confusing.

> - Unfortunately IPython as shipped needs a tiny patch for this to
> work, due to a really silly omission.  The patch is a trivial 2-liner,
> in case anyone wants to take this further for Sage:
>
> (ipython-0.10)maqroll[0.10]> bzr diff
> === modified file 'IPython/Shell.py'
> --- IPython/Shell.py    2009-04-14 20:12:02 +0000
> +++ IPython/Shell.py    2009-11-18 09:03:01 +0000
> @@ -1230,7 +1230,7 @@
>
>
>  # This is the one which should be called by external code.
> -def start(user_ns = None):
> +def start(user_ns = None, user_global_ns = None):
>     """Return a running shell instance, dealing with threading options.
>
>     This is a factory function which will instantiate the proper IPython shell
> @@ -1238,7 +1238,7 @@
>     different GUI toolkits require different thread handling details."""
>
>     shell = _select_shell(sys.argv)
> -    return shell(user_ns = user_ns)
> +    return shell(user_ns = user_ns, user_global_ns = user_global_ns)
>
>  # Some aliases for backwards compatibility
>  IPythonShell = IPShell

Thanks!

-- William

Fernando Perez

unread,
Nov 18, 2009, 5:06:13 AM11/18/09
to sage-...@googlegroups.com, sage-n...@googlegroups.com, Fernando Perez
On Wed, Nov 18, 2009 at 1:34 AM, William Stein <wst...@gmail.com> wrote:
> Awesome.  I've made a new ticket for doing a command-line version for Sage:
>
>   http://trac.sagemath.org/sage_trac/ticket/7486
>

Great! And please send it our way once ready. If sage improvements
to ipython go to ipython, all users (including sage) benefit.
Otherwise only sage benefits; the more you upstream improvements, the
more we all gain.

I'm sure this is the type of extension that others (sympy, etc) could
also use; as long as the default name generator can be controlled.
Sage would emit its own variables, sympy would use sympy.var(),
someone in another context could emit whatever makes sense in their
environment, etc. We'd be happy to include this as an optional
ipython tool if you make it available to us!

Cheers,

f
Reply all
Reply to author
Forward
0 new messages