OKlibrary  0.2.1.6
NumberTheory_Models.hpp
Go to the documentation of this file.
00001 // Oliver Kullmann, 6.11.2004 (Swansea)
00002 /* Copyright 2004 - 2007 Oliver Kullmann
00003 This file is part of the OKlibrary. OKlibrary is free software; you can redistribute
00004 it and/or modify it under the terms of the GNU General Public License as published by
00005 the Free Software Foundation and included in this library; either version 3 of the
00006 License, or any later version. */
00007 
00014 #ifndef NUMBERTHEORYMODELS_66hdhsb2
00015 #define NUMBERTHEORYMODELS_66hdhsb2
00016 
00017 #include <functional>
00018 #include <algorithm>
00019 #include <ostream>
00020 #include <string>
00021 #include <cassert>
00022 
00023 #include <OKlib/General/Algebra_Traits.hpp>
00024 
00025 namespace NumberTheory {
00026 
00027   // ######################################################
00028 
00029   // Euclidian algorithm
00030 
00031   template <typename Int>
00032   struct GcdVisitor_empty {
00033     void operator() (const Int&) {}
00034     void finished() {}
00035   };
00036   template <typename Int>
00037   struct GcdVisitor_output {
00038     std::ostream& out;
00039     const std::string sep;
00040     GcdVisitor_output(std::ostream& out, const std::string& sep = ",") : out(out), sep(sep) {}
00041     void operator() (const Int& x) {
00042       out << x << sep;
00043     }
00044     void finished() {
00045       out << 0;
00046     }
00047   };
00048 
00049   template <typename Int, class Visitor = GcdVisitor_empty<Int> >
00050   struct Gcd : std::binary_function<Int, Int, Int> {
00051     typedef Int int_type;
00052     Visitor vis;
00053     Gcd() {}
00054     Gcd(Visitor vis) : vis(vis) {}
00055     int_type operator() (int_type a, int_type b) {
00056       vis(a);
00057       while (b != int_type(0)) {
00058         vis(b);
00059         a %= b;
00060         using std::swap;
00061         swap(a,b);
00062       }
00063       vis.finished();
00064       return a;
00065     }
00066   };
00067 
00068   template <typename Int>
00069   inline Int gcd(const Int a, const Int b) {
00070     return Gcd<Int>()(a, b);
00071   }
00072 
00073   // ######################
00074 
00075   // Extended Euclidian algorithm
00076 
00077   template <typename Int>
00078   struct GcdExtVisitor_empty {
00079     void operator() (const Int&) {}
00080     void coefficients(const Int&, const Int&) {}
00081     void last_coefficients(const Int&, const Int&) {}
00082     void finished() {}
00083   };
00084   template <typename Int>
00085   struct GcdExtVisitor_output {
00086     std::ostream& out_euc_seq;
00087     std::ostream& out_euc_ext_seq;
00088     const std::string sep;
00089     GcdExtVisitor_output(std::ostream& out1, std::ostream& out2, const std::string& sep = ",") : out_euc_seq(out1), out_euc_ext_seq(out2), sep(sep) {}
00090     void operator() (const Int& a) {
00091       out_euc_seq << a << sep;
00092     }
00093     void coefficients(const Int& x, const Int& y) {
00094       out_euc_ext_seq << "(" << x << "," << y << ")" << sep;
00095     }
00096     void last_coefficients(const Int& x, const Int& y) {
00097       out_euc_ext_seq << "(" << x << "," << y << ")";
00098     }
00099     void finished() {
00100       out_euc_seq << 0;
00101     }
00102   };
00103 
00104   template <typename Int, class Visitor = GcdExtVisitor_empty<Int> >
00105   struct Gcd_extended : std::binary_function<Int, Int, Algebra_Traits::BinaryLinearCombination<Int, Int> > {
00106 
00107     typedef Int int_type;
00108     typedef typename std::binary_function<int_type,int_type,Algebra_Traits::BinaryLinearCombination<int_type, int_type> >::result_type result_type;
00109 
00110     Visitor vis;
00111 
00112     Gcd_extended() {}
00113     Gcd_extended(Visitor vis) : vis(vis) {}
00114 
00115     result_type operator() (const int_type a, const int_type b) {
00116       // TO IMPROVE: Using a fixed size vector class
00117       int_type a0(a), a1(b);
00118       vis(a0);
00119       int_type x0(int_type(1)), y0(int_type(0)), x1(int_type(0)), y1(int_type(1));
00120       vis.coefficients(x0, y0);
00121       assert(a0 == x0 * a + y0 * b);
00122       assert(a1 == x1 * a + y1 * b);
00123       while (a1 != int_type(0)) {
00124         vis(a1);
00125         const int_type div = a0 / a1;
00126         using std::swap;
00127         x0 = x0 - div * x1; y0 = y0 - div * y1;
00128         swap(x0, x1); swap(y0, y1);
00129         vis.coefficients(x0, y0);
00130         a0 -= div * a1;
00131         swap(a0, a1);
00132         assert(a0 == x0 * a + y0 * b);
00133         assert(a1 == x1 * a + y1 * b);
00134       }
00135       vis.last_coefficients(x1, y1);
00136       vis.finished();
00137       return result_type(x0, y0, a, b, a0);
00138     }
00139   };
00140 
00141   template <typename Int>
00142   inline Algebra_Traits::BinaryLinearCombination<Int, Int> gcd_extended(const Int a, const Int b) {
00143     return Gcd_extended<Int>()(a, b);
00144   }
00145 
00146   // ######################################################
00147 
00148   // Euler's phi function
00149   template <typename Int>
00150   struct Euler_phi_brute_force : std::unary_function<Int, Int> {
00151     Int operator() (const Int n) const {
00152       assert(n >= 0);
00153       if (n == Int(0)) return Int(0);
00154       Int counter(Int(0));
00155       for (Int i = 2; i < n; ++i)
00156   if (gcd(i, n) == Int(1)) ++counter;
00157       return counter + Int(1);
00158     }
00159   };
00160   template <typename Int>
00161   inline Int euler_phi_brute_force(const Int n) {
00162     return Euler_phi_brute_force<Int>()(n);
00163   }
00164 }
00165 
00166 #endif