Vaucanson 1.4
numerical_semiring.hxx
00001 // numerical_semiring.hxx: this file is part of the Vaucanson project.
00002 //
00003 // Vaucanson, a generic library for finite state machines.
00004 //
00005 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 The Vaucanson Group.
00006 //
00007 // This program is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2
00010 // of the License, or (at your option) any later version.
00011 //
00012 // The complete GNU General Public Licence Notice can be found as the
00013 // `COPYING' file in the root directory.
00014 //
00015 // The Vaucanson Group consists of people listed in the `AUTHORS' file.
00016 //
00017 #ifndef VCSN_ALGEBRA_IMPLEMENTATION_SEMIRING_NUMERICAL_SEMIRING_HXX
00018 # define VCSN_ALGEBRA_IMPLEMENTATION_SEMIRING_NUMERICAL_SEMIRING_HXX
00019 
00020 # include <cmath>
00021 # include <vaucanson/algebra/concept/semiring_base.hh>
00022 # include <vaucanson/algebra/implementation/semiring/numerical_semiring.hh>
00023 
00024 # include <vaucanson/misc/random.hh>
00025 # include <vaucanson/misc/limits.hh>
00026 # include <vaucanson/misc/contract.hh>
00027 
00028 namespace vcsn {
00029 
00030   namespace algebra {
00031 
00032     template<typename T>
00033     bool op_contains(const algebra::NumericalSemiring&, T)
00034     {
00035       return true;
00036     }
00037 
00038     template<typename T, typename U>
00039     void op_in_mul(const algebra::NumericalSemiring&,
00040                    T& dst, U arg)
00041     {
00042       dst *= arg;
00043     }
00044 
00045     template<typename T, typename U>
00046     void op_in_add(const algebra::NumericalSemiring&,
00047                    T& dst, U arg)
00048     {
00049       dst += arg;
00050     }
00051 
00052     // FIXME: there should be specializations of op_add_traits and
00053     // op_mul_traits giving the type of the result depending on the
00054     // type of the arguments.
00055 
00056     template<typename T, typename U>
00057     T op_mul(const algebra::NumericalSemiring&, T a, U b)
00058     {
00059       return a * b;
00060     }
00061 
00062     template<typename T, typename U>
00063     T op_add(const algebra::NumericalSemiring&, T a, U b)
00064     {
00065       return a + b;
00066     }
00067 
00068     template<typename T>
00069     T identity_value(SELECTOR(algebra::NumericalSemiring), SELECTOR(T))
00070     {
00071       return T(1);
00072     }
00073 
00074     template<typename T>
00075     bool show_identity_value(SELECTOR(algebra::NumericalSemiring), SELECTOR(T))
00076     {
00077       return false;
00078     }
00079 
00080     template<typename T>
00081     T zero_value(SELECTOR(algebra::NumericalSemiring), SELECTOR(T))
00082     {
00083       return T(0);
00084     }
00085 
00086     template <class T>
00087     Element<algebra::NumericalSemiring, T>
00088     op_choose(const algebra::NumericalSemiring& set, SELECTOR(T))
00089     {
00090       return
00091         Element<algebra::NumericalSemiring, T>
00092           (set, misc::random::generate<T>());
00093     }
00094 
00095     /*-----------------------------.
00096     | specializations for integers |
00097     `-----------------------------*/
00098 
00099     inline
00100     bool
00101     op_can_choose_non_starable(const algebra::NumericalSemiring&,
00102                                 SELECTOR(int))
00103     {
00104       return true; // Every integer excepted Zero is non-starable
00105     }
00106 
00107     inline
00108     Element<algebra::NumericalSemiring, int>
00109     op_choose_starable(const algebra::NumericalSemiring& set, SELECTOR(int))
00110     {
00111       // 0 is the only one integer to be starable. So we have no choice !
00112       return Element<algebra::NumericalSemiring, int>(set, 0);
00113     }
00114 
00115     inline
00116     Element<algebra::NumericalSemiring, int>
00117     op_choose_non_starable(const algebra::NumericalSemiring& set,
00118                            SELECTOR(int))
00119     {
00120       int r = misc::random::generate<int>();
00121       if (!r)
00122         r = 1;
00123       return Element<algebra::NumericalSemiring, int>(set, r);
00124     }
00125 
00126     /*-----------------------------.
00127     | specializations for Booleans |
00128     `-----------------------------*/
00129     template <typename T>
00130     void op_in_mul(const algebra::NumericalSemiring&, bool& dst, bool src)
00131     {
00132       dst = dst && src;
00133     }
00134 
00135     inline bool op_mul(const algebra::NumericalSemiring&, bool a, bool b)
00136     {
00137       return a && b;
00138     }
00139 
00140     inline void op_in_add(const algebra::NumericalSemiring&,
00141                           bool& dst, bool src)
00142     {
00143       dst = dst || src;
00144     }
00145 
00146     inline bool op_add(const algebra::NumericalSemiring&, bool a, bool b)
00147     {
00148       return a || b;
00149     }
00150 
00151     inline bool identity_value(SELECTOR(algebra::NumericalSemiring),
00152                                SELECTOR(bool))
00153     {
00154       return true;
00155     }
00156 
00157     inline bool zero_value(SELECTOR(algebra::NumericalSemiring),
00158                            SELECTOR(bool))
00159     {
00160       return false;
00161     }
00162 
00163     inline bool op_starable(const algebra::NumericalSemiring&, bool)
00164     {
00165       return true;
00166     }
00167 
00168     inline void op_in_star(const algebra::NumericalSemiring&, bool& b)
00169     {
00170       b = true;
00171     }
00172 
00173     inline
00174     Element<algebra::NumericalSemiring, bool>
00175     op_choose_starable(const algebra::NumericalSemiring& set, SELECTOR(bool))
00176     {
00177       // Every Boolean is starable !
00178       return op_choose(set, SELECT(bool));
00179     }
00180 
00181     inline
00182     Element<algebra::NumericalSemiring, bool>
00183     op_choose_non_starable(const algebra::NumericalSemiring& set,
00184                            SELECTOR(bool))
00185     {
00186       assertion_(false, "Cannot choose non-starable boolean: all boolean are starable.");
00187       return Element<algebra::NumericalSemiring, bool>(set, false);
00188     }
00189 
00190     /*--------------------------------------------.
00191     | specialization for floating point numbers.  |
00192     `--------------------------------------------*/
00193 
00194     inline float op_sub(const algebra::NumericalSemiring&, const float& a, const float& b)
00195     {
00196       return a - b;
00197     }
00198 
00199     inline double op_sub(const algebra::NumericalSemiring&, const double& a, const double& b)
00200     {
00201       return a - b;
00202     }
00203 
00204     inline float op_div(const algebra::NumericalSemiring&, const float& a, const float& b)
00205     {
00206       return a / b;
00207     }
00208 
00209     inline double op_div(const algebra::NumericalSemiring&, const double& a, const double& b)
00210     {
00211       return a / b;
00212     }
00213 
00214     inline bool op_eq(const algebra::NumericalSemiring&, float& a, float& b)
00215     {
00216       return std::abs(a - b) < 0.00001;
00217     }
00218 
00219     inline bool op_eq(const algebra::NumericalSemiring&, double& a, double& b)
00220     {
00221       return std::abs(a - b) < 0.00001;
00222     }
00223 
00224     template<typename T>
00225     bool op_starable(const algebra::NumericalSemiring&, T v)
00226     {
00227       return v == 0;
00228     }
00229 
00230     inline bool op_starable(const algebra::NumericalSemiring&,
00231                              const float& f)
00232     {
00233       return (-1.0 < f) && (f < 1.0);
00234     }
00235 
00236     inline bool op_starable(const algebra::NumericalSemiring&,
00237                              const double& f)
00238     {
00239       return (-1.0 < f) && (f < 1.0);
00240     }
00241 
00242     inline void op_in_star(const algebra::NumericalSemiring&, float& f)
00243     {
00244       static_assertion(misc::limits<float>::has_infinity,
00245                        float_has_infinity);
00246       if (f < 1.0)
00247         f = (1.0 / (1.0 - f));
00248       else
00249         f = misc::limits<float>::infinity();
00250     }
00251 
00252     inline void op_in_star(const algebra::NumericalSemiring&, double& f)
00253     {
00254       if (f < 1.0)
00255         f = (1.0 / (1.0 - f));
00256       else
00257         assertion(! "star not defined.");
00258     }
00259 
00260     inline
00261     bool
00262     op_can_choose_non_starable(const algebra::NumericalSemiring&,
00263                                 SELECTOR(float))
00264     {
00265       return true; // Every float which is less than -1 or greater than 1 is
00266                    // non-starable.
00267     }
00268 
00269     inline
00270     Element<algebra::NumericalSemiring, float>
00271     op_choose_starable(const algebra::NumericalSemiring& set,
00272                        SELECTOR(float))
00273     {
00274       float res = misc::random::generate<float>(-1, 1);
00275 
00276       while (res == -1)
00277         res = misc::random::generate<float>(-1, 1);
00278       return
00279         Element<algebra::NumericalSemiring, float>
00280           (set, res);
00281     }
00282 
00283     inline
00284     Element<algebra::NumericalSemiring, float>
00285     op_choose_non_starable(const algebra::NumericalSemiring& set,
00286                            SELECTOR(float))
00287     {
00288       float res = misc::random::generate<float>() * 1000.;
00289       while (op_starable(set, res))
00290         res = misc::random::generate<float>() * 1000.;
00291       return Element<algebra::NumericalSemiring, float>(set, res);
00292     }
00293 
00294     inline
00295     bool
00296     op_can_choose_non_starable(const algebra::NumericalSemiring&,
00297                                 SELECTOR(double))
00298     {
00299       return true; // Every float which is less than -1 or greater than 1 is
00300                    // non-starable.
00301     }
00302 
00303     inline
00304     Element<algebra::NumericalSemiring, double>
00305     op_choose_starable(const algebra::NumericalSemiring& set,
00306                        SELECTOR(double))
00307     {
00308       double res = misc::random::generate<double>(-1, 1);
00309 
00310       while (res == -1)
00311         res = misc::random::generate<double>(-1, 1);
00312       return
00313         Element<algebra::NumericalSemiring, double>
00314           (set, res);
00315    }
00316 
00317     inline
00318     Element<algebra::NumericalSemiring, double>
00319     op_choose_non_starable(const algebra::NumericalSemiring& set,
00320                            SELECTOR(double))
00321     {
00322       double res = misc::random::generate<double>() * 1000.;
00323       while (op_starable(set, res))
00324         res = misc::random::generate<double>() * 1000.;
00325       return Element<algebra::NumericalSemiring, double>(set, res);
00326     }
00327     // FIXME: add some more operators as syntactic sugar
00328 
00329 
00330     /*------------------------------------.
00331     | specialization for rational numbers |
00332      `------------------------------------*/
00333 
00334 
00335     inline RationalNumber
00336     op_sub(const algebra::NumericalSemiring&, const RationalNumber& a, const RationalNumber& b)
00337     {
00338       return a - b;
00339     }
00340 
00341     inline RationalNumber
00342     op_div(const algebra::NumericalSemiring&, const RationalNumber& a, const RationalNumber& b)
00343     {
00344       return a / b;
00345     }
00346 
00347 
00348     inline algebra::RationalNumber
00349     identity_value(SELECTOR(algebra::NumericalSemiring),
00350                    SELECTOR(algebra::RationalNumber))
00351     {
00352       return algebra::RationalNumber(1);
00353     }
00354 
00355     inline algebra::RationalNumber
00356     zero_value(SELECTOR(algebra::NumericalSemiring),
00357                SELECTOR(algebra::RationalNumber))
00358     {
00359       return algebra::RationalNumber(0);
00360     }
00361 
00362     inline bool
00363     op_starable(const algebra::NumericalSemiring&,
00364                 const algebra::RationalNumber& r)
00365     {
00366       return std::abs(r.num_get()) < r.den_get ();
00367     }
00368 
00369     inline bool
00370     op_starable(const algebra::NumericalSemiring&,
00371                 algebra::RationalNumber& r)
00372     {
00373       return std::abs(r.num_get()) < r.den_get ();
00374     }
00375 
00376     inline void op_in_star(const algebra::NumericalSemiring&,
00377                            algebra::RationalNumber& r)
00378     {
00379       if (std::abs(r.num_get()) < r.den_get ())
00380       {
00381         algebra::RationalNumber one = algebra::RationalNumber(1);
00382         r = one / (one - r);
00383       }
00384       else
00385         assertion(! "vcsn::algebra::RationalNumber: star not defined.");
00386     }
00387 
00388     inline
00389     bool
00390     op_can_choose_non_starable(const algebra::NumericalSemiring&,
00391                                 SELECTOR(algebra::RationalNumber))
00392     {
00393       return true; // Every rational number which is greater than 1 and
00394                    // less than -1 is non-starable
00395     }
00396 
00397     inline
00398     Element<algebra::NumericalSemiring, algebra::RationalNumber>
00399     op_choose_starable(const algebra::NumericalSemiring& set,
00400                        SELECTOR(algebra::RationalNumber))
00401     {
00402       algebra::RationalNumber min = algebra::RationalNumber(-1, 1);
00403       algebra::RationalNumber max = algebra::RationalNumber(1, 1);
00404       return
00405         Element<algebra::NumericalSemiring, algebra::RationalNumber>
00406         (set, misc::random::generate<algebra::RationalNumber>(min, max));
00407    }
00408 
00409     inline
00410     Element<algebra::NumericalSemiring, algebra::RationalNumber>
00411     op_choose_non_starable(const algebra::NumericalSemiring& set,
00412                            SELECTOR(algebra::RationalNumber))
00413     {
00414       algebra::RationalNumber res;
00415       do
00416         {
00417           res = misc::random::generate<algebra::RationalNumber> ();
00418         }
00419       while (res.den_get () >= std::abs(res.num_get ()));
00420       return Element<algebra::NumericalSemiring, algebra::RationalNumber> (set, res);
00421     }
00422 
00423   } // algebra
00424 
00425 } // vcsn
00426 
00427 #endif // ! VCSN_ALGEBRA_IMPLEMENTATION_SEMIRING_NUMERICAL_SEMIRING_HXX