Opened 9 years ago

Closed 9 years ago

#10772 closed defect (fixed)

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

Reported by: mstreng Owned by: AlexGhitza
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:

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 mstreng 9 years ago.

Download all attachments as: .zip

Change History (6)

Changed 9 years ago by mstreng

comment:1 Changed 9 years ago by mstreng

  • Status changed from new to needs_review

comment:2 Changed 9 years ago by robertwb

  • Status changed from needs_review to positive_review

comment:3 Changed 9 years ago by jdemeyer

  • Milestone set to sage-4.7

comment:4 Changed 9 years ago by jdemeyer

  • Reviewers set to Robert Bradshaw

comment:5 Changed 9 years ago by jdemeyer

  • Merged in set to sage-4.7.alpha2
  • Resolution set to fixed
  • Status changed from positive_review to closed
Note: See TracTickets for help on using tickets.