Opened 6 years ago

# Effectively can't create a symbolic variable named 'lambda'

Reported by: Owned by: wonder major sage-6.8 symbolics N/A

This is closely related to #13545, but is not a duplicate.

It is possible to create a variable whose name is 'lambda' by bypassing the SR.var() function, which prohibits it. However, this leads to crashes later, when that function is used internally:

sage: l = SR.symbol('lambda')
sage: l
lambda
sage: latex(l)
\lambda
sage: l^2
lambda^2
sage: solve( l^2, l )
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-50da04b743b5> in <module>()
----> 1 solve( l**Integer(2), l )

/usr/local/src/sage/local/lib/python2.7/site-packages/sage/symbolic/relation.pyc in solve(f, *args, **kwds)
796     from sage.symbolic.expression import is_Expression
797     if is_Expression(f): # f is a single expression
--> 798         ans = f.solve(*args,**kwds)
799         return ans
800

/usr/local/src/sage/src/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression.solve (build/cythonized/sage/symbolic/expression.cpp:48303)()
10006         from sage.symbolic.relation import string_to_list_of_solutions
10007
> 10008         X = string_to_list_of_solutions(s) # our initial list of solutions
10009
10010         if multiplicities: # to_poly_solve does not return multiplicities, so in this case we end here

/usr/local/src/sage/local/lib/python2.7/site-packages/sage/symbolic/relation.pyc in string_to_list_of_solutions(s)
535     from sage.structure.sequence import Sequence
536     from sage.calculus.calculus import symbolic_expression_from_maxima_string
--> 537     v = symbolic_expression_from_maxima_string(s, equals_sub=True)
538     return Sequence(v, universe=Objects(), cr_str=True)
539

/usr/local/src/sage/local/lib/python2.7/site-packages/sage/calculus/calculus.pyc in symbolic_expression_from_maxima_string(x, equals_sub, maxima)
1906             global _augmented_syms
1907             _augmented_syms = syms
-> 1908             return SRM_parser.parse_sequence(s)
1909         finally:
1910             _augmented_syms = {}

/usr/local/src/sage/src/sage/misc/parser.pyx in sage.misc.parser.Parser.parse_sequence (build/cythonized/sage/misc/parser.c:4529)()
539         return expr
540
--> 541     cpdef parse_sequence(self, s):
542         """
543         Parse a (possibly nested) set of lists and tuples.

/usr/local/src/sage/src/sage/misc/parser.pyx in sage.misc.parser.Parser.parse_sequence (build/cythonized/sage/misc/parser.c:4405)()
555         """
556         cdef Tokenizer tokens = Tokenizer(s)
--> 557         all = self.p_sequence(tokens)
558         if tokens.next() != EOS:
559             self.parse_error(tokens)

/usr/local/src/sage/src/sage/misc/parser.pyx in sage.misc.parser.Parser.p_sequence (build/cythonized/sage/misc/parser.c:5117)()
619                     obj = self.p_eqn(tokens)
620             elif token == '[':
--> 621                 obj = self.p_list(tokens)
622             elif token == '(':
623                 obj = self.p_tuple(tokens)

/usr/local/src/sage/src/sage/misc/parser.pyx in sage.misc.parser.Parser.p_list (build/cythonized/sage/misc/parser.c:5436)()
651         if token != '[':
652             self.parse_error(tokens, "Malformed list")
--> 653         all = self.p_sequence(tokens)
654         token = tokens.next()
655         if token != ']':

/usr/local/src/sage/src/sage/misc/parser.pyx in sage.misc.parser.Parser.p_sequence (build/cythonized/sage/misc/parser.c:5207)()
628                 return all
629             else:
--> 630                 obj = self.p_eqn(tokens)
631             PyList_Append(all, obj)
632             token = tokens.next()

/usr/local/src/sage/src/sage/misc/parser.pyx in sage.misc.parser.Parser.p_eqn (build/cythonized/sage/misc/parser.c:6006)()
718             a != b
719         """
--> 720         lhs = self.p_expr(tokens)
721         cdef int op = tokens.next()
722         if op == '=':

/usr/local/src/sage/src/sage/misc/parser.pyx in sage.misc.parser.Parser.p_expr (build/cythonized/sage/misc/parser.c:6355)()
758         # Note: this is left-recursive, so we can't just recurse
759         cdef int op
--> 760         operand1 = self.p_term(tokens)
761         op = tokens.next()
762         while op == '+' or op == '-':

/usr/local/src/sage/src/sage/misc/parser.pyx in sage.misc.parser.Parser.p_term (build/cythonized/sage/misc/parser.c:6618)()
792         # Note: this is left-recursive, so we can't just recurse
793         cdef int op
--> 794         operand1 = self.p_factor(tokens)
795         op = tokens.next()
796         if op == NAME and self.implicit_multiplication:

/usr/local/src/sage/src/sage/misc/parser.pyx in sage.misc.parser.Parser.p_factor (build/cythonized/sage/misc/parser.c:7036)()
835         else:
836             tokens.backtrack()
--> 837             return self.p_power(tokens)
838
839 # power ::=  (atom | atom!) ^ factor | atom | atom!

/usr/local/src/sage/src/sage/misc/parser.pyx in sage.misc.parser.Parser.p_power (build/cythonized/sage/misc/parser.c:7190)()
863
864         """
--> 865         operand1 = self.p_atom(tokens)
866         cdef int token = tokens.next()
867         if token == '^':

/usr/local/src/sage/src/sage/misc/parser.pyx in sage.misc.parser.Parser.p_atom (build/cythonized/sage/misc/parser.c:7902)()
925             else:
926                 tokens.backtrack()
--> 927                 return self.variable_constructor(name)
928         elif token == '(':
929             expr = self.p_expr(tokens)

