stator
A math, geometry, and utility library
print.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2017 Marcus N Campbell Bannerman <[email protected]>
3 
4  This file is part of stator.
5 
6  stator is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  stator is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with stator. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #pragma once
21 
22 namespace stator {
23  template<class Config = DefaultReprConfig, std::intmax_t Num, std::intmax_t Denom>
24  inline std::string repr(const sym::C<Num, Denom>)
25  {
26  if (Config::Debug_output)
27  return "C<" + repr(Num) + ((Denom!=1) ? (std::string(", ") + repr(Denom) + ">") : std::string(">"));
28  else
29  return (Denom!=1) ? ("("+repr(Num)+"/"+repr(Denom)+")") : repr(Num);
30 
31  }
32 
33  template<class Config = DefaultReprConfig, class ...Args>
34  inline std::string repr(const sym::Var<Args...>& v) {
35  return std::string(1, v.getidx());
36  }
37 
38  template<class Config = DefaultReprConfig, class Var, class Arg>
39  inline std::string repr(const sym::Relation<Var, Arg>& sub) {
40  return repr<Config>(sub._var) << "=" << repr<Config>(sub._val);
41  }
42 
43  template<class Config = DefaultReprConfig, class Arg>
44  inline std::string repr(const sym::UnaryOp<Arg, sym::detail::Sine>& f)
45  {
46  return std::string((Config::Latex_output) ? "\\sin\\left(" : "sin(")
47  + repr<Config>(f._arg)
48  + std::string((Config::Latex_output) ? "\\right)" : ")")
49  ;
50  }
51 
52  template<class Config = DefaultReprConfig, class Arg>
53  inline std::string repr(const sym::UnaryOp<Arg, sym::detail::Cosine>& f)
54  {
55  return std::string((Config::Latex_output) ? "\\cos\\left(" : "cos(")
56  + repr<Config>(f._arg)
57  + std::string((Config::Latex_output) ? "\\right)" : ")")
58  ;
59  }
60 
61  template<class Config = DefaultReprConfig, class Arg>
62  inline std::string repr(const sym::UnaryOp<Arg, sym::detail::Exp>& f)
63  {
64  return
65  std::string((Config::Latex_output) ? "\\mathrm{e}^{" : "exp(")
66  + repr<Config>(f._arg)
67  + std::string((Config::Latex_output) ? "}" : ")")
68  ;
69  }
70 
71  template<class Config = DefaultReprConfig, class Arg>
72  inline std::string repr(const sym::UnaryOp<Arg, sym::detail::Log>& f)
73  {
74  return
75  std::string((Config::Latex_output) ? "\\ln\\left(" : "ln(")
76  + repr<Config>(f._arg)
77  + std::string((Config::Latex_output) ? "\\right)" : ")")
78  ;
79  }
80 
81  template<class Config = DefaultReprConfig, class Arg>
82  inline std::string repr(const sym::UnaryOp<Arg, sym::detail::Absolute>& f)
83  {
84  return
85  std::string((Config::Latex_output) ? "\\left|" : "|")
86  + repr<Config>(f._arg)
87  + std::string((Config::Latex_output) ? "\\right|" : "|")
88  ;
89  }
90 
91  template<class Config = DefaultReprConfig, class Arg>
92  inline std::string repr(const sym::UnaryOp<Arg, sym::detail::Arbsign>& f)
93  {
94  return
95  std::string((Config::Latex_output) ? "\\pm\\left|" : "|")
96  + repr<Config>(f._arg)
97  + std::string((Config::Latex_output) ? "\\right|" : "|")
98  ;
99  }
100 
101  template<class Config = DefaultReprConfig, class T, typename = typename std::enable_if<std::is_base_of<Eigen::EigenBase<T>, T>::value>::type>
102  std::string repr(const T& val) {
103  std::ostringstream os;
104  if ((val.cols() == 1) && (val.rows()==1))
105  os << repr<Config>(val(0,0));
106  else if (val.cols() == 1) {
107  os << "{ ";
108  for (int i(0); i < val.rows(); ++i)
109  os << repr<Config>(val(i, 0)) << " ";
110  os << "}^T";
111  } else {
112  os << "{ ";
113  for (int i(0); i < val.cols(); ++i) {
114  os << "{ ";
115  for (int j(0); j < val.rows(); ++j)
116  os << repr<Config>(val(i, j)) << " ";
117  os << "} ";
118  }
119  os << "}";
120  }
121  return os.str();
122  }
123 
129  template<class Config = DefaultReprConfig, class Coeff_t, size_t N, class PolyVar>
130  inline std::string repr(const sym::Polynomial<N, Coeff_t, PolyVar>& poly) {
131  std::ostringstream oss;
132  size_t terms = 0;
133  oss << "P(";
134  for (size_t i(N); i != 0; --i) {
135  if (poly[i] == sym::empty_sum(poly[i])) continue;
136  if (terms != 0)
137  oss << " + ";
138  ++terms;
139  oss << repr<Config>(poly[i]) << "*" << PolyVar::idx;
140  if (i > 1)
141  oss << "^" << i;
142  }
143  if ((poly[0] != sym::empty_sum(poly[0])) || (terms == 0)) {
144  if (terms != 0)
145  oss << " + ";
146  ++terms;
147  oss << repr<Config>(poly[0]);
148  }
149  oss << ")";
150  return oss.str();
151  }
155  namespace detail {
162  template<class T>
163  std::pair<int, int> BP (const T& v)
164  { return std::make_pair(std::numeric_limits<int>::max(), std::numeric_limits<int>::max()); }
165 
169  template<class LHS, class Op, class RHS>
170  std::pair<int, int> BP (const sym::BinaryOp<LHS, Op, RHS>& v) {
171  const int L = Op::leftBindingPower;
172  const int R = sym::detail::RBP<Op>();
173  return std::make_pair(L, R);
174  }
175 
177  struct BPVisitor : public sym::detail::VisitorHelper<BPVisitor> {
178 
179  template<class T> sym::Expr apply(const T& rhs) { return sym::Expr(); }
180 
182  LBP = Op::leftBindingPower;
183  RBP = sym::detail::RBP<Op>();
184  return sym::Expr();
185  }
186 
187  int LBP = std::numeric_limits<int>::max();
188  int RBP = std::numeric_limits<int>::max();
189  };
190 
194  std::pair<int, int> BP (const sym::Expr& v) {
195  BPVisitor vis;
196  v->visit(vis);
197  return std::make_pair(vis.LBP, vis.RBP);
198  }
199 
200  template<class Config>
201  std::string paren_wrap(std::string arg) {
202  return ((Config::Latex_output) ? "\\left(" : "(") + arg + ((Config::Latex_output) ? "\\right)" : ")");
203  }
204  }
205 
206  template<class Config = DefaultReprConfig, class LHS, class RHS, class Op>
207  inline std::string repr(const sym::BinaryOp<LHS, Op, RHS>& op) {
208  const auto this_BP = detail::BP(op);
209  const auto LHS_BP = detail::BP(op._l);
210  const auto RHS_BP = detail::BP(op._r);
211 
212  std::string LHS_repr = repr<Config>(op._l);
213  if (LHS_BP.second < this_BP.first) LHS_repr = detail::paren_wrap<Config>(LHS_repr);
214 
215  std::string RHS_repr = repr<Config>(op._r);
216  if (this_BP.second > RHS_BP.first) RHS_repr = detail::paren_wrap<Config>(RHS_repr);
217 
218  return LHS_repr + Op::repr() + RHS_repr;
219  }
220 
221  template<class Config = DefaultReprConfig, class LHS, class RHS>
222  inline std::string repr(const sym::BinaryOp<LHS, sym::detail::Power, RHS>& op) {
223  const auto this_BP = detail::BP(op);
224  const auto LHS_BP = detail::BP(op._l);
225  const auto RHS_BP = detail::BP(op._r);
226 
227  std::string LHS_repr = repr<Config>(op._l);
228  if (LHS_BP.second < this_BP.first) LHS_repr = detail::paren_wrap<Config>(LHS_repr);
229 
230  std::string RHS_repr = repr<Config>(op._r);
231  if (!Config::Latex_output) {
232  if (this_BP.second > RHS_BP.first) RHS_repr = detail::paren_wrap<Config>(RHS_repr);
233  } else {
234  RHS_repr = "{" + RHS_repr + "}";
235  }
236 
237  return LHS_repr + sym::detail::Power::repr() + RHS_repr;
238  }
239 
240  template<class Config = DefaultReprConfig, class LHS, class RHS>
241  inline std::string repr(const sym::BinaryOp<LHS, sym::detail::Divide, RHS>& op) {
242  const auto this_BP = detail::BP(op);
243  const auto LHS_BP = detail::BP(op._l);
244  const auto RHS_BP = detail::BP(op._r);
245 
246  std::string LHS_repr = repr<Config>(op._l);
247  std::string RHS_repr = repr<Config>(op._r);
248 
249  if (!Config::Latex_output) {
250  if (LHS_BP.second < this_BP.first) LHS_repr = detail::paren_wrap<Config>(LHS_repr);
251  if (this_BP.second > RHS_BP.first) RHS_repr = detail::paren_wrap<Config>(RHS_repr);
252  return LHS_repr + sym::detail::Divide::repr() + RHS_repr;
253  } else {
254  return "\\frac{" + LHS_repr + "}{" + RHS_repr + "}";
255  }
256  }
257 
258  template<class Config = DefaultReprConfig, class LHS, class RHS>
259  inline std::string repr(const sym::BinaryOp<LHS, sym::detail::Multiply, RHS>& op) {
260  const auto this_BP = detail::BP(op);
261  const auto LHS_BP = detail::BP(op._l);
262  const auto RHS_BP = detail::BP(op._r);
263 
264  std::string LHS_repr = repr<Config>(op._l);
265  std::string RHS_repr = repr<Config>(op._r);
266 
267  if (LHS_BP.second < this_BP.first) LHS_repr = detail::paren_wrap<Config>(LHS_repr);
268  if (this_BP.second > RHS_BP.first) RHS_repr = detail::paren_wrap<Config>(RHS_repr);
269 
270  if (!Config::Latex_output) {
271  return LHS_repr + sym::detail::Multiply::repr() + RHS_repr;
272  } else {
273  if (sym::is_constant(op._l) && sym::is_constant(op._r))
274  return LHS_repr + "\\times " + RHS_repr;
275  else
276  return LHS_repr + "\\," + RHS_repr;
277  }
278  }
279 
280  namespace detail {
281  template<class Config>
282  struct ReprVisitor : public sym::detail::VisitorHelper<ReprVisitor<Config> > {
283  template<class T> sym::Expr apply(const T& rhs) {
284  _repr = repr<Config>(rhs);
285  return sym::Expr();
286  }
287 
288  std::string _repr;
289  };
290  }
291 
292  template<class Config>
293  std::string repr(const sym::RTBase& b) {
295  b.visit(visitor);
296  return visitor._repr;
297  }
298 
299  template<class Config>
300  std::string repr(const sym::Expr& b) {
301  return repr<Config>(*b);
302  }
303 }
304 
305 namespace sym {
306  template<class T, typename = typename std::enable_if<sym::IsSymbolic<T>::value>::type>
307  std::ostream& operator<<(std::ostream& os, const T& v) {
308  return os << stator::repr(v);
309  }
310 }
const Arg & _val
Definition: symbolic.hpp:80
A CRTP helper base class which transforms the visitor interface into a call to the derived classes ap...
Definition: runtime.hpp:135
bool is_constant(const Expr &a)
Definition: runtime.hpp:651
Symbolic representation of a variable.
Definition: symbolic.hpp:94
auto N(const T &a) -> STATOR_AUTORETURN(simplify< NConfig >(a))
A variant of simplify that converts compile time symbols into numbers.
virtual Expr visit(detail::VisitorInterface &c) const =0
ReprConfig<> DefaultReprConfig
Definition: repr.hpp:107
Abstract interface class for all runtime symbolic classes.
Definition: runtime.hpp:171
std::enable_if< std::is_integral< T >::value, std::string >::type repr(T a)
Definition: repr.hpp:111
sym::Expr apply(const T &rhs)
Definition: print.hpp:283
A class representing a compile-time rational constant (i.e., std::ratio).
Definition: constants.hpp:31
std::string repr(const sym::Expr &b)
Definition: print.hpp:300
Symbolic representation of a binary symbolic operation.
Definition: binary_ops.hpp:33
static std::string repr()
Definition: binary_ops.hpp:145
char getidx() const
Definition: symbolic.hpp:102
static std::string repr()
Definition: binary_ops.hpp:158
Symbolic representation of a variable substitution.
Definition: symbolic.hpp:76
The generic holder/smart pointer for a runtime Abstract Syntax Tree (AST) (expression).
Definition: runtime.hpp:68
The stator symbolic math library.
T empty_sum(const T &)
Returns the empty sum of a type.
Definition: symbolic.hpp:153
sym::Expr apply(const T &rhs)
Definition: print.hpp:179
Binding power visitor for sym::detail::BP(const Expr&).
Definition: print.hpp:177
std::ostream & operator<<(std::ostream &os, const T &v)
Definition: print.hpp:307
const RHS _r
Definition: binary_ops.hpp:35
static std::string repr()
Definition: binary_ops.hpp:167
auto sub(BinaryOp< LHS, Op, RHS > f, Relation< Var, Arg > x) -> STATOR_AUTORETURN_BYVALUE(Op::apply(sub(f._l, x), sub(f._r, x)))
const LHS _l
Definition: binary_ops.hpp:34
The stator library namespace.
Definition: frontpage.dox:243
const Var _var
Definition: symbolic.hpp:79
sym::Expr apply(const sym::BinaryOp< sym::Expr, Op, sym::Expr > &op)
Definition: print.hpp:181
Symbolic representation of a unary operator (i.e., sin(x)).
Definition: unary_ops.hpp:30
std::pair< int, int > BP(const T &v)
Returns the binding powers (precedence) of binary operators.
Definition: print.hpp:163
std::string paren_wrap(std::string arg)
Definition: print.hpp:201
Array representation of Polynomial.
Definition: polynomial.hpp:63