#14972: charpoly name clashes with matrix content
-------------------------------+-----------------------------
    Reporter:  gagern          |            Owner:
        Type:  defect          |           Status:  new
    Priority:  major           |        Milestone:  sage-5.12
   Component:  linear algebra  |         Keywords:
   Merged in:                  |          Authors:
   Reviewers:                  |  Report Upstream:  N/A
 Work issues:                  |           Branch:
Dependencies:                  |         Stopgaps:
-------------------------------+-----------------------------
 ''This is a spin-off from #14403, to get that one landed and have a
 discussion with a wider scope here.''

 == Problem

 `matrix.charpoly()` will return a polynomial in a polynomial ring over
 `x`. That variable name is always used, unless overridden by an argument
 provided by the user. This is OK in many cases, but can become confusing
 or outright dangerous in cases where `x` already occursd inside the
 matrix, since in those cases there would be two occurrences of `x` with
 different semantics:

 {{{
 sage: x = var('x')
 sage: R = SR
 sage: matrix(R,2,2,[x,1,1,x]).charpoly()
 x^2 - 2*x*x + x^2 - 1
 sage: R.<x> = QQ[]
 sage: matrix(R,2,2,[x,1,1,x]).charpoly()
 x^2 - 2*x*x + x^2 - 1
 sage: R.<x> = FiniteField(4)
 sage: matrix(R,2,2,[x,1,1,x]).charpoly()
 x^2 + x
 sage: R.<x> = PowerSeriesRing(QQ)
 sage: matrix(R,2,2,[x,1,1,x]).charpoly()
 x^2 - 2*x*x - 1 + x^2
 }}}

 It is easy to see that this kind of result can be confusing to say the
 least. The data structure returned is a polynomial over the ring of the
 matrix, so the coefficients are all right. Any piece of code only
 interested in the list of coefficients shouldn't have to bother. But even
 code could encounter trouble if it were to pass this to some other
 application or library using a string-like representation, like this:

 {{{
 sage: R.<x> = QQ[]
 sage: y = var('y')
 sage: (matrix(R,2,2,[x,1,1,x]).charpoly()*(1 + y))
 -y - 1
 sage: (matrix(R,2,2,[x,1,1,x]).charpoly('t')*(1 + y))
 (y + 1)*((t - 2*x)*t + x^2 - 1)
 }}}

 As you can see, the distinction between the two flavours of `x` can easily
 get lost, e.g. by (deliberate or accidential) coercion into the symbolic
 ring. The real problem here is not so much the fact that this does not
 work (after all, the user ''could'' have chosen a different variable name
 in the first place), but rather that this will seem to work but will yield
 wrong results.

 == Proposal

 For this reason, I am of the strong opinion that `charpoly` (and perhaps
 other polynomial-returning functions as well, so if you know any, please
 point them out) should take some care to choose a non-clashing name.

 To implement this, we'd need a general method to recursively enumerate all
 names occuring in a set of values from a given ring. For most rings a
 complete list of generators would probably be appropriate, no matter
 whether they actually occur. For the symbolic ring I'd prefer to only use
 those which actually occur, since otherwise the current default of `x`
 would probably never be chosen for symbolic matrices, causing an
 unexpected difference in behavior.

 Given a list of symbol names, we could then try to come up with a non-
 clashing one. The most elaborate scheme would try some well-known symbols
 first, like `['x', 'y', 'z', 't', 'u', 'mu']`, before using indexed ones
 like `['x1', 'x2', …]`, until a locally unique one has been found. Of
 course one could omit the former, and use `SR.symbol()` instead of the
 latter, but the consequence would be that the default charpoly of a given
 matrix would not depend on this matrix alone, but also on which other
 computations have been done before. Plus those names are harder to read.
 So I'd rather avoid this approach.

 == Unsatisfied expectations

 Some users might be confused by the unexpected and perhaps unintuitive
 name of the variable. Compared with the confusion caused by the clashing
 names, I consider this acceptable.

 In comment:10:ticket:14403, nbruin pointed out that one might expect

 {{{
 charpoly(A)*charpoly(B) == charpoly(block_diagonal(A,B))
 }}}

 but this would no longer be universally true after this change. I consider
 this acceptable, since the result would not be an incorrect computation
 but instead an exception thrown due to a multiplication between
 incompatible rings. Faced with this, users could always augment their
 calls to

 {{{
 charpoly(A,'t')*charpoly(B,'t') == charpoly(block_diagonal(A,B),'t')
 }}}

 for some non-clashing variable name `t`.

--
Ticket URL: <http://trac.sagemath.org/ticket/14972>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to