1 /*
2     Copyright (C) 2010 Sebastian Pancratz
3 
4     This file is part of FLINT.
5 
6     FLINT is free software: you can redistribute it and/or modify it under
7     the terms of the GNU Lesser General Public License (LGPL) as published
8     by the Free Software Foundation; either version 2.1 of the License, or
9     (at your option) any later version.  See <https://www.gnu.org/licenses/>.
10 */
11 
12 #include <gmp.h>
13 #include "flint.h"
14 #include "fmpz.h"
15 #include "fmpz_vec.h"
16 #include "fmpq_poly.h"
17 
_fmpq_poly_add_can(fmpz * rpoly,fmpz_t rden,const fmpz * poly1,const fmpz_t den1,slong len1,const fmpz * poly2,const fmpz_t den2,slong len2,int can)18 void _fmpq_poly_add_can(fmpz * rpoly, fmpz_t rden,
19                     const fmpz * poly1, const fmpz_t den1, slong len1,
20                     const fmpz * poly2, const fmpz_t den2, slong len2, int can)
21 {
22     slong max = FLINT_MAX(len1, len2);
23     slong min = FLINT_MIN(len1, len2);
24 
25     fmpz_t d;
26 
27     if (fmpz_equal(den1, den2))
28     {
29         _fmpz_poly_add(rpoly, poly1, len1, poly2, len2);
30 
31         if (fmpz_is_one(den1) || !can)
32             fmpz_set(rden, den1);
33         else
34         {
35             fmpz_init(d);
36             _fmpz_vec_content_chained(d, rpoly, max, den1);
37             if (fmpz_is_one(d))
38                   fmpz_set(rden, den1);
39             else
40             {
41                 _fmpz_vec_scalar_divexact_fmpz(rpoly, rpoly, max, d);
42                 fmpz_divexact(rden, den1, d);
43             }
44             fmpz_clear(d);
45         }
46 
47         return;
48     }
49 
50     fmpz_init(d);
51     fmpz_one(d);
52     if (!fmpz_is_one(den1) && !fmpz_is_one(den2))
53         fmpz_gcd(d, den1, den2);
54 
55     if (fmpz_is_one(d))
56     {
57         _fmpz_vec_scalar_mul_fmpz(rpoly, poly1, len1, den2);
58         _fmpz_vec_scalar_addmul_fmpz(rpoly, poly2, min, den1);
59         if (len1 < len2)
60             _fmpz_vec_scalar_mul_fmpz(rpoly + min, poly2 + min, max - min, den1);
61         fmpz_mul(rden, den1, den2);
62     }
63     else
64     {
65         fmpz_t den11;
66         fmpz_t den22;
67         fmpz_init(den11);
68         fmpz_init(den22);
69         fmpz_divexact(den11, den1, d);
70         fmpz_divexact(den22, den2, d);
71 
72         _fmpz_vec_scalar_mul_fmpz(rpoly, poly1, len1, den22);
73         _fmpz_vec_scalar_addmul_fmpz(rpoly, poly2, len2, den11);
74         if (len1 < len2)
75             _fmpz_vec_scalar_mul_fmpz(rpoly + min, poly2 + min, max - min, den11);
76 
77         if (_fmpz_vec_is_zero(rpoly, max))
78             fmpz_one(rden);
79         else
80         {
81             if (can)
82             {
83                fmpz_t e;
84                fmpz_init(e);
85                _fmpz_vec_content_chained(e, rpoly, max, d);
86                if (fmpz_is_one(e))
87                   fmpz_mul(rden, den1, den22);
88                else
89                {
90                    _fmpz_vec_scalar_divexact_fmpz(rpoly, rpoly, max, e);
91                    fmpz_divexact(den11, den1, e);
92                    fmpz_mul(rden, den11, den22);
93                }
94                fmpz_clear(e);
95             } else
96                fmpz_mul(rden, den1, den22);
97         }
98         fmpz_clear(den11);
99         fmpz_clear(den22);
100     }
101     fmpz_clear(d);
102 }
103 
_fmpq_poly_add(fmpz * rpoly,fmpz_t rden,const fmpz * poly1,const fmpz_t den1,slong len1,const fmpz * poly2,const fmpz_t den2,slong len2)104 void _fmpq_poly_add(fmpz * rpoly, fmpz_t rden,
105                     const fmpz * poly1, const fmpz_t den1, slong len1,
106                     const fmpz * poly2, const fmpz_t den2, slong len2)
107 {
108    _fmpq_poly_add_can(rpoly, rden, poly1, den1, len1, poly2, den2, len2, 1);
109 }
110 
fmpq_poly_add_can(fmpq_poly_t res,const fmpq_poly_t poly1,const fmpq_poly_t poly2,int can)111 void fmpq_poly_add_can(fmpq_poly_t res, const fmpq_poly_t poly1,
112                                     const fmpq_poly_t poly2, int can)
113 {
114     slong len1 = poly1->length, len2, max;
115 
116     if (poly1 == poly2)  /* Set res = 2 * poly1 */
117     {
118         fmpq_poly_fit_length(res, len1);
119         _fmpq_poly_set_length(res, len1);
120 
121         if (fmpz_is_even(poly1->den))
122         {
123             _fmpz_vec_set(res->coeffs, poly1->coeffs, len1);
124             fmpz_fdiv_q_2exp(res->den, poly1->den, 1);
125         }
126         else
127         {
128             _fmpz_vec_scalar_mul_2exp(res->coeffs, poly1->coeffs, len1, 1);
129             fmpz_set(res->den, poly1->den);
130         }
131         return;
132     }
133 
134     len2 = poly2->length;
135     max  = FLINT_MAX(len1, len2);
136     fmpq_poly_fit_length(res, max);
137 
138     if (res != poly2)
139         _fmpq_poly_add_can(res->coeffs, res->den,
140                        poly1->coeffs, poly1->den, len1,
141                        poly2->coeffs, poly2->den, len2, can);
142     else
143         _fmpq_poly_add_can(res->coeffs, res->den,
144                        poly2->coeffs, poly2->den, len2,
145                        poly1->coeffs, poly1->den, len1, can);
146 
147     _fmpq_poly_set_length(res, max);
148     _fmpq_poly_normalise(res);
149 }
150 
fmpq_poly_add(fmpq_poly_t res,const fmpq_poly_t poly1,const fmpq_poly_t poly2)151 void fmpq_poly_add(fmpq_poly_t res, const fmpq_poly_t poly1,
152                                     const fmpq_poly_t poly2)
153 {
154    fmpq_poly_add_can(res, poly1, poly2, 1);
155 }
156 
fmpq_poly_add_si(fmpq_poly_t res,const fmpq_poly_t poly,slong c)157 void fmpq_poly_add_si(fmpq_poly_t res, const fmpq_poly_t poly, slong c)
158 {
159     if (c == 0)
160     {
161         fmpq_poly_set(res, poly);
162     }
163     else if (poly->length == 0)
164     {
165         fmpq_poly_set_si(res, c);
166     }
167     else
168     {
169         fmpz_t p, q;
170         fmpz_init_set_si(p, c);
171         *q = 1;
172         fmpq_poly_fit_length(res, poly->length);
173         _fmpq_poly_set_length(res, poly->length);
174         _fmpq_poly_add(res->coeffs, res->den, poly->coeffs, poly->den, poly->length, p, q, 1);
175         _fmpq_poly_normalise(res);
176         fmpz_clear(p);
177     }
178 }
179 
fmpq_poly_add_fmpz(fmpq_poly_t res,const fmpq_poly_t poly,const fmpz_t c)180 void fmpq_poly_add_fmpz(fmpq_poly_t res, const fmpq_poly_t poly, const fmpz_t c)
181 {
182     if (fmpz_is_zero(c))
183     {
184         fmpq_poly_set(res, poly);
185     }
186     else if (poly->length == 0)
187     {
188         fmpq_poly_set_fmpz(res, c);
189     }
190     else
191     {
192         fmpz_t q;
193         *q = 1;
194         fmpq_poly_fit_length(res, poly->length);
195         _fmpq_poly_set_length(res, poly->length);
196         _fmpq_poly_add(res->coeffs, res->den, poly->coeffs, poly->den, poly->length, c, q, 1);
197         _fmpq_poly_normalise(res);
198     }
199 }
200 
fmpq_poly_add_fmpq(fmpq_poly_t res,const fmpq_poly_t poly,const fmpq_t c)201 void fmpq_poly_add_fmpq(fmpq_poly_t res, const fmpq_poly_t poly, const fmpq_t c)
202 {
203     if (fmpq_is_zero(c))
204     {
205         fmpq_poly_set(res, poly);
206     }
207     else if (poly->length == 0)
208     {
209         fmpq_poly_set_fmpq(res, c);
210     }
211     else
212     {
213         fmpq_poly_fit_length(res, poly->length);
214         _fmpq_poly_set_length(res, poly->length);
215         _fmpq_poly_add(res->coeffs, res->den, poly->coeffs, poly->den, poly->length, fmpq_numref(c), fmpq_denref(c), 1);
216         _fmpq_poly_normalise(res);
217     }
218 }
219