source: sage/modules/vector_rational_sparse_c.pxi @ 3092:227119d39b73

Revision 3092:227119d39b73, 12.0 KB checked in by William Stein <wstein@…>, 6 years ago (diff)

matrix coding sprint -- snapshot.

Line 
1#############################################################
2#
3#    Sparse Vector over mpq_t (the GMP rationals)
4#
5#############################################################
6
7include "../ext/cdefs.pxi"
8
9cdef struct mpq_vector:
10    mpq_t *entries      # array of nonzero entries
11    int   *positions    # positions of those nonzero entries, starting at 0
12    int    degree       # the degree of this sparse vector
13    int    num_nonzero  # the number of nonzero entries of this vector.
14
15cdef int allocate_mpq_vector(mpq_vector* v, int num_nonzero) except -1:
16    """
17    Allocate memory for a mpq_vector -- most user code won't call this.
18    num_nonzero is the number of nonzero entries to allocate memory for.
19
20    This function *does* call mpq_init on each mpq_t that is allocated.
21    It does *not* clear the entries of v, if there are any.
22    """
23    cdef int i
24    v.entries = <mpq_t*>sage_malloc(num_nonzero*sizeof(mpq_t))
25    if v.entries == <mpq_t*> 0:
26        raise MemoryError, "Error allocating memory"
27    for i from 0 <= i < num_nonzero:
28        mpq_init(v.entries[i])
29    v.positions = <int*>sage_malloc(num_nonzero*sizeof(int))
30    if v.positions == <int*> 0:
31        raise MemoryError, "Error allocating memory"
32    return 0
33
34cdef int init_mpq_vector(mpq_vector* v, int degree, int num_nonzero) except -1:
35    """
36    Initialize a mpq_vector -- most user code *will* call this.
37    """
38    allocate_mpq_vector(v, num_nonzero)
39    v.num_nonzero = num_nonzero
40    v.degree = degree
41
42cdef void clear_mpq_vector(mpq_vector* v):
43    cdef int i
44    # Free all mpq objects allocated in creating v
45    for i from 0 <= i < v.num_nonzero:
46        mpq_clear(v.entries[i])
47    # Free entries and positions of those entries.
48    # These were allocated from the Python heap.
49    # If init_mpq_vector was not called, then this
50    # will (of course!) cause a core dump.
51    sage_free(v.entries)
52    sage_free(v.positions)
53
54cdef int mpq_binary_search0(mpq_t* v, int n, mpq_t x):
55    """
56    Find the position of the rational x in the array v, which has length n.
57    Returns -1 if x is not in the array v.
58    """
59    cdef int i, j, k, c
60    if n == 0:
61        return -1
62    i = 0
63    j = n-1
64    while i<=j:
65        if i == j:
66            if mpq_equal(v[i],x):
67                return i
68            return -1
69        k = (i+j)/2
70        c = mpq_cmp(v[k],x)
71        if c > 0:       # v[k] > x
72            j = k-1
73        elif c < 0:     # v[k] < x
74            i = k+1
75        else:   # only possibility is that v[k] == x
76            return k
77    return -1
78
79cdef int mpq_binary_search(mpq_t* v, int n, mpq_t x, int* ins):
80    """
81    Find the position of the integer x in the array v, which has length n.
82    Returns -1 if x is not in the array v, and in this case ins is
83    set equal to the position where x should be inserted in order to
84    obtain an ordered array.
85   
86    INPUT:
87       v -- array of mpq_t  (rational)
88       n -- integer (length of array v)
89       x -- mpq_t  (rational)
90    OUTPUT:
91       position of x (as an int)
92       ins -- (call be pointer), the insertion point if x is not found.
93    """
94    cdef int i, j, k, c
95    if n == 0:
96        ins[0] = 0
97        return -1
98    i = 0
99    j = n-1
100    while i<=j:
101        if i == j:
102            c = mpq_cmp(v[i],x)
103            if c == 0:          # v[i] == x
104                ins[0] = i
105                return i
106            if c < 0:           # v[i] < x
107                ins[0] = i + 1
108            else:
109                ins[0] = i
110            return -1
111        k = (i+j)/2
112        c = mpq_cmp(v[k], x)
113        if c > 0:               # v[k] > x
114            j = k-1
115        elif c < 0:             # v[k] < x
116            i = k+1
117        else:   # only possibility is that v[k] == x
118            ins[0] = k
119            return k
120    # end while
121    ins[0] = j+1
122    return -1
123
124cdef int mpq_vector_get_entry(mpq_t* ans, mpq_vector* v, int n) except -1:
125    """
126    Returns the n-th entry of the sparse vector v.  This
127    would be v[n] in Python syntax.
128
129    The return is done using the pointer ans, which is to an mpq_t
130    that *must* have been initialized using mpq_init.
131    """
132    if n >= v.degree:
133        raise IndexError, "Index must be between 0 and %s."%(v.degree - 1)
134    cdef int m
135    m = binary_search0(v.positions, v.num_nonzero, n)
136    if m == -1:
137        mpq_set_si(ans[0], 0,1)
138        return 0
139    mpq_set(ans[0], v.entries[m])
140    return 0
141
142cdef object mpq_vector_to_list(mpq_vector* v):
143    """
144    Returns a Python list of 2-tuples (i,x), where x=v[i] runs
145    through the nonzero elements of x, in order.
146    """
147    cdef X
148    cdef sage.rings.rational.Rational a
149    cdef int i
150    X = []
151    for i from 0 <= i < v.num_nonzero:
152        a = sage.rings.rational.Rational()
153        a.set_from_mpq(v.entries[i])
154        X.append( (v.positions[i], a) )
155    return X
156
157
158cdef int mpq_vector_set_entry(mpq_vector* v, int n, mpq_t x) except -1:
159    """
160    Set the n-th component of the sparse vector v equal to x.
161    This would be v[n] = x in Python syntax.
162    """
163    if n >= v.degree or n < 0:
164        raise IndexError, "Index must be between 0 and the degree minus 1."
165        return -1
166    cdef int i, m, ins
167    cdef int m2, ins2
168    cdef int *pos
169    cdef mpq_t *e
170
171    m = binary_search(v.positions, v.num_nonzero, n, &ins)
172   
173    if m != -1:
174        # The position n was found in the array of positions.
175        # Now there are two cases:
176        #   1. x =/= 0, which is easy, and
177        #   2. x = 0, in which case we have to recopy
178        #      positions and entries, without the m-th
179        #      element, and change num_nonzero.
180        if mpq_sgn(x) != 0:   # x != 0,  case 1
181            # v.entries[m] = x
182            mpq_set(v.entries[m], x)
183        else:        # case 2
184            e = v.entries
185            pos = v.positions
186            allocate_mpq_vector(v, v.num_nonzero - 1)
187            for i from 0 <= i < m:
188                # v.entries[i] = e[i]
189                mpq_set(v.entries[i], e[i])
190                v.positions[i] = pos[i]
191            for i from m < i < v.num_nonzero:
192                # v.entries[i-1] = e[i]
193                mpq_set(v.entries[i-1], e[i])
194                v.positions[i-1] = pos[i]
195            sage_free(e)
196            sage_free(pos)
197            v.num_nonzero = v.num_nonzero - 1
198    else:
199        # Allocate new memory and copy over elements from the
200        # old array.  This is similar to case 2 above,
201        # except we are inserting a new entry rather than
202        # deleting an old one.  The new entry should be inserted
203        # at position ins, which was computed using binary search.
204        #
205        # There is one exception -- if the new entry is 0, we
206        # do nothing and return.
207        if mpq_sgn(x) == 0:
208            return 0
209        v.num_nonzero = v.num_nonzero + 1
210        e = v.entries
211        pos = v.positions
212        allocate_mpq_vector(v, v.num_nonzero)
213        for i from 0 <= i < ins:
214            # v.entries[i] = e[i]
215            mpq_set(v.entries[i], e[i])
216            v.positions[i] = pos[i]
217        # v.entries[ins] = x
218        mpq_set(v.entries[ins], x)
219        v.positions[ins] = n
220        for i from ins < i < v.num_nonzero:
221            mpq_set(v.entries[i], e[i-1])
222            v.positions[i] = pos[i-1]
223        # Free the memory occupie by GMP rationals.
224        # This -1 is because we incremented v.num_nonzero above.
225        for i from 0 <= i < v.num_nonzero-1:
226            mpq_clear(e[i])
227        sage_free(e)
228        sage_free(pos)
229
230
231
232cdef mpq_t mpq_set_tmp
233mpq_init(mpq_set_tmp)
234cdef int mpq_vector_set_entry_str(mpq_vector* v, int n, char *x_str) except -1:
235    """
236    Set the n-th component of the sparse vector v equal to x.
237    This would be v[n] = x in Python syntax.
238    """
239    mpq_set_str(mpq_set_tmp, x_str, 0)
240    mpq_vector_set_entry(v, n, mpq_set_tmp)
241
242
243cdef int add_mpq_vector_init(mpq_vector* sum,
244                             mpq_vector* v,
245                             mpq_vector* w,
246                             mpq_t multiple) except -1:
247    """
248    Initialize sum and set sum = v + multiple*w.
249    """
250    if v.degree != w.degree:
251        print "Can't add vectors of degree %s and %s"%(v.degree, w.degree)
252        raise ArithmeticError, "The vectors must have the same degree."
253
254    cdef int nz, i, j, k, do_multiply
255    cdef mpq_vector* z
256    cdef mpq_t tmp
257    mpq_init(tmp)
258    if mpq_cmp_si(multiple, 0, 1) == 0:
259        init_mpq_vector(sum, v.degree, 0)
260        return 0
261    # Do not do the multiply if the multiple is 1.
262    do_multiply = mpq_cmp_si(multiple, 1,1)
263   
264    z = sum
265    # ALGORITHM:
266    # 1. Allocate enough memory to hold the union of the two
267    #    lists of positions.  We allocate the sum of the number
268    #    of positions of both (up to the degree), to avoid
269    #    having to make two passes.  This might be slightly wasteful of
270    #    memory, but is faster.
271    # 2. Move along the entries of v and w, copying them into the
272    #    new position / entry array.  When position are the same,
273    #    add modulo p.
274    # 3. Set num_nonzero and return success code.
275
276    # 1. Allocate memory:
277    nz = v.num_nonzero + w.num_nonzero
278    if nz > v.degree: nz = v.degree
279    init_mpq_vector(z, v.degree, nz)
280    # 2. Merge entries
281    i = 0  # index into entries of v
282    j = 0  # index into entries of w
283    k = 0  # index into z (the vector we are creating)
284    while i < v.num_nonzero or j < w.num_nonzero:
285        if i >= v.num_nonzero:   # just copy w in
286            z.positions[k] = w.positions[j]
287           
288            if do_multiply:
289                # This means: z.entries[k] = (multiple*w.entries[j])
290                mpq_mul(z.entries[k], multiple, w.entries[j])
291            else:
292                mpq_set(z.entries[k], w.entries[j])
293            j = j + 1
294            k = k + 1
295        elif j >= w.num_nonzero:  # just copy v in
296            z.positions[k] = v.positions[i]
297            # This means: z.entries[k] = v.entries[i]
298            mpq_set(z.entries[k], v.entries[i])
299            i = i + 1
300            k = k + 1           
301        elif v.positions[i] < w.positions[j]:  # copy entry from v in
302            z.positions[k] = v.positions[i]
303            # This means: z.entries[k] = v.entries[i]
304            mpq_set(z.entries[k], v.entries[i])
305            i = i + 1
306            k = k + 1           
307        elif v.positions[i] > w.positions[j]: # copy entry from w in
308            if do_multiply:
309                # This means: tmp = multiple*w.entries[j]
310                mpq_mul(tmp, multiple, w.entries[j])
311                # This means: z.entries[k] = tmp
312                mpq_set(z.entries[k], tmp)
313            else:
314                mpq_set(z.entries[k], w.entries[j])
315            z.positions[k] = w.positions[j]
316            k = k + 1           
317            j = j + 1
318        else:                                 # equal, so add and copy
319            if do_multiply:
320                # This means: tmp = v.entries[i] + multiple*w.entries[j]
321                mpq_mul(tmp, multiple, w.entries[j])
322                mpq_add(tmp, tmp, v.entries[i])
323            else:
324                mpq_add(tmp, v.entries[i], w.entries[j])
325            if mpq_sgn(tmp) != 0:
326                z.positions[k] = v.positions[i]
327                # This means: z.entries[k] = tmp
328                mpq_set(z.entries[k], tmp)
329                k = k + 1     # only increment if sum is nonzero!
330            i = i + 1
331            j = j + 1
332        #end if
333    # end while
334    z.num_nonzero = k
335    mpq_clear(tmp)
336    return 0
337
338cdef int scale_mpq_vector(mpq_vector* v, mpq_t scalar) except -1:
339    if mpq_sgn(scalar) == 0:  # scalar = 0
340        clear_mpq_vector(v)
341        init_mpq_vector(v, v.degree, 0)
342        return 0
343    cdef int i
344    for i from 0 <= i < v.num_nonzero:
345        # v.entries[i] = scalar * v.entries[i]
346        mpq_mul(v.entries[i], v.entries[i], scalar)
347    return 0
348
349cdef int mpq_vector_cmp(mpq_vector* v, mpq_vector* w):
350    if v.degree < w.degree:
351        return -1
352    elif v.degree > w.degree:
353        return 1
354    cdef int i, c
355    for i from 0 <= i < v.num_nonzero:
356        c = mpq_cmp(v.entries[i], w.entries[i])
357        if c < 0:
358            return -1
359        elif c > 0:
360            return 1
361    return 0
Note: See TracBrowser for help on using the repository browser.