Ask Your Question

Is this a bug or intended behavior?

asked 2019-08-30 17:33:21 +0200

dsejas gravatar image

Hello, SageMath Community!

I was trying to define the function $\tau(n)=$ "number of divisors of $n$" in Sage, so I tried this:

tau(n) = len(divisors(n))

After pressing ENTER, I get the following traceback:

TypeError                                 Traceback (most recent call last)
<ipython-input-1-7aac193e89de> in <module>()
----> 1 __tmp__=var("n"); tau = symbolic_expression(len(divisors(n))).function(n)

/Scientific/SageMath/local/lib/python2.7/site-packages/sage/arith/misc.pyc in divisors(n)
   1494             one = parent(n)(1)
   1495             output = [one]
-> 1496             for p, e in f:
   1497                 prev = output[:]
   1498                 pn = one

TypeError: 'sage.symbolic.expression.Expression' object is not iterable

However, I can use exactly the same definition of the function by means of Python's standard function definition mechanism:

def tau(n):
    return len(divisors(n))

I am not completely sure, but the following behaviour seems to be related. An alternative definition of $\tau$ would be:

tau(n) = sigma(n, 0)

However, this produces the following traceback:

TypeError                                 Traceback (most recent call last)
<ipython-input-7-016584cdbd3f> in <module>()
----> 1 __tmp__=var("n"); tau = symbolic_expression(sigma(n,Integer(0))).function(n)

/Scientific/SageMath/local/lib/python2.7/site-packages/sage/arith/misc.pyc in __call__(self, n, k)
   1595             130
   1596         """
-> 1597         n = ZZ(n)
   1598         k = ZZ(k)
   1599         one = ZZ(1)

/Scientific/SageMath/local/lib/python2.7/site-packages/sage/structure/parent.pyx in sage.structure.parent.Parent.__call__ (build/cythonized/sage/structure/parent.c:9197)()
    898         if mor is not None:
    899             if no_extra_args:
--> 900                 return mor._call_(x)
    901             else:
    902                 return mor._call_with_args(x, args, kwds)

/Scientific/SageMath/local/lib/python2.7/site-packages/sage/structure/coerce_maps.pyx in sage.structure.coerce_maps.NamedConvertMap._call_ (build/cythonized/sage/structure/coerce_maps.c:5942)()
    286             raise TypeError("Cannot coerce {} to {}".format(x, C))
    287         cdef Map m
--> 288         cdef Element e = method(C)
    289         if e is None:
    290             raise RuntimeError("BUG in coercion model: {} method of {} returned None".format(self.method_name, type(x)))

/Scientific/SageMath/local/lib/python2.7/site-packages/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression._integer_ (build/cythonized/sage/symbolic/expression.cpp:8690)()
   1085             n = self.pyobject()
   1086         except TypeError:
-> 1087             raise TypeError("unable to convert %r to an integer" % self)
   1088         if isinstance(n, sage.rings.integer.Integer):
   1089             return n

TypeError: unable to convert n to an integer

However, I can do:

def tau(n):
    return sigma(n, 0)

Of course, it is possible to evaluate the formulas len(divisors(n)) and sigma(n, 0), when $n$ has a particular value---n=50, for example.

OS: Ubuntu 18.04.2 LTS

SageMath version: 8.8, dated 2019-06-26

Python version: 2.7.15

Possible explanation: SageMath seems to be trying to evaluate part of the body of the function during compile-time, instead of defering it to execution-time, as Python does.

edit retag flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted

answered 2019-08-30 19:19:55 +0200

rburing gravatar image

You have discovered the horror of the syntax for callable symbolic expressions.

  • Numbers confusion:

    sage: f(x) = x^2
    sage: f(2).factor()
  • Polynomial confusion:

    sage: R.<z,w> = PolynomialRing(QQ)
    sage: f(x) = x^2
    sage: f(z+w).coefficient({z : 1})
    TypeError: no canonical coercion from <type 'dict'> to Symbolic Ring

  • Matrix confusion:

    sage: B(x) = matrix([[x, 0], [0, 0]])
    sage: B(12)
    [x 0]
    [0 0]

  • List confusion:

    sage: f(x) = [x,x]
    sage: f(2).parent()
    Vector space of dimension 2 over Symbolic Ring

  • Derivative confusion (and argument confusion):

    sage: f(x) = x.derivative()
    sage: f(x^2)
    sage: f(y) = y.derivative(x)
    sage: f(x^2)

  • Matrix argument confusion:

    sage: f(x) = x^2
    sage: f(2*identity_matrix(2))
    TypeError: no canonical coercion from Full MatrixSpace of 2 by 2 dense matrices over Integer Ring to Callable function ring with argument x

  • Adding confusion:

    sage: f(x) = x^2
    sage: g(x) = x^2
    sage: var('t')
    sage: h(t) = t^2
    sage: f+g
    x |--> 2*x^2
    sage: f+h
    (t, x) |--> t^2 + x^2

  • Non-symbolic function confusion (your question)

I've seen this too many times now. I went ahead and opened a ticket for it: #28434: Syntax for callable symbolic expressions causes too much confusion.

You should define your function in the way you did, or alternatively with a lambda:

 tau = lambda n: len(divisors(n))
edit flag offensive delete link more


Hello, @rburing and @Bruno. I really appreciate your answers. They were very informative! However, the system only allows me to select one question, so I selected @rburing for being more informative for me. This behavior you describe is amazingly misleading. Makes me wonder why not use Python's def mechanism exclusively, although I find Sage's mechanism more convenient. Maybe I'll post a question about the differences between both methods.

dsejas gravatar imagedsejas ( 2019-08-31 14:52:39 +0200 )edit

answered 2019-08-30 18:08:47 +0200

B r u n o gravatar image

I'm not sure it is absolutely intended but it is at least an expected behavior: When you write f(x) = <expr>, SageMath actually creates a "callable symbolic expression" from <expr> (in which x is considered as a symbolic variable). This means that <expr> itself must initially be a symbolic expression (or anything that can be transformed into a symbolic expression). But this is not the case of divisors(n) since divisors is not a symbolic function applicable to a symbolic variable. Thus you must use the def ... return ... construction, or the equivalent lambda-expression f = lambda n: divisors(n).

In other words, there is a difference between a symbolic function, which is a Sage object made to represent mathematical functions (thus you can work with it, for instance derive it, integrate, etc.) and a Python function which is a function in the computer science sense, that is a subroutine. The shorthand f(x) = <expr> is a construction for symbolic functions and not for Python functions.

edit flag offensive delete link more


To be precise: neither divisors(x) nor len(x) are symbolic expressions.

Emmanuel Charpentier gravatar imageEmmanuel Charpentier ( 2019-08-30 19:05:55 +0200 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower


Asked: 2019-08-30 17:33:21 +0200

Seen: 125 times

Last updated: Aug 30 '19