/usr/local/src/sage/local/lib/python2.7/site-packages/sage/calculus/calculus.pyc in _find_Mvar(name)
2097     """
2098     if name[:10] == "_SAGE_VAR_":
-> 2099         return var(name[10:])
2100     res = _augmented_syms.get(name)
2101     if res is not None and not isinstance(res, Function):

/usr/local/src/sage/src/sage/symbolic/ring.pyx in sage.symbolic.ring.var (build/cythonized/sage/symbolic/ring.cpp:10931)()
988         ValueError: The name "3" is not a valid Python identifier.
989     """
--> 990     return SR.var(name, **kwds)
991
992 def is_SymbolicVariable(x):

/usr/local/src/sage/src/sage/symbolic/ring.pyx in sage.symbolic.ring.SymbolicRing.var (build/cythonized/sage/symbolic/ring.cpp:8883)()
611         return e
612
--> 613     cpdef var(self, name, latex_name=None, domain=None):
614         """
615         Return the symbolic variable defined by x as an element of the

/usr/local/src/sage/src/sage/symbolic/ring.pyx in sage.symbolic.ring.SymbolicRing.var (build/cythonized/sage/symbolic/ring.cpp:8557)()
664         for s in names_list:
665             if not isidentifier(s):
--> 666                 raise ValueError('The name "'+s+'" is not a valid Python identifier.')
667
668         if len(names_list) == 0:

ValueError: The name "lambda" is not a valid Python identifier.
sage:


If the reason for prohibiting this name is that it can't be used when var() creates a Python global variable, that prohibition should be enforced in var(), not in SR.var().

### comment:1 Changed 6 years ago by wonder

• Description modified (diff)

### comment:2 Changed 6 years ago by jhpalmieri

lambda is a reserved keyword in Python, so just like and or def it shouldn't be used as a variable name.

### comment:3 Changed 6 years ago by wonder

This ticket is about using lambda as a math symbol, not a Python variable name. That's why the Python variable name in the included code snippet is not lambda. It's standard mathematical practice to use lambda as a symbol, and Sage should support it as fully as possible.

### comment:4 Changed 6 years ago by nbruin

I maybe agree. SR.var doesn't particularly inject a binding into a python scope, so it doesn't necessarily need to check whether things are python identifiers.

That said, for the sanity of the system it might be a good idea to make some checks on what kind of math symbols we allow. These things tend to end up in strings to various interfaces (although we wouldn't really need to do that for maxima, but we still do). It might even be that we end up "eval"-ing expressions in python, in which case python identifiers shouldn't be allowed.

### comment:5 follow-up: ↓ 6 Changed 6 years ago by wonder

Is that eval-ing really a good thing to do? Given that SR expressions are not python expressions - they include things like "integral" and "D[0]" - it seems like any code that tries to interpret the string value of an SR expression as a python expression would be a serious bug, whether it collides with names like lambda or not. I imagine there must be some kind of translation step from SR to python. Surely that step could include translating "lambda" to "SAGE_SR_SYMBOL_lambda" or whatever.

### comment:6 in reply to: ↑ 5 Changed 6 years ago by nbruin

Is that eval-ing really a good thing to do? Given that SR expressions are not python expressions - they include things like "integral" and "D[0]" - it seems like any code that tries to interpret the string value of an SR expression as a python expression would be a serious bug,

I don't know. I think the standard representation we use is valid python syntax (modulo keyword clashes), and otherwise it would be easy to render them into valid python syntax. I'm not sure if we ever do. The fact is symbolic expressions DO get rendered as strings in various languages. Even in maxima, the whole SAGE_VAR wrapping thing is relatively recent. We have various implicit restrictions on what symbols survive the various translation processes. I'm not entirely sure whether lambda is one of those implicit restrictions.

### comment:7 follow-up: ↓ 9 Changed 6 years ago by wonder

I'm not entirely sure whether lambda is one of those implicit restrictions.

Would it be helpful to relax the restriction and see if the tests fail?

I think the standard representation we use is valid python syntax (modulo keyword clashes),

Out of curiosity, how is "D[0](f)(x)" made into valid python syntax?

### comment:8 Changed 6 years ago by wonder

Would it be helpful to relax the restriction and see if the tests fail?

No, of course not. New tests would have to be written. Never mind that.

### comment:9 in reply to: ↑ 7 Changed 6 years ago by nbruin

Out of curiosity, how is "D[0](f)(x)" made into valid python syntax?

It already is: you don't get a syntax error if you type it into sage.

If you want to ensure it executes properly in addition to being valid syntax you have to bind D to an object that puts the information in the right places. I posted this example elsewhere but I can't locate it right now:

class Dclass(object):
def __getitem__(self,a):
if isinstance(a,tuple):
L=[i for i in a]
else:
L=[a]
def derivator(f):
return sage.symbolic.operators.FDerivativeOperator(f,L)
return derivator
D=Dclass()


With this binding, you get:

sage: D[0,0,0](sin)(x)
-cos(x)


EDIT: Found the original code (it's painful how google results now depend on which computer you use!) in this sage-devel discussion

Last edited 6 years ago by nbruin (previous) (diff)

### comment:10 Changed 6 years ago by kcrisman

Note also that lambda_ does most of what you want, if I recall correctly.

### comment:11 Changed 6 years ago by wonder

Note also that lambda_ does most of what you want, if I recall correctly.

@kcrisman thanks, that's good to know.

If you want to ensure it executes properly in addition to being valid syntax you have to bind D to an object

@nbruin thanks - this seems to say that SR expressions can be parsed as python expressions but not evaled, since this operator isn't defined in Sage as is.

Note: See TracTickets for help on using tickets.