Opened 9 years ago

Closed 9 years ago

#15321 closed defect (invalid)

Function changes behaviour, related to polynomial rings

Reported by: Martin von Gagern Owned by:
Priority: major Milestone: sage-duplicate/invalid/wontfix
Component: algebra Keywords:
Cc: Merged in:
Authors: Reviewers: Nils Bruin
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Status badges

Description (last modified by Martin von Gagern)

I've just observed the following strange behaviour in sage 5.12:

sage: PR1 = PolynomialRing(QQ, ["t" + str(i) for i in range(10)])
sage: t = PR1.gens()
sage: def L(r, j):
...       return (t[r] - t[r + j])/t[r + j]
...
sage: PR2 = PolynomialRing(PR1.fraction_field(), ["p" + str(i) for i in range(5)])
sage: p = PR2.gens()
sage: def D(r):
...       return sum(L(r, j)*p[r-4+j] for j in range(3))
...
sage: D(4)
((t4 - t5)/t5)*p1 + ((t4 - t6)/t6)*p2
sage: myc = list(D(4))    # here the command works all right
sage: D(4)                # reproducing the call still works fine here
((t4 - t5)/t5)*p1 + ((t4 - t6)/t6)*p2
sage: [c for c, p in myc] # THIS LINE APPEARS TO BREAK THINGS!
[(t4 - t5)/t5, (t4 - t6)/t6]
sage: D(4)                # now the result is wrong, no error reported
0
sage: myc = list(D(4))    # and this throws, probably due to the zero result
Traceback (most recent call last):
...
TypeError: 'sage.rings.fraction_field_element.FractionFieldElement' object is not iterable

So it seems that repeated execution of the same function can yield different (and sometimes wrong!) results if some result was iterated over in a certain way. No clue why.

Change History (5)

comment:1 Changed 9 years ago by Martin von Gagern

Description: modified (diff)

comment:2 Changed 9 years ago by Nils Bruin

Milestone: sage-5.13sage-duplicate/invalid/wontfix
Status: newneeds_review

This is not a problem in Sage, but a documented "feature" of Python2. It was realized to be a wart and fixed in Python3. The problem is indeed the line you mark:

sage: p
(p0, p1, p2, p3, p4)
sage: [c for c, p in myc] # THIS LINE APPEARS TO BREAK THINGS!
[(t4 - t5)/t5, (t4 - t6)/t6]
sage: p
p2

List comprehensions leak their variables, so the value of your global variable p (which gets used in your function D) gets overwritten. This problem does not with happen if you write

sage: list(c for c, p in myc)

because iterators do not leak their variables. In Python3, list comprehensions share the same semantics as iterators.

It's a wart, but as long as we stick with Python2 we'll have to live with it. Ways to mitigate the problem:

  • Don't rely on a global variable such as p inside a function. Derive parents and their generators from your input variables (meaning: D should probably have PR2 as one of its parameters).
  • Use list(...) rather than [...] if you don't want to leak variables into scope.

Polynomials are indexable and iterable (for better or for worse), but fraction field elements are not. Thus, you have:

sage: parent(D(4))
Multivariate Polynomial Ring in p0, p1, p2, p3, p4 over Fraction Field of Multivariate Polynomial Ring in t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 over Rational Field
sage: p=PR2.2 #THIS LINE BREAKS THINGS
sage: parent(D(4))
Fraction Field of Multivariate Polynomial Ring in t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 over Rational Field

comment:3 in reply to:  2 Changed 9 years ago by Martin von Gagern

Replying to nbruin:

This is not a problem in Sage, but a documented "feature" of Python2. […] List comprehensions leak their variables, so the value of your global variable p […] gets overwritten.

Thanks for clarifying this.

I seem to have a knack for reporting things in the wrong place: I tend to ask questions on Ask Sage which turn out to be bugs, and now I asked here about what felt like a sure bug, and it turns out to be “a feature” or at least not Sage's bug, so it might have been more appropriate to use that Q&A forum instead.

comment:4 Changed 9 years ago by Jeroen Demeyer

Reviewers: Nils Bruin
Status: needs_reviewpositive_review

comment:5 Changed 9 years ago by Jeroen Demeyer

Resolution: invalid
Status: positive_reviewclosed
Note: See TracTickets for help on using tickets.