summaryrefslogtreecommitdiff
path: root/utils/semiring.h
blob: 5007994c82b204076e6263e36a79acf9d3d2840b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#ifndef SEMIRING_H
#define SEMIRING_H

struct init_1 {  };
struct init_0 {  };
struct init_minus_1 { };
struct init_lnx {  };

#undef LOGVAL_LOG0
#define LOGVAL_LOG0 -std::numeric_limits<T>::infinity()

/* if T is a semiring,

   then constructors:
   T() := T(init_0)
   T(init_0()) := semiring 0
   T(init_1()) := semiring 1
   (copy constructor, equality, assignment also)
   T(other initializers) - semiring dependent e.g. T(double lnx,bool is_negative); T(double lnx,init_lnx); T(double x) := T(log(fabs(x)),signbit(x))

   optional: T(init_minus_1()) := -1, assuming additive inverse

   if T a,b;
   then a+b := semiring + - commutative monoid with 0
   a*b := semiring * with identity 1 - monoid with 1
   * distributes over +
   0*a=a*0=0

   also a+= a*=

   optional: commutative multiplication (commutative semiring)

   non-semiring concepts you may also have:
   order (a<b)
   logplus(a,b), logpluseq(a,b), T::exp(lnx), log(a)
   a-b, usually with a-b := a+T(init_minus_1())*b
   a.inverse() : a*a.inverse() = 1
   a.left_inverse() : a.left_inverse()*a = 1 (define if not commuatative and it exists)
   signbit(a) := a<0
   pow(a,2) := a*a
   pow(a,2.3)
*/

template <class T>
struct default_semiring_traits {
  static const T One;
  static const T Zero;
  static inline bool is_1(T const& x) { return x==One; }
  static inline bool is_0(T const& x) { return x==Zero; }
  static const bool commutative=true;
  static const bool has_inverse=true; // multiplicative, that is
//  static const bool has_left_inverse=false; // note: not intended to imply that inverse isn't a left_inverse
  static const bool has_order=false; // we usually don't defined < > <= >= although == != must exist
  static const bool has_ltgt=true; // but we will probably give a a.lt(b) x.gt(y) which are a<b and x>y resp.
  static const bool has_subtract=false; // e.g. tropical can't do this
  static const bool has_logplus=false;
  static const bool has_pow=true;
  static const bool has_init_float=true; // implies you can T a; T a.as_float() as well as T(float f)
  static const bool has_negative=false;
  static const bool has_ostream=false; // we could provide these but for some reason we usually don't
  static const bool has_istream=false;
};

template <class T>
struct semiring_traits : default_semiring_traits<T> {
};


template <class T>
const T default_semiring_traits<T>::One=init_1();
template <class T>
const T default_semiring_traits<T>::Zero=init_0();

#endif