00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef MATH_POWER_INCLUDE
00013 #define MATH_POWER_INCLUDE
00014
00015 #include <concepts>
00016 #include <boost/numeric/linear_algebra/concepts.hpp>
00017 #include <boost/numeric/linear_algebra/identity.hpp>
00018 #include <stdexcept>
00019
00020
00021 namespace math {
00022
00023 template <typename Op, std::Semiregular Element, Integral Exponent>
00024 requires std::Callable2<Op, Element, Element>
00025 && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
00026 inline Element power(const Element& a, Exponent n, Op op)
00027 {
00028 std::cout << "[Magma] ";
00029 if (n < 1) throw std::range_error("power [magma]: n must be > 0");
00030
00031 Element value= a;
00032 for (; n > 1; --n)
00033 value= op(value, a);
00034 return value;
00035 }
00036
00037 #if 0
00038 template <typename Op, std::Semiregular Element, Integral Exponent>
00039 requires SemiGroup<Op, Element>
00040 && std::Callable2<Op, Element, Element>
00041 && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
00042 inline Element multiply_and_square_horner(const Element& a, Exponent n, Op op)
00043 {
00044 if (n < 1) throw std::range_error("mult&square Horner: n must be > 0");
00045
00046
00047 Exponent mask= 1 << (8 * sizeof(mask) - 1);
00048
00049
00050
00051 if (mask < 0)
00052 mask= 1 << (8 * sizeof(mask) - 2);
00053
00054
00055 while(!bool(mask & n)) mask>>= 1;
00056
00057 Element value= a;
00058 for (mask>>= 1; mask; mask>>= 1) {
00059 value= op(value, value);
00060 if (n & mask)
00061 value= op(value, a);
00062 }
00063 return value;
00064 }
00065
00066 template <typename Op, std::Semiregular Element, Integral Exponent>
00067 requires SemiGroup<Op, Element>
00068 && std::Callable2<Op, Element, Element>
00069 && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
00070 inline Element power(const Element& a, Exponent n, Op op)
00071 {
00072 return multiply_and_square_horner(a, n, op);
00073 }
00074 #endif
00075
00076
00077 #if 1
00078
00079
00080 template <typename Op, std::Semiregular Element, Integral Exponent>
00081 requires SemiGroup<Op, Element>
00082 && std::Callable2<Op, Element, Element>
00083 && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
00084 inline Element power(const Element& a, Exponent n, Op op)
00085 {
00086 std::cout << "[SemiGroup] ";
00087 if (n < 1) throw std::range_error("power [SemiGroup]: n must be > 0");
00088
00089 Exponent half(n / 2);
00090
00091 if (half == 0)
00092 return a;
00093
00094
00095 Element value= power(a, half, op);
00096 value= op(value, value);
00097
00098
00099 if (n & 1)
00100 value= op(value, a);
00101 return value;
00102 }
00103 #endif
00104
00105
00106
00107 template <typename Op, std::Semiregular Element, Integral Exponent>
00108 requires Monoid<Op, Element>
00109 && std::Callable2<Op, Element, Element>
00110 && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
00111 inline Element multiply_and_square(const Element& a, Exponent n, Op op)
00112 {
00113
00114
00115 if (n < 0) throw std::range_error("mult&square: n must be >= 0");
00116
00117 using math::identity;
00118 Element value= bool(n & 1) ? Element(a) : Element(identity(op, a)), square= a;
00119
00120 for (n>>= 1; n > 0; n>>= 1) {
00121 square= op(square, square);
00122 if (n & 1)
00123 value= op(value, square);
00124 }
00125 return value;
00126 }
00127
00128
00129 template <typename Op, std::Semiregular Element, Integral Exponent>
00130 requires Monoid<Op, Element>
00131 && std::Callable2<Op, Element, Element>
00132 && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
00133 inline Element power(const Element& a, Exponent n, Op op)
00134 {
00135 std::cout << "[Monoid] ";
00136 return multiply_and_square(a, n, op);
00137 }
00138
00139
00140
00141
00142 template <typename Op, std::Semiregular Element, Integral Exponent>
00143 requires PIMonoid<Op, Element>
00144 && std::Callable2<Op, Element, Element>
00145 && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
00146 inline Element power(const Element& a, Exponent n, Op op)
00147 {
00148 std::cout << "[PIMonoid] ";
00149 if (n < 0 && !is_invertible(op, a))
00150 throw std::range_error("power [PIMonoid]: a must be invertible with n < 0");
00151
00152 return n < 0 ? multiply_and_square(Element(inverse(op, a)), Exponent(-n), op)
00153 : multiply_and_square(a, n, op);
00154 }
00155
00156 #if 1
00157 template <typename Op, std::Semiregular Element, Integral Exponent>
00158 requires Group<Op, Element>
00159 && std::Callable2<Op, Element, Element>
00160 && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
00161 inline Element power(const Element& a, Exponent n, Op op)
00162 {
00163 std::cout << "[Group] ";
00164
00165
00166 return n < 0 ? multiply_and_square(Element(inverse(op, a)), Exponent(-n), op)
00167 : multiply_and_square(a, n, op);
00168 }
00169 #endif
00170
00171
00172 #if 0
00173 template <typename Op, typename Element, typename Exponent>
00174 requires Group<Op, Element>
00175 && Integral<Exponent>
00176 && std::Semiregular<Element>
00177 && std::Callable2<Op, Element, Element>
00178 && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
00179 && std::Semiregular<math::Inversion<Op, Element>::result_type>
00180 && std::HasNegate<Exponent>
00181 && math::Monoid<Op, math::Inversion<Op, Element>::result_type>
00182 && Integral< std::HasNegate<Exponent>::result_type>
00183 && std::Callable2<Op, math::Inversion<Op, Element>::result_type,
00184 math::Inversion<Op, Element>::result_type>
00185 && std::Convertible<std::Callable2<Op, math::Inversion<Op, Element>::result_type,
00186 math::Inversion<Op, Element>::result_type>::result_type,
00187 math::Inversion<Op, Element>::result_type>
00188 inline Element power(const Element& a, Exponent n, Op op)
00189 {
00190 return n < 0 ? multiply_and_square(inverse(op, a), -n, op)
00191 : multiply_and_square(a, n, op);
00192 }
00193 #endif
00194
00195 }
00196
00197 #endif // MATH_POWER_INCLUDE