Opened 12 years ago

Closed 12 years ago

#10772 closed defect (fixed)

0**0 = 1 for number fields, matrices, and more

Reported by: Marco Streng Owned by: Alex Ghitza
Priority: major Milestone: sage-4.7
Component: basic arithmetic Keywords: 0, power, pow, number field, matrix, convention, python
Cc: Merged in: sage-4.7.alpha2
Authors: Marco Streng Reviewers: Robert Bradshaw
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Status badges

Description

Python has the convention x**0 = 1 even for x=0. Sage follows this convention in some cases, but raises an error in others. This patch generalizes Python's convention to sage.structure.element.generic_power_c, which includes number field elements and matrices. This fixes inconsistent behaviour for matrices and a bug for number fields (see examples below). See also this discussion.

Example 1:

sage: K.<a> = NumberField(x^4+x+1)
sage: r = [ZZ,QQ,RR,CC,int,float,K]
sage: N = len(r)^2; N
49
sage: for a in r:
....:     for b in r:
....:         try:
....:             if a(0)^b(0) != 1:
....:                 (a,b,a(0)^b(0))
....:                 N = N - 1
....:         except (ArithmeticError, TypeError, AttributeError, RuntimeError) as e:
....:             (a,b,e)
....:             N = N - 1
....: 
(Integer Ring, Complex Field with 53 bits of precision, NaN - NaN*I)
(Integer Ring, Number Field in a with defining polynomial x^4 + x + 1, ArithmeticError('0^0 is undefined.',))
(Rational Field, Complex Field with 53 bits of precision, NaN - NaN*I)
(Rational Field, Number Field in a with defining polynomial x^4 + x + 1, ArithmeticError('0^0 is undefined.',))
Exception RuntimeError: 'maximum recursion depth exceeded in __subclasscheck__' in <type 'exceptions.TypeError'> ignored
Exception RuntimeError: 'maximum recursion depth exceeded in __subclasscheck__' in <type 'exceptions.TypeError'> ignored
Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' in <type 'exceptions.GeneratorExit'> ignored
Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' in <type 'exceptions.GeneratorExit'> ignored
Exception GeneratorExit in <generator object <genexpr> at 0x6d2e1e0> ignored
(Real Field with 53 bits of precision, Number Field in a with defining polynomial x^4 + x + 1, RuntimeError('maximum recursion depth exceeded while calling a Python object',))
(Complex Field with 53 bits of precision, Integer Ring, ArithmeticError('0^0 is undefined.',))
(Complex Field with 53 bits of precision, Rational Field, NaN - NaN*I)
(Complex Field with 53 bits of precision, Real Field with 53 bits of precision, NaN - NaN*I)
(Complex Field with 53 bits of precision, Complex Field with 53 bits of precision, NaN - NaN*I)
(Complex Field with 53 bits of precision, <type 'int'>, ArithmeticError('0^0 is undefined.',))
(Complex Field with 53 bits of precision, <type 'float'>, NaN - NaN*I)
(Complex Field with 53 bits of precision, Number Field in a with defining polynomial x^4 + x + 1, TypeError(<type 'sage.rings.complex_number.ComplexNumber'>,))
(<type 'int'>, Real Field with 53 bits of precision, TypeError("unsupported operand type(s) for ** or pow(): 'int' and 'sage.rings.real_mpfr.RealNumber'",))
(<type 'int'>, Complex Field with 53 bits of precision, AttributeError("'int' object has no attribute 'log'",))
(<type 'int'>, Number Field in a with defining polynomial x^4 + x + 1, TypeError('An embedding into RR or CC must be specified.',))
(<type 'float'>, Complex Field with 53 bits of precision, AttributeError("'float' object has no attribute 'log'",))
(<type 'float'>, Number Field in a with defining polynomial x^4 + x + 1, TypeError('An embedding into RR or CC must be specified.',))
(Number Field in a with defining polynomial x^4 + x + 1, Integer Ring, ArithmeticError('0^0 is undefined.',))
(Number Field in a with defining polynomial x^4 + x + 1, Rational Field, ArithmeticError('0^0 is undefined.',))
(Number Field in a with defining polynomial x^4 + x + 1, Real Field with 53 bits of precision, ArithmeticError('0^0 is undefined.',))
(Number Field in a with defining polynomial x^4 + x + 1, Complex Field with 53 bits of precision, TypeError('An embedding into RR or CC must be specified.',))
(Number Field in a with defining polynomial x^4 + x + 1, <type 'int'>, ArithmeticError('0^0 is undefined.',))
(Number Field in a with defining polynomial x^4 + x + 1, <type 'float'>, ArithmeticError('0^0 is undefined.',))
(Number Field in a with defining polynomial x^4 + x + 1, Number Field in a with defining polynomial x^4 + x + 1, ArithmeticError('0^0 is undefined.',))
sage: N
25

So in about half of these cases (25/49) we follow Python's convention 0^0=1 and the other half of the time we get an assortment of errors and NaN. This patch removes the 10 occurrences of ArithmeticError from the list. Other tickets can deal with the other cases.

Example 2:

sage: a = Matrix([[1,0],[0,0]]); a
[1 0]
[0 0]
b = Matrix([[0,0],[0,0]]); b
[0 0]
[0 0]
sage: a^0
[1 0]
[0 1]
sage: b^0
ArithmeticError: 0^0 is undefined.

Here Sage finds a!=0, and concludes a^0 = a.parent()(1). Note that the lower right entry of a^0 should be 0^0, and is 1. Next, Sage finds b==0, and concludes that b^0 is illegal. Both the upper left and lower right entry of b are the same as the lower right entry of a, so the behaviour of a^0 and b^0 in Sage is inconsistent: either both should yield an ArithmeticError or neither should. The patch adopts Python's convention so that the output of b^0 is the 2x2 identity matrix and this example becomes consistent.

Example 3:

sage: K.<a> = NumberField(x^3+x+1)
sage: K.relativize(1, 'c')
Number Field in c0 with defining polynomial x^3 + x + 1 over its base field
sage: K.relativize(0, 'c')
ArithmeticError: 0^0 is undefined.

This is explained by

sage: NumberField(x-1, 'a').power_basis()
[1]
sage: NumberField(x, 'a').power_basis()
ArithmeticError: 0^0 is undefined.

And it gets worse: a number field with defining polynomial x is part of the output of K.subfields()

sage: s = K.subfields()
sage: for i in [1,0]:
....:     K.relativize(s[i][1], 'c')
....: 
Number Field in c0 with defining polynomial x - a1 over its base field
ArithmeticError: 0^0 is undefined.

This last example is clearly a bug. An automatic consequence of generalizing Python's convention 0^0=1 is that this bug vanishes.

Interestingly, the patch adds no code.

Attachments (1)

trac_10772-0pow0.patch (4.4 KB) - added by Marco Streng 12 years ago.

Download all attachments as: .zip

Change History (6)

Changed 12 years ago by Marco Streng

Attachment: trac_10772-0pow0.patch added

comment:1 Changed 12 years ago by Marco Streng

Status: newneeds_review

comment:2 Changed 12 years ago by Robert Bradshaw

Status: needs_reviewpositive_review

comment:3 Changed 12 years ago by Jeroen Demeyer

Milestone: sage-4.7

comment:4 Changed 12 years ago by Jeroen Demeyer

Reviewers: Robert Bradshaw

comment:5 Changed 12 years ago by Jeroen Demeyer

Merged in: sage-4.7.alpha2
Resolution: fixed
Status: positive_reviewclosed
Note: See TracTickets for help on using tickets.