source: sage/matrix/matrix_rational_sparse.pyx @ 3271:d86a714eab75

Revision 3271:d86a714eab75, 8.2 KB checked in by William Stein <wstein@…>, 6 years ago (diff)

Sparse matrices over the integers; also fixed a bug that prevented sparse matrices over ZZ and QQ from pickling.

Line 
1"""
2Sparse rational matrices.
3
4AUTHORS:
5    -- William Stein (2007-02-21)
6    -- Soroosh Yazdani (2007-02-21)
7"""
8
9##############################################################################
10#       Copyright (C) 2007 William Stein <wstein@gmail.com>
11#  Distributed under the terms of the GNU General Public License (GPL)
12#  The full text of the GPL is available at:
13#                  http://www.gnu.org/licenses/
14##############################################################################
15
16include '../modules/vector_rational_sparse_h.pxi'
17include '../modules/vector_rational_sparse_c.pxi'
18include '../ext/stdsage.pxi'
19
20from sage.rings.rational cimport Rational
21from sage.rings.integer  cimport Integer
22from matrix cimport Matrix
23
24from sage.rings.integer_ring import ZZ
25import sage.matrix.matrix_space
26
27cdef class Matrix_rational_sparse(matrix_sparse.Matrix_sparse):   
28
29    ########################################################################
30    # LEVEL 1 functionality
31    #   * __new__ 
32    #   * __dealloc__   
33    #   * __init__     
34    #   * set_unsafe
35    #   * get_unsafe
36    #   * __richcmp__    -- always the same
37    #   * __hash__       -- alway simple
38    ########################################################################
39    def __new__(self, parent, entries, copy, coerce):
40        # set the parent, nrows, ncols, etc.
41        matrix_sparse.Matrix_sparse.__init__(self, parent)
42
43        self._matrix = <mpq_vector*> sage_malloc(parent.nrows()*sizeof(mpq_vector))
44        if self._matrix == NULL:
45            raise MemoryError, "error allocating sparse matrix"
46        # initialize the rows
47        for i from 0 <= i < parent.nrows():
48            init_mpq_vector(&self._matrix[i], self._ncols, 0)
49
50        # record that rows have been initialized
51        self._initialized = True
52
53       
54    def __dealloc__(self):
55        cdef Py_ssize_t i
56        if self._initialized:
57            for i from 0 <= i < self._nrows:
58                clear_mpq_vector(&self._matrix[i])
59        sage_free(self._matrix)
60   
61    def __init__(self, parent, entries, copy, coerce):
62        """
63        Create a sparse matrix over the rational numbers
64       
65        INPUT:
66            parent -- a matrix space
67            entries -- * a Python list of triples (i,j,x), where 0 <= i < nrows,
68                         0 <= j < ncols, and x is coercible to an int.  The i,j
69                         entry of self is set to x.  The x's can be 0.
70                       * Alternatively, entries can be a list of *all* the entries
71                         of the sparse matrix (so they would be mostly 0).
72            copy -- ignored
73            coerce -- ignored
74        """
75        cdef Py_ssize_t i, j, k
76        cdef Rational z
77        cdef void** X
78
79        # fill in entries in the dict case
80        if isinstance(entries, dict):
81            R = self.base_ring()
82            for ij, x in entries.iteritems():
83                z = R(x)
84                if z != 0:
85                    i, j = ij  # nothing better to do since this is user input, which may be bogus.
86                    if i < 0 or j < 0 or i >= self._nrows or j >= self._ncols:
87                        raise IndexError, "invalid entries list"
88                    mpq_vector_set_entry(&self._matrix[i], j, z.value)
89        elif isinstance(entries, list):
90            # Dense input format -- fill in entries
91            if len(entries) != self._nrows * self._ncols:
92                raise TypeError, "list of entries must be a dictionary of (i,j):x or a dense list of n * m elements"
93            seq = PySequence_Fast(entries,"expected a list")
94            X = PySequence_Fast_ITEMS(seq)
95            k = 0
96            R = self.base_ring()
97            # Get fast access to the entries list.
98            for i from 0 <= i < self._nrows:
99                for  j from 0 <= j < self._ncols:
100                    z = R(<object>X[k])
101                    if z != 0:
102                        mpq_vector_set_entry(&self._matrix[i], j, z.value)
103                    k = k + 1
104        else:
105            # fill in entries in the scalar case
106            z = Rational(entries)
107            if z == 0:
108                return
109            if self._nrows != self._ncols:
110                raise TypeError, "matrix must be square to initialize with a scalar."
111            for i from 0 <= i < self._nrows:
112                mpq_vector_set_entry(&self._matrix[i], i, z.value)
113           
114
115    cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, x):
116        mpq_vector_set_entry(&self._matrix[i], j, (<Rational> x).value)
117
118    cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
119        cdef Rational x
120        x = Rational()
121        mpq_vector_get_entry(&x.value, &self._matrix[i], j)
122        return x
123
124    def __richcmp__(Matrix self, right, int op):  # always need for mysterious reasons.
125        return self._richcmp(right, op)
126    def __hash__(self):
127        return self._hash()
128   
129   
130    ########################################################################
131    # LEVEL 2 functionality
132    #   * def _pickle
133    #   * def _unpickle
134    #   * cdef _add_c_impl
135    #   * cdef _sub_c_impl             
136    #   * cdef _mul_c_impl
137    #   * cdef _cmp_c_impl
138    #   * __neg__
139    #   * __invert__
140    #   * __copy__
141    #   * _multiply_classical
142    #   * _matrix_times_matrix_c_impl
143    #   * _list -- list of underlying elements (need not be a copy)
144    #   * _dict -- sparse dictionary of underlying elements (need not be a copy)
145    ########################################################################
146    # def _pickle(self):
147    # def _unpickle(self, data, int version):   # use version >= 0
148    # cdef ModuleElement _add_c_impl(self, ModuleElement right):
149    # cdef _mul_c_impl(self, Matrix right):
150    # cdef int _cmp_c_impl(self, Matrix right) except -2:
151    # def __neg__(self):
152    # def __invert__(self):
153    # def __copy__(self):
154    # def _multiply_classical(left, matrix.Matrix _right):
155    # def _list(self):
156    # def _dict(self):   
157   
158
159    ########################################################################
160    # LEVEL 3 functionality (Optional)
161    #    * cdef _sub_c_impl
162    #    * __deepcopy__
163    #    * __invert__
164    #    * Matrix windows -- only if you need strassen for that base
165    #    * Other functions (list them here):
166    ########################################################################
167
168##     cdef int mpz_denom(self, mpz_t d) except -1:
169##         mpz_set_si(d,1)
170##         cdef Py_ssize_t i, j
171##         cdef mpq_vector *v
172       
173##         _sig_on
174##         for i from 0 <= i < self._nrows:
175##             v = self._matrix[i]
176##             for j from 0 <= j < v.num_nonzero:
177##                 mpz_lcm(d, d, mpq_denref(v.entries[j]))
178##         _sig_off
179##         return 0
180
181##     def _clear_denom(self):
182##         """
183##         INPUT:
184##             self -- a matrix
185
186##         OUTPUT:
187##             D*self, D
188
189##         The product D*self is a matrix over ZZ
190##         """
191##         cdef Integer D
192##         cdef Py_ssize_t i, j
193##         cdef Matrix_integer_sparse A
194##         cdef mpz_t t
195
196##         D = Integer()
197##         self.mpz_denom(D.value)
198       
199##         MZ = sage.matrix.matrix_space.MatrixSpace(ZZ, self._nrows, self._ncols, sparse=True)
200##         A = MZ.zero_matrix()
201
202##         mpz_init(t)
203##             _sig_on
204##         for i from 0 <= i < self._nrows:
205##             v = self._matrix[i]
206##             for j from 0 <= j < v.num_nonzero:
207##                 mpz_divexact(t, D.value, mpq_denref(v.entries[j]))
208##                 mpz_mul(t, t, mpq_numref(v.entries[j]))
209##                 mpz_vector_set_entry(&A._matrix[i], v.positions[j], t)
210##         _sig_off
211##         mpz_clear(t)
212##         A._initialized = 1
213##         return A, D
214   
215
216    def _echelon_form_multimodular(self, height_guess=None, proof=True):
217        """
218        Returns reduced row-echelon form using a multi-modular
219        algorithm.  Does not change self.
220
221        REFERENCE: Chapter 7 of Stein's "Explicitly Computing Modular Forms".
222
223        INPUT:
224            height_guess -- integer or None
225            proof -- boolean (default: True)
226        """
227        import misc
228        return misc.matrix_rational_echelon_form_multimodular(self,
229                                 height_guess=height_guess, proof=proof)
Note: See TracBrowser for help on using the repository browser.