Path: blob/master/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx
8822 views
"""1Optimized Cython code needed by quaternion algebras.23This is a collection of miscellaneous routines that are in Cython for4speed purposes and are used by the quaternion algebra code. For5example, there are functions for quickly constructing an n x 4 matrix6from a list of n rational quaternions.78AUTHORS:9- William Stein10"""1112########################################################################13# Copyright (C) 2009 William Stein <[email protected]>14#15# Distributed under the terms of the GNU General Public License (GPL)16#17# This code is distributed in the hope that it will be useful,18# but WITHOUT ANY WARRANTY; without even the implied warranty of19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU20# General Public License for more details.21#22# The full text of the GPL is available at:23#24# http://www.gnu.org/licenses/25########################################################################262728include "sage/ext/stdsage.pxi"2930from sage.rings.integer_ring import ZZ31from sage.rings.rational_field import QQ32from sage.rings.integer cimport Integer33from sage.matrix.matrix_space import MatrixSpace34from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense35from sage.matrix.matrix_rational_dense cimport Matrix_rational_dense3637from quaternion_algebra_element cimport QuaternionAlgebraElement_rational_field3839from sage.libs.gmp.mpz cimport mpz_t, mpz_lcm, mpz_init, mpz_set, mpz_clear, mpz_init_set, mpz_mul, mpz_fdiv_q, mpz_cmp_si40from sage.libs.gmp.mpq cimport mpq_set_num, mpq_set_den, mpq_canonicalize4142def integral_matrix_and_denom_from_rational_quaternions(v, reverse=False):43r"""44Given a list of rational quaternions, return matrix `A` over `\ZZ`45and denominator `d`, such that the rows of `(1/d)A` are the46entries of the quaternions.4748INPUT:49- v -- a list of quaternions in a rational quaternion algebra50- reverse -- whether order of the coordinates as well as the51order of the list v should be reversed.5253OUTPUT:54- a matrix over ZZ55- an integer (the common denominator)5657EXAMPLES::58sage: A.<i,j,k>=QuaternionAlgebra(-4,-5)59sage: sage.algebras.quatalg.quaternion_algebra_cython.integral_matrix_and_denom_from_rational_quaternions([i/2,1/3+j+k])60(61[0 3 0 0]62[2 0 6 6], 663)6465sage: sage.algebras.quatalg.quaternion_algebra_cython.integral_matrix_and_denom_from_rational_quaternions([i/2,1/3+j+k], reverse=True)66(67[6 6 0 2]68[0 0 3 0], 669)70"""71# This function is an optimized version of72# MatrixSpace(QQ,len(v),4)([x.coefficient_tuple() for x in v], coerce=False)._clear_denom7374cdef Py_ssize_t i, n=len(v)75M = MatrixSpace(ZZ, n, 4)76cdef Matrix_integer_dense A = M.zero_matrix().__copy__()77if n == 0: return A7879# Find least common multiple of the denominators80cdef QuaternionAlgebraElement_rational_field x81cdef Integer d = Integer()82# set denom to the denom of the first quaternion83x = v[0]; mpz_set(d.value, x.d)84for x in v[1:]:85mpz_lcm(d.value, d.value, x.d)8687# Now fill in each row x of A, multiplying it by q = d/denom(x)88cdef mpz_t q89cdef mpz_t* row90mpz_init(q)91for i in range(n):92x = v[i]93mpz_fdiv_q(q, d.value, x.d)94if reverse:95mpz_mul(A._matrix[n-i-1][3], q, x.x)96mpz_mul(A._matrix[n-i-1][2], q, x.y)97mpz_mul(A._matrix[n-i-1][1], q, x.z)98mpz_mul(A._matrix[n-i-1][0], q, x.w)99else:100mpz_mul(A._matrix[i][0], q, x.x)101mpz_mul(A._matrix[i][1], q, x.y)102mpz_mul(A._matrix[i][2], q, x.z)103mpz_mul(A._matrix[i][3], q, x.w)104mpz_clear(q)105return A, d106107def rational_matrix_from_rational_quaternions(v, reverse=False):108"""109Return matrix over the rationals whose rows have entries the110coefficients of the rational quaternions in v.111112INPUT:113- v -- a list of quaternions in a rational quaternion algebra114- reverse -- whether order of the coordinates as well as the115order of the list v should be reversed.116117OUTPUT:118- a matrix over QQ119120EXAMPLES::121sage: A.<i,j,k>=QuaternionAlgebra(-4,-5)122sage: sage.algebras.quatalg.quaternion_algebra_cython.rational_matrix_from_rational_quaternions([i/2,1/3+j+k])123[ 0 1/2 0 0]124[1/3 0 1 1]125126sage: sage.algebras.quatalg.quaternion_algebra_cython.rational_matrix_from_rational_quaternions([i/2,1/3+j+k], reverse=True)127[ 1 1 0 1/3]128[ 0 0 1/2 0]129"""130cdef Py_ssize_t i, j, n=len(v)131M = MatrixSpace(QQ, n, 4)132cdef Matrix_rational_dense A = M.zero_matrix().__copy__()133if n == 0: return A134135cdef QuaternionAlgebraElement_rational_field x136if reverse:137for i in range(n):138x = v[i]139mpq_set_num(A._matrix[n-i-1][3], x.x)140mpq_set_num(A._matrix[n-i-1][2], x.y)141mpq_set_num(A._matrix[n-i-1][1], x.z)142mpq_set_num(A._matrix[n-i-1][0], x.w)143144if mpz_cmp_si(x.d,1):145for j in range(4):146mpq_set_den(A._matrix[n-i-1][j], x.d)147mpq_canonicalize(A._matrix[n-i-1][j])148else:149for i in range(n):150x = v[i]151mpq_set_num(A._matrix[i][0], x.x)152mpq_set_num(A._matrix[i][1], x.y)153mpq_set_num(A._matrix[i][2], x.z)154mpq_set_num(A._matrix[i][3], x.w)155156if mpz_cmp_si(x.d,1):157for j in range(4):158mpq_set_den(A._matrix[i][j], x.d)159mpq_canonicalize(A._matrix[i][j])160return A161162def rational_quaternions_from_integral_matrix_and_denom(A, Matrix_integer_dense H, Integer d, reverse=False):163"""164Given an integral matrix and denominator, returns a list of rational quaternions.165166INPUT:167- A -- rational quaternion algebra168- H -- matrix over the integers169- d -- integer170- reverse -- whether order of the coordinates as well as the171order of the list v should be reversed.172173OUTPUT:174- list of H.nrows() elements of A175176EXAMPLES::177178sage: A.<i,j,k>=QuaternionAlgebra(-1,-2)179sage: f = sage.algebras.quatalg.quaternion_algebra_cython.rational_quaternions_from_integral_matrix_and_denom180sage: f(A, matrix([[1,2,3,4],[-1,2,-4,3]]), 3)181[1/3 + 2/3*i + j + 4/3*k, -1/3 + 2/3*i - 4/3*j + k]182183sage: f(A, matrix([[3,-4,2,-1],[4,3,2,1]]), 3, reverse=True)184[1/3 + 2/3*i + j + 4/3*k, -1/3 + 2/3*i - 4/3*j + k]185"""186#187# This is an optimized version of the following interpreted Python code.188# H2 = H.change_ring(QQ)._rmul_(1/d)189# return [A(v.list()) for v in H2.rows()]190#191cdef QuaternionAlgebraElement_rational_field x192v = []193cdef Integer a, b194a = Integer(A.invariants()[0])195b = Integer(A.invariants()[1])196cdef Py_ssize_t i, j197198if reverse:199rng = range(H.nrows()-1,-1,-1)200else:201rng = range(H.nrows())202203for i in rng:204x = <QuaternionAlgebraElement_rational_field> PY_NEW(QuaternionAlgebraElement_rational_field)205x._parent = A206mpz_set(x.a, a.value)207mpz_set(x.b, b.value)208if reverse:209mpz_init_set(x.x, H._matrix[i][3])210mpz_init_set(x.y, H._matrix[i][2])211mpz_init_set(x.z, H._matrix[i][1])212mpz_init_set(x.w, H._matrix[i][0])213else:214mpz_init_set(x.x, H._matrix[i][0])215mpz_init_set(x.y, H._matrix[i][1])216mpz_init_set(x.z, H._matrix[i][2])217mpz_init_set(x.w, H._matrix[i][3])218mpz_init_set(x.d, d.value)219# WARNING -- we do *not* canonicalize the entries in the quaternion. This is220# I think _not_ needed for quaternion_element.pyx221v.append(x)222return v223224225from sage.rings.rational_field import QQ226MS_16_4 = MatrixSpace(QQ,16,4)227228229