Happy New Year!
[ginac.git] / ginac / polynomial / normalize.h
1 /** @file normalize.h
2  *
3  *  Functions to normalize polynomials in a field. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #ifndef GINAC_UPOLY_NORMALIZE_H
24 #define GINAC_UPOLY_NORMALIZE_H
25
26 #include "upoly.h"
27 #include "ring_traits.h"
28 #include "debug.h"
29
30 namespace GiNaC {
31
32 bool normalize_in_field(umodpoly& a, cln::cl_MI* content_ = nullptr);
33
34 /// Make the univariate polynomial @a x unit normal. This version is used
35 /// for rings which are not fields. 
36 /// Returns true if the polynomial @x is already unit normal, and false
37 /// otherwise.
38 template<typename T> bool
39 normalize_in_ring(T& x, typename T::value_type* content_ = nullptr, int* unit_ = nullptr)
40 {
41         typedef typename T::value_type ring_t;
42         static const ring_t one(1);
43         if (x.empty())
44                 return true;
45
46         bool something_changed = false;
47         if (minusp(lcoeff(x))) {
48                 something_changed = true;
49                 if (unit_)
50                         *unit_ = -1;
51                 for (std::size_t i = x.size(); i-- != 0; )
52                         x[i] = - x[i];
53         }
54
55         if (degree(x) == 0) {
56                 if (content_)
57                         *content_ = x[0];
58                 if (x[0] == one)
59                         return something_changed;
60                 x[0] = one;
61                 return false; // initial polynomial was unit normal
62         }
63                 
64         // Compute the gcd of coefficients
65         ring_t content = lcoeff(x);
66         // We want this function to be fast when applied to unit normal
67         // polynomials. Hence we start from the leading coefficient.
68         for (std::size_t i = x.size() - 1; i-- != 0; ) {
69                 if (content == one) {
70                         if (content_)
71                                 *content_ = one;
72                         return something_changed;
73                 }
74                 content = gcd(x[i], content);
75         }
76
77         if (content == one) {
78                 if (content_)
79                         *content_ = one;
80                 return something_changed;
81         }
82         
83         for (std::size_t i = x.size(); i-- != 0; )
84                 x[i] = exquo(x[i], content);
85
86         if (content_)
87                 *content_ = content;
88         return false; // initial polynomial was not unit normal
89 }
90
91 } // namespace GiNaC
92         
93 #endif // GINAC_UPOLY_NORMALIZE_H