Merge branch 'master' of git://ffmssmsc.jinr.ru:443/varg/ginac
[ginac.git] / ginac / polynomial / cra_garner.cpp
1 #include <cln/integer.h>
2 #include <cln/modinteger.h>
3 #include <vector>
4 #include <cstddef>
5 #include "cra_garner.hpp"
6
7 namespace cln
8 {
9 using std::vector;
10 using std::size_t;
11
12 static cl_I 
13 retract_symm(const cl_MI& x, const cl_modint_ring& R,
14              const cl_I& modulus)
15 {
16         cl_I result = R->retract(x);
17         if (result > (modulus >> 1))
18                 result = result - modulus;
19         return result;
20 }
21
22 static void
23 compute_recips(vector<cl_MI>& dst, 
24                const vector<cl_I>& moduli)
25 {
26         for (size_t k = 1; k < moduli.size(); ++k) {
27                 cl_modint_ring R = find_modint_ring(moduli[k]);
28                 cl_MI product = R->canonhom(moduli[0]);
29                 for (size_t i = 1; i < k; ++i)
30                         product = product*moduli[i];
31                 dst[k-1] = recip(product);
32         }
33 }
34
35 static void
36 compute_mix_radix_coeffs(vector<cl_I>& dst,
37                          const vector<cl_I>& residues,
38                          const vector<cl_I>& moduli,
39                          const vector<cl_MI>& recips)
40 {
41         dst[0] = residues[0];
42
43         do {
44                 cl_modint_ring R = find_modint_ring(moduli[1]);
45                 cl_MI tmp = R->canonhom(residues[0]);
46                 cl_MI next = (R->canonhom(residues[1]) - tmp)*recips[0];
47                 dst[1] = retract_symm(next, R, moduli[1]);
48         } while (0);
49
50         for (size_t k = 2; k < residues.size(); ++k) {
51                 cl_modint_ring R = find_modint_ring(moduli[k]);
52                 cl_MI tmp = R->canonhom(dst[k-1]);
53
54                 for (size_t j = k - 1 /* NOT k - 2 */; j-- != 0; )
55                         tmp = tmp*moduli[j] + R->canonhom(dst[j]);
56
57                 cl_MI next = (R->canonhom(residues[k]) - tmp)*recips[k-1];
58                 dst[k] = retract_symm(next, R, moduli[k]);
59         }
60 }
61
62 static cl_I
63 mixed_radix_2_ordinary(const vector<cl_I>& mixed_radix_coeffs,
64                        const vector<cl_I>& moduli)
65 {
66         size_t k = mixed_radix_coeffs.size() - 1;
67         cl_I u = mixed_radix_coeffs[k];
68         for (; k-- != 0; )
69                 u = u*moduli[k] + mixed_radix_coeffs[k];
70         return u;
71 }
72
73 cl_I integer_cra(const vector<cl_I>& residues,
74                  const vector<cl_I>& moduli)
75 {
76
77         vector<cl_MI> recips(moduli.size() - 1);
78         compute_recips(recips, moduli);
79
80         vector<cl_I> coeffs(moduli.size());
81         compute_mix_radix_coeffs(coeffs, residues, moduli, recips);
82         cl_I result = mixed_radix_2_ordinary(coeffs, moduli);
83
84         return result;
85 }
86
87 } // namespace cln
88