Fleet  0.0.9
Inference in the LOT
Polynomial.h
Go to the documentation of this file.
1 #pragma once
2 
3 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 // Compute polynomial degrees
5 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 
7 #include <vector>
8 
9 /* This class stores the degree of a polynomial and a bool that indicates whether
10  * its a degree or a constant (which is somemtimes used in computing the degree). When
11  * we end up with a non-polynomial, we return NaN */
12 
13 // TODO: We could rewrite this to define two subclasses of polynomial degrees (constants and powers)
14 // and then define arithmetic on them...
15 
16 class Polydeg {
17 public:
18  double value; //
19  bool is_const; //if true, value is a constant, otherwise it is an exponent on x
20  Polydeg(double v, bool b) : value(v), is_const(b) {
21  }
22  bool isnan() { return std::isnan(value); }
23 };
24 
25 
26 Polydeg get_polynomial_degree_rec(const Node& n, const std::vector<Constant>& constants, size_t cidx) {
27 
28  const std::string fmt = n.rule->format;
29 
30  if(fmt == "%s") { // single arguments we just pass through
31  assert(n.nchildren() == 1);
32  return get_polynomial_degree_rec(n.child(0), constants, cidx);
33  }
34  else if(fmt == "(%s+%s)") {
35  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
36  Polydeg v2 = get_polynomial_degree_rec(n.child(1), constants, cidx);
37  if(v1.isnan() or v2.isnan()) return Polydeg(NaN,false); // doesn't matter whether its const or not
38  else if(v1.is_const && v2.is_const) return Polydeg(v1.value+v2.value, true); // if both consts, then return their value
39  else if (v1.is_const) return v2; // we can't let cosntants/nans interfere here
40  else if (v2.is_const) return v1;
41  else return Polydeg(std::max(v1.value,v2.value), false);
42  }
43  else if(fmt == "(%s-%s)") {
44  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
45  Polydeg v2 = get_polynomial_degree_rec(n.child(1), constants, cidx);
46  if(v1.isnan() or v2.isnan()) return Polydeg(NaN,false);
47  else if(v1.is_const && v2.is_const) return Polydeg(v1.value-v2.value, true); // if both consts, then return their value
48  else if (v1.is_const) return v2;
49  else if (v2.is_const) return v1;
50  else return Polydeg(std::max(v1.value,v2.value), false);
51  }
52  else if(fmt == "(%s*%s)") {
53  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
54  Polydeg v2 = get_polynomial_degree_rec(n.child(1), constants, cidx);
55  if(v1.isnan() or v2.isnan()) return Polydeg(NaN,false);
56  else if(v1.is_const && v2.is_const) return Polydeg(v1.value*v2.value,true); // if boths consts, then return their value
57  else if(v1.is_const) return v2; // otherwise we ignore constants
58  else if(v2.is_const) return v1;
59  else return Polydeg(v1.value+v2.value,false); // both are powers so they add
60  }
61  else if(fmt == "(%s/%s)") {
62  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
63  Polydeg v2 = get_polynomial_degree_rec(n.child(1), constants, cidx);
64  if(v1.isnan() or v2.isnan()) return Polydeg(NaN,false);
65  else if(v1.is_const && v2.is_const) return Polydeg(v1.value/v2.value,true); // if boths consts, then return their value
66  else if(v1.is_const) return Polydeg(NaN, false); // negative powers not allowed -- since otherwise things like x/(1+x) are counted as polynomials
67  else if(v2.is_const) return v1; // v1 is an exponent, constant doesn't matter
68  return Polydeg(NaN,true);
69  }
70  else if(fmt == "(%s^%s)" or fmt == "pow_abs(%s,%s)") { // either format allowed
71  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
72  Polydeg v2 = get_polynomial_degree_rec(n.child(1), constants, cidx);
73  if(v1.isnan() or v2.isnan()) return Polydeg(NaN,false);
74  else if(v1.is_const && v2.is_const) return Polydeg(pow(std::abs(v1.value),v2.value),true); // if both constants, take their power
75  else if(v1.is_const) return Polydeg(NaN,false); // 2.3 ^ x -- not a polynomial
76  else if(v2.is_const) return Polydeg(std::abs(v1.value)*v2.value,false); // x^{2.3} -- is a polynomial, so multiply the exponents
77  return Polydeg(NaN,false); // both are exponents but not a polynomial so forget it
78  }
79  else if(fmt == "(-%s)") {
80  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
81  if(v1.isnan()) return Polydeg(NaN,false);
82  else if(v1.is_const) return Polydeg(-v1.value, true);
83  else return v1;
84  }
85  else if(fmt == "x" or
86  (fmt[0] == '%' and fmt[1]=='s' and fmt.size()<=4) or
87  (fmt[0] == 'x' and fmt.size() == 2)) { // x or %s1 %s2, %s3, etc
88  return Polydeg(1.0, false);
89  }
90  else if(fmt == "C") {
91  return Polydeg(constants.at(cidx++).get_value(), true);
92  }
93  else if(fmt == "1") {
94  return Polydeg(1.0, true);
95  }
96  else if(fmt == "2") {
97  return Polydeg(2.0, true);
98  }
99  else if(fmt == "3") {
100  return Polydeg(3.0, true);
101  }
102  else if(fmt == "0.5") {
103  return Polydeg(0.5, true);
104  }
105  else if(fmt == "pi") {
106  return Polydeg(M_PI, true);
107  }
108  else if(fmt == "tau") {
109  return Polydeg(2*M_PI, true);
110  }
111  else if(fmt == "log(%s)") {
112  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
113  if(v1.isnan()) return Polydeg(NaN,false);
114  else if(v1.is_const) return Polydeg(log(v1.value), true); // handles cases like x^exp(3)
115  else return Polydeg(NaN,false);
116  }
117  else if(fmt == "exp(%s)") {
118  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
119  if(v1.isnan()) return Polydeg(NaN,false);
120  else if(v1.is_const) return Polydeg(exp(v1.value), true);
121  else return Polydeg(NaN,false);
122  }
123  else if(fmt == "expm(%s)") {
124  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
125  if(v1.isnan()) return Polydeg(NaN,false);
126  else if(v1.is_const) return Polydeg(exp(-v1.value), true);
127  else return Polydeg(NaN,false);
128  }
129  else if(fmt == "asin(%s)") {
130  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
131  if(v1.isnan()) return Polydeg(NaN,false);
132  else if(v1.is_const) return Polydeg(asin(v1.value), true);
133  else return Polydeg(NaN,false);
134  }
135  else if(fmt == "sin(%s)") {
136  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
137  if(v1.isnan()) return Polydeg(NaN,false);
138  else if(v1.is_const) return Polydeg(sin(v1.value), true);
139  else return Polydeg(NaN,false);
140  }
141  else if(fmt == "cos(%s)") {
142  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
143  if(v1.isnan()) return Polydeg(NaN,false);
144  else if(v1.is_const) return Polydeg(cos(v1.value), true);
145  else return Polydeg(NaN,false);
146  }
147  else if(fmt == "sq(%s)") {
148  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
149  if(v1.isnan()) return Polydeg(NaN,false);
150  else if(v1.is_const) return Polydeg(v1.value*v1.value, true);
151  else return Polydeg(2*v1.value, false);
152  }
153  else if(fmt == "sqrt_abs(%s)") {
154  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
155  if(v1.isnan()) return Polydeg(NaN,false);
156  else if(v1.is_const) return Polydeg(std::sqrt(std::abs(v1.value)), true);
157  else return Polydeg(0.5*std::abs(v1.value), false);
158  }
159  else if(fmt == "pow_abs(%s,2)") {
160  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
161  if(v1.isnan()) return Polydeg(NaN,false);
162  else if(v1.is_const) return Polydeg(powf(std::abs(v1.value),2), true);
163  else return Polydeg(2*std::abs(v1.value), false);
164  }
165  else if(fmt == "pow_abs(%s,3)") {
166  Polydeg v1 = get_polynomial_degree_rec(n.child(0), constants, cidx);
167  if(v1.isnan()) return Polydeg(NaN,false);
168  else if(v1.is_const) return Polydeg(powf(std::abs(v1.value),3), true);
169  else return Polydeg(3*std::abs(v1.value), false);
170  }
171  else {
172  print("In format string: ", fmt);
173  assert(false && "*** Unmatched format string by polynomial. Did you change the primitives and not update this?");
174  }
175 }
176 
177 double get_polynomial_degree(const Node& n, const std::vector<Constant>& constants) {
178  size_t cidx = 0;
179  Polydeg r = get_polynomial_degree_rec(n, constants, cidx);
180  if(r.isnan()) return NaN;
181  else return (r.is_const ? 0.0 : r.value);
182 }
Definition: Node.h:22
Polydeg(double v, bool b)
Definition: Polynomial.h:20
double get_polynomial_degree(const Node &n, const std::vector< Constant > &constants)
Definition: Polynomial.h:177
bool isnan()
Definition: Polynomial.h:22
double value
Definition: Polynomial.h:18
void print(FIRST f, ARGS... args)
Lock output_lock and print to std:cout.
Definition: IO.h:53
std::string format
Definition: Rule.h:28
this_t & child(const size_t i)
Definition: BaseNode.h:175
const Rule * rule
Definition: Node.h:32
Polydeg get_polynomial_degree_rec(const Node &n, const std::vector< Constant > &constants, size_t cidx)
Definition: Polynomial.h:26
constexpr double NaN
Definition: Numerics.h:21
Definition: Polynomial.h:16
bool is_const
Definition: Polynomial.h:19
size_t nchildren() const
Definition: BaseNode.h:208