Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
8526ca2
Make Stein gcd more generic for polynomial.
jeremy-murphy May 23, 2016
579f332
[gcd] Stein_gcd: assert that at least one of the operands is not zero.
jeremy-murphy Jun 20, 2016
b3596f0
[gcd] Add/update comments.
jeremy-murphy Jun 20, 2016
04c96ae
Merge branch 'develop' into gcd_Stein_poly
jeremy-murphy Jun 20, 2016
58c17ae
[polynomial] Make the gcd_traits subtraction more debug friendly.
jeremy-murphy Jun 23, 2016
a6b550a
[polynomial] Make separate Euclid and Stein gcd test cases.
jeremy-murphy Jun 23, 2016
3cb1a25
[gcd] Improve comments, use more asserts in Stein_gcd.
jeremy-murphy Jun 23, 2016
3caf635
[polynomial] Simplify gcd_traits::subtract.
jeremy-murphy Jun 25, 2016
d507474
[polynomial] Expand unit tests of Euclid and Stein gcd.
jeremy-murphy Jun 25, 2016
7e10edd
[gcd] Tweak comments and assertions.
jeremy-murphy Jun 27, 2016
577547a
[polynomial] Add Antoine Joux's implementation of subtraction for Stein.
jeremy-murphy Jun 27, 2016
0df6016
More specific gcd_traits for polynomial...
jeremy-murphy Jun 29, 2016
97d0566
[gcd] Add odd/even functions for integers, mostly for debugging.
jeremy-murphy Jul 3, 2016
11f3d04
[polynomial] Split gcd_traits on coefficient type: float vs int.
jeremy-murphy Jul 3, 2016
54a8835
[polynomial] Make the Stein_gcd unit tests more organized.
jeremy-murphy Jul 3, 2016
aff5c07
[polynomial] Move gcd_traits into new file.
jeremy-murphy Jul 6, 2016
ca97a3b
Redesign gcd unit tests to use fixtures.
jeremy-murphy Jul 6, 2016
ed5fe6a
Merge branch 'develop' into gcd_Stein_poly
jeremy-murphy Jul 12, 2016
5fc2791
Merge branch 'develop' into gcd_Stein_poly
jeremy-murphy Jul 17, 2016
cd8ac4f
Merge branch 'develop' into gcd_Stein_poly
jeremy-murphy Aug 3, 2016
1491ab1
Merge branch 'develop' into gcd_Stein_poly
jeremy-murphy Dec 4, 2016
8129587
Merge branch 'develop' into gcd_Stein_poly
jeremy-murphy Dec 4, 2016
92bc677
Use Stepanov or Joux implementation of subtraction as appropriate.
jeremy-murphy Dec 5, 2016
5ae445e
Common gcd traits for polynomials.
jeremy-murphy Dec 5, 2016
0629a9f
A kludge to allow gcd<double>, which makes Stein_gcd<double> work.
jeremy-murphy Dec 5, 2016
2524741
If gcd_traits::normalize works, then the tests pass.
jeremy-murphy Dec 5, 2016
fa0fac2
Remove gcd header from polynomial.
jeremy-murphy Dec 5, 2016
4df9cf5
Use the convenience typedef polynomial_type.
jeremy-murphy Dec 5, 2016
cf0ff3d
Include normalize in abs_defaults; add modulo defaults; always normal…
jeremy-murphy Dec 7, 2016
010de67
Use the same approach for Z[x] as for R[X].
jeremy-murphy Dec 7, 2016
2f141cf
Consolidate the polynomial normalization gcd_trait.
jeremy-murphy Dec 7, 2016
32f2e83
To implicitly cast to bool or not, that is the question.
jeremy-murphy Dec 7, 2016
4a0bfd8
TODO: Decorate the failing Euclid test.
jeremy-murphy Dec 8, 2016
b5d54da
Explicitly convert return value to bool.
jeremy-murphy Dec 8, 2016
2982b3b
Use library's mixed_binary_gcd, forbid gcd(0, 0).
jeremy-murphy Dec 8, 2016
e7b5e40
Simplify Euclidean algorithm very slightly using (x) vs (x != 0).
jeremy-murphy Dec 11, 2016
f4f94f1
Instead of normalizing after Joux's subtraction, find gcd(a(0), b(0))…
jeremy-murphy Dec 11, 2016
cd4f125
Add performance reporting test for gcd of polynomials.
jeremy-murphy Dec 14, 2016
1cd5679
Modularize the various subtraction methods for Stein gcd.
jeremy-murphy Jan 22, 2017
082cb40
Update performance test to support different Stein implementations.
jeremy-murphy Jan 22, 2017
8679047
Add explicit constructor from storage type (std::vector).
jeremy-murphy Nov 26, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 80 additions & 30 deletions include/boost/math/common_factor_rt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ namespace boost {
struct gcd_traits_abs_defaults
{
inline static const T& abs(const T& val) { return val; }

inline static void normalize(T&) {}
};

template <class T>
struct gcd_traits_abs_defaults<T, false>
{
Expand All @@ -45,10 +48,32 @@ namespace boost {
using std::abs;
return abs(val);
}

inline static void normalize(T& val) { val = abs(val); }
};


template <typename T, bool = is_floating_point<T>::value || (std::numeric_limits<T>::is_specialized && !std::numeric_limits<T>::is_integer)>
struct gcd_traits_modulo_defaults
{
inline static void modulo(T& a, const T& b)
{
using std::fmod;
a = fmod(a, b);
}
};

template <class T>
struct gcd_traits_modulo_defaults<T, false>
{
inline static void modulo(T& a, const T& b)
{
a %= b;
}
};

template <class T>
struct gcd_traits_defaults : public gcd_traits_abs_defaults<T>
struct gcd_traits_defaults : public gcd_traits_abs_defaults<T>, gcd_traits_modulo_defaults<T>
{
BOOST_FORCEINLINE static unsigned make_odd(T& val)
{
Expand All @@ -60,11 +85,17 @@ namespace boost {
}
return r;
}

inline static bool less(const T& a, const T& b)
{
return a < b;
}

inline static void subtract(T& a, const T& b)
{
a -= b;
}

enum method_type
{
method_euclid = 0,
Expand All @@ -78,25 +109,13 @@ namespace boost {
boost::has_right_shift_assign<T>::value && boost::has_left_shift_assign<T>::value && boost::has_less<T>::value
? method_binary : method_euclid;
};

//
// Default gcd_traits just inherits from defaults:
//
template <class T>
struct gcd_traits : public gcd_traits_defaults<T> {};
//
// Special handling for polynomials:
//
namespace tools {
template <class T>
class polynomial;
}

template <class T>
struct gcd_traits<boost::math::tools::polynomial<T> > : public gcd_traits_defaults<T>
{
static const boost::math::tools::polynomial<T>& abs(const boost::math::tools::polynomial<T>& val) { return val; }
};
//

// Some platforms have fast bitscan operations, that allow us to implement
// make_odd much more efficiently:
//
Expand Down Expand Up @@ -253,6 +272,23 @@ namespace boost {
};
#endif

template <typename T>
inline
typename enable_if_c<std::numeric_limits<T>::is_integer, bool>::type
odd(const T& x)
{
return bool(x & 1u);
}

template <typename T>
inline
typename enable_if_c<std::numeric_limits<T>::is_integer, bool>::type
even(const T& x)
{
return !odd(x);
}


namespace detail
{

Expand All @@ -277,7 +313,7 @@ namespace detail

shifts = (std::min)(gcd_traits<T>::make_odd(u), gcd_traits<T>::make_odd(v));

while(gcd_traits<T>::less(1, v))
while(u != v)
{
u %= v;
v -= u;
Expand All @@ -290,36 +326,48 @@ namespace detail
if(gcd_traits<T>::less(u, v))
swap(u, v);
}
return (v == 1 ? v : u) << shifts;
u <<= shifts;
return u;
}

/** Stein gcd (aka 'binary gcd')
*
* From Mathematics to Generic Programming, Alexander Stepanov, Daniel Rose
*
* What can we say about the Stein Domain?
* - It must have zero.
* - It must have parity: being exclusively even or odd.
* - It must have a smallest prime (2 for integers, x for polynomials, etc).
* - It must have shift operations that add or remove factors of the smallest prime.
* - It does not work for negative integers.
*/
template <typename SteinDomain>
SteinDomain Stein_gcd(SteinDomain m, SteinDomain n)
{
using std::swap;
BOOST_ASSERT(m >= 0);
BOOST_ASSERT(n >= 0);
if (m == SteinDomain(0))
BOOST_ASSERT(m || n);
if (!m)
return n;
if (n == SteinDomain(0))
if (!n)
return m;
// m > 0 && n > 0
int d_m = gcd_traits<SteinDomain>::make_odd(m);
int d_n = gcd_traits<SteinDomain>::make_odd(n);
unsigned shifts = std::min(gcd_traits<SteinDomain>::make_odd(m), gcd_traits<SteinDomain>::make_odd(n));
// odd(m) && odd(n)
while (m != n)
{
if (n > m)
if (gcd_traits<SteinDomain>::less(m, n))
swap(n, m);
m -= n;
gcd_traits<SteinDomain>::subtract(m, n);
BOOST_ASSERT(even(m));
// With polynomials for example, it is possible that m is now zero.
if (!m)
{
n <<= shifts;
return n;
}
gcd_traits<SteinDomain>::make_odd(m);
}
// m == n
m <<= (std::min)(d_m, d_n);
m <<= shifts;
return m;
}

Expand All @@ -333,9 +381,9 @@ namespace detail
inline EuclideanDomain Euclid_gcd(EuclideanDomain a, EuclideanDomain b)
{
using std::swap;
while (b != EuclideanDomain(0))
while (b)
{
a %= b;
gcd_traits<EuclideanDomain>::modulo(a, b);
swap(a, b);
}
return a;
Expand Down Expand Up @@ -380,7 +428,9 @@ namespace detail
template <typename Integer>
inline Integer gcd(Integer const &a, Integer const &b)
{
return detail::optimal_gcd_select(static_cast<Integer>(gcd_traits<Integer>::abs(a)), static_cast<Integer>(gcd_traits<Integer>::abs(b)));
Integer result = detail::optimal_gcd_select(static_cast<Integer>(gcd_traits<Integer>::abs(a)), static_cast<Integer>(gcd_traits<Integer>::abs(b)));
gcd_traits<Integer>::normalize(result);
return result;
}

template <typename Integer>
Expand Down
36 changes: 31 additions & 5 deletions include/boost/math/tools/polynomial.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <boost/math/special_functions/binomial.hpp>
#include <boost/operators.hpp>

#include <limits>
#include <vector>
#include <ostream>
#include <algorithm>
Expand Down Expand Up @@ -277,6 +278,13 @@ class polynomial :
normalize();
}


explicit polynomial(std::vector<T> const &data)
: m_data(data)
{
normalize();
}

template <class I>
polynomial(I first, I last)
: m_data(first, last)
Expand Down Expand Up @@ -444,8 +452,7 @@ class polynomial :
template <typename U>
polynomial& operator >>=(U const &n)
{
BOOST_ASSERT(n <= m_data.size());
m_data.erase(m_data.begin(), m_data.begin() + n);
m_data.erase(m_data.begin(), m_data.begin() + std::min(size_type(n), m_data.size()));
return *this;
}

Expand Down Expand Up @@ -491,6 +498,12 @@ class polynomial :
using namespace boost::lambda;
m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), _1 != T(0)).base(), m_data.end());
}

// Negate in-place.
void negate()
{
std::transform(data().begin(), data().end(), data().begin(), std::negate<T>());
}

private:
template <class U, class R1, class R2>
Expand Down Expand Up @@ -696,6 +709,7 @@ polynomial<T> pow(polynomial<T> base, int exp)
return result;
}


template <class charT, class traits, class T>
inline std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT, traits>& os, const polynomial<T>& poly)
{
Expand All @@ -709,11 +723,23 @@ inline std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT,
return os;
}


template <typename T>
T constant_coefficient(polynomial<T> const &x)
{
return x ? x.data().front() : T(0);
}

// Trivial but useful convenience function referred to simply as l() in Knuth.
template <class T>
T leading_coefficient(polynomial<T> const &x)
{
BOOST_ASSERT(x);
return x.data().back();
}

} // namespace tools
} // namespace math
} // namespace boost

#endif // BOOST_MATH_TOOLS_POLYNOMIAL_HPP



Loading