Opened 8 years ago

Closed 8 years ago

#15321 closed defect (invalid)

Function changes behaviour, related to polynomial rings

Reported by: 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 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 8 years ago by gagern

  • Description modified (diff)

comment:2 follow-up: Changed 8 years ago by nbruin

  • Milestone changed from sage-5.13 to sage-duplicate/invalid/wontfix
  • Status changed from new to needs_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 8 years ago by 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 8 years ago by jdemeyer

  • Reviewers set to Nils Bruin
  • Status changed from needs_review to positive_review

comment:5 Changed 8 years ago by jdemeyer

  • Resolution set to invalid
  • Status changed from positive_review to closed
Note: See TracTickets for help on using tickets.