What do people think about making the default ring for matrices QQ?
Additionally, if the ring R is determined from the elements provided,
then the matrix would be over R.fraction_field(). Of course, the
documentation for matrix() would clearly indicate what is happening if
the ring is not specified.
With this change:
matrix(3, range(9)) would yield a matrix over QQ because the elements
live in ZZ, and then we call ZZ.fraction_field() to get the base ring of
the matrix.
matrix(3,3) would yield a matrix over QQ because QQ would be the default
ring if no entries are specified.
matrix(R,...) would yield a ring over R, since R was explicitly specified.
Thanks,
Jason
More concisely, this proposal could be worded:
What do people think of making matrix() return a matrix over a field by
default, unless a ring is explicitly specified. The default field would
either be the fraction field of the ring containing the specified
elements, or would be QQ if no elements are specified. This logic would
*only* be applied if a ring is not specified. The documentation of
matrix() would also be changed accordingly.
+1
I suggested this idea. I would never do this is Sage were "just for me",
but Sage isn't. Please keep that in mind when reading the above proposal...
-- William
Just to make sure I get it:
matrix(1,1,[1]) and matrix(1,2,[Mod(23,4),23]) will be over QQ
To me it looks like the *only* change from the current beahavior will
be that the matrices above will be over QQ, instead of over ZZ or a
generic ring. What other cases am I missing?
didier
Currently, your first example yields a matrix over ZZ and the second a
matrix over Ring of integers mod 4.
After the change, your first example would yield a matrix over QQ. The
second would still yield a matrix over Ring of integers mod 4 because
calling fraction_field throws an exception (the ring is not an integral
domain).
>
> To me it looks like the *only* change from the current beahavior will
> be that the matrices above will be over QQ, instead of over ZZ or a
> generic ring. What other cases am I missing?
A matrix over a polynomial ring, for example.
sage: x=polygen(QQ)
sage: matrix([x]).base_ring()
Univariate Polynomial Ring in x over Rational Field
After the change it would be:
sage: x=polygen(QQ)
sage: matrix([x]).base_ring()
Fraction Field of Univariate Polynomial Ring in x over Rational Field
Jason
Yes.
> matrix(1,2,[Mod(23,4),23]) will be over QQ
Absolutely not! The behavior of matrix(1,2,[Mod(23,4),23]) will be exactly
like it is now, since Integers(4).fraction_field() doesn't contain Integers(4).
sage: matrix(1,2,[Mod(23,4),23])
[3 3]
sage: parent(matrix(1,2,[Mod(23,4),23]))
Full MatrixSpace of 1 by 2 dense matrices over Ring of integers modulo 4
> To me it looks like the *only* change from the current beahavior will
> be that the matrices above will be over QQ, instead of over ZZ or a
> generic ring. What other cases am I missing?
I don't know. Why would you think that matrix(1,2,[Mod(23,4),23]) would
suddenly be over QQ? That would be very weird.
>
> didier
>
> >
>
--
William Stein
Associate Professor of Mathematics
University of Washington
http://wstein.org
That would work fine. What you're really asking about is making
the function rescale row on an *integer* or rational matrix automatically
change the base ring to complex. I think that is very reasonable and
would be fine with that. It is somewhat orthogonal to Jason's proposal
though.
> Under the current scaling code, this happens:
>
> sage: N.rescale_col(2,i/2)
> ---------------------------------------------------------------------------
> <type 'exceptions.TypeError'> Traceback (most recent call
> last)
> <snip>
> <type 'exceptions.TypeError'>: unable to convert I/2 to a rational
>
> I certainly have no problem with matrices starting off as rational
> ones - a great idea! But it doesn't directly affect this sort of
> issue - one could still start with a matrix over ZZ and then want to
> multiply it later on by 1/2 without using change_ring().
Yep, this is orthogonal. You're just suggesting that scale_row
be improved.
>
> What I am wondering is whether throwing an exception of TypeError
> under the current code should be replaced by a try statement first
> attempting N.changering(??) . The problem is I have no idea what to
> use for ??, because unfortunately i/2 lives in Symbolic Ring, not in
> CC, so I can't just put in ??=parent(i/2).
The Sequence constructor is the canonical answer to this question.
Given any list v of Sage object it will find a canonical place to put
them all:
sage: v = [3, I/2]
sage: w = Sequence(v)
sage: w
[3, I/2]
sage: w.universe()
Symbolic Ring
I do. That's definitely *not* the proposal. The proposal is to make the
base ring the fraction field of the canonical ring in which the list of
entries live, if that fraction field is defined. QQ was just an example.
> However, I don't think this resolves the problem entirely.
>
> A part of the confusion stems from echelon_form doing entirely
> different things based on the type of argument it gets. I would prefer
> echelon_form to always use fractions, and have some other function
> avoid the fractions. Another solution I could get behind is for
> echelon_form to have a parameter for whether to use fractions, and
> have the default be to use them.
Echelon form over a field is just a natural special case of a more
general notion of echelon forms over rings. So from an algebraist's
point of view echelon form does *exactly* the same thing over ZZ
or QQ, relative to the ring over which we are working.
-- William
I'm not sure I understand the problem. Here is an example session in
Sage 3.0.1. Can you change this to illustrate what you mean?
sage: m=matrix(3,3,range(9))
sage: n = m*(i/2)
sage: n.parent()
Full MatrixSpace of 3 by 3 dense matrices over Symbolic Ring
sage: n
[ 0 I/2 I]
[3*I/2 2*I 5*I/2]
[ 3*I 7*I/2 4*I]
sage: m2 = m/i
sage: m2.parent()
Full MatrixSpace of 3 by 3 dense matrices over Symbolic Ring
sage: m2
[ 0 -1*I -2*I]
[-3*I -4*I -5*I]
[-6*I -7*I -8*I]
Thanks,
Jason
I'm not certain why I dislike this so much, but I vote -1. I think
it's because I understand the Sage coercion model well and since I
know what to expect, I appreciate my data starting at the "lowest
level of the model".
I would prefer changing echelon_form over an integral domain to work
over the fraction field and reserve hermite_normal_form for PIDs.
Nick
We could do this. It would
1. Require rewriting code in modules/*.py to
call different functions depending on whether the base ring
is a field or not.
2. Break compatibility with Magma where EchelonForm is the
same as in Sage over ZZ (not a priori bad.)
3. Probably other things would break, but I'm not sure where.
It's likely doctest would uncover what, hopefully. Code
would also have to be changed in matrix_integer_dense,
obviously...
-- William
I think the fundamental problem among the people I have talked with was
that they never thought of a "matrix over ZZ". Instead they always
really thought of a "matrix over RR" with entries in ZZ. So I think the
proposal addresses the problem well. Those people that don't want to
worry about matrices over non-fields don't have to deal with them, while
those people that do work with matrices over non-fields can get them easily.
Thanks,
Jason
The other part of the proposal is making it so that a matrix without a
ring specified and without entries specified would default to being over
QQ, i.e., we would have:
sage: matrix(3,3).parent()
Rational Field
Currently this returns a matrix over ZZ.
In that sense, the default ring for matrices would be QQ instead of ZZ
after the change.
Thanks,
Jason
Good points. In the current case, I don't think the speed issues affect
us because apparently sage can't create the field of fractions of the
first case, unless I'm doing this wrong:
sage: R.<x,y>=QQ['x','y']
sage: Frac(R.quo(x^2+y^2-1))
---------------------------------------------------------------------------
<type 'exceptions.NotImplementedError'> Traceback (most recent call last)
/home/grout/<ipython console> in <module>()
/home/grout/sage/local/lib/python2.5/site-packages/sage/rings/fraction_field.py
in FractionField(R, names)
104 if not ring.is_Ring(R):
105 raise TypeError, "R must be a ring"
--> 106 if not R.is_integral_domain():
107 raise TypeError, "R must be an integral domain."
108 return R.fraction_field()
/home/grout/sage/local/lib/python2.5/site-packages/sage/rings/quotient_ring.py
in is_integral_domain(self)
351
352 """
--> 353 return self.defining_ideal().is_prime()
354
355 def cover_ring(self):
/home/grout/sage/local/lib/python2.5/site-packages/sage/rings/ideal.py
in is_prime(self)
402 NotImplementedError
403 """
--> 404 raise NotImplementedError
405
406 def is_principal(self):
<type 'exceptions.NotImplementedError'>:
sage: Frac(R.quo(x^2-y^2))
---------------------------------------------------------------------------
<type 'exceptions.NotImplementedError'> Traceback (most recent call last)
/home/grout/<ipython console> in <module>()
/home/grout/sage/local/lib/python2.5/site-packages/sage/rings/fraction_field.py
in FractionField(R, names)
104 if not ring.is_Ring(R):
105 raise TypeError, "R must be a ring"
--> 106 if not R.is_integral_domain():
107 raise TypeError, "R must be an integral domain."
108 return R.fraction_field()
/home/grout/sage/local/lib/python2.5/site-packages/sage/rings/quotient_ring.py
in is_integral_domain(self)
351
352 """
--> 353 return self.defining_ideal().is_prime()
354
355 def cover_ring(self):
/home/grout/sage/local/lib/python2.5/site-packages/sage/rings/ideal.py
in is_prime(self)
402 NotImplementedError
403 """
--> 404 raise NotImplementedError
405
406 def is_principal(self):
<type 'exceptions.NotImplementedError'>:
Of course, we shouldn't rely on Sage not having functionality
(especially if we point it out the lack of said functionality, as it is
quite likely to be fixed soon!).
If it is too expensive in general, then maybe we can just special-case
the ZZ->QQ conversion. My guess is that this would take care of most
common scenarios.
Is that special case what you are referring to below?
>
> I think special-casing matrix([ZZ(1)]) etc. is a bad idea. You would
> need a method R.has_an_obvious_field_of_fractions() on rings to both
> deal with ZZ and avoid expensive operations for R1 and R2 above.
> --~--~---------~--~----~------------~-------~--~----~
Thanks,
Jason
I would second this idea, I like it much better than matrix(3,range
(9) being over Q. I think that's the way it used to be. It seems odd
to make matrices by default over their fraction fields (if they
exist)--other than echelon form is there any other case that one
wants this. This could slow things down a lot too--matrices over QQ
have some overhead (only O(n^2)) over matrices over ZZ, but there is
a huge difference in performance for Z[x] and Frac(Z[x]). Also, then
sage: matrix(3, range(9).charpoly('x')
would return a polynomial over QQ rather than ZZ which I think is odd
and less efficient.
- Robert
I think based on this whole discussion:
(1) matrix(3, range(9)) returning a matrix over QQ is *definitely* out.
If there is a trac ticket it should be marked invalid.
(2) The echelon_form command should be changed to always return
a result over the fraction field, thus making a break with Magma.
(3) Rewrite all the rest of code in Sage that depends on the current
behavior of echelon_form. This code will have to call hermite_form
instead. E.g., code in modules/free_module.py will have to change.
Code in a.kernel() will have to change, etc.
Doing (1), (2) is almost trivial. Do (3) will be a little more difficult, and
could introduce bugs.
I'm very much against
a.echelon_form(...)
being over ZZ or QQ depending on arguments to echelon_form.
If for no other reason than even if one does that then it will
still be necessary to do all of (3) above.
I've cc'd David Kohel on this email, since he is 100% responsible
for the current state of affairs regarding echelon form, and I want
to give him a chance to speak up before we do (1)-(3) above.
-- William