stator
A math, geometry, and utility library
simplify.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 sym {
24  //
25  // Rules of the game:
26  //
27  // (1) A simplfy implementation is only available if there is a
28  // simplification! This is required to ensure recursive
29  // simplification terminates.
30  //
31  // (2) Cancellation is the highest priority to keep the AST as
32  // small as possible.
33  //
34  // (3) Adding new rules is difficult, some simplify rules are
35  // recursive, thus you must avoid infinite recursion AND ambiguity.
36  //
37  // (4) ...?
38 
40  namespace detail {
41  struct expand_to_Polynomial_ID;
42  struct expand_Constants_ID;
43  struct expand_Constants_to_ID;
44  };
45 
46  struct expand_to_Polynomial : stator::orphan::basic_conf_t<detail::expand_to_Polynomial_ID> {};
47 
48  struct expand_Constants : stator::orphan::basic_conf_t<detail::expand_Constants_ID> {};
49  template<typename T>
50  struct expand_Constants_to : stator::orphan::type_conf_t<detail::expand_Constants_to_ID, T> {};
51 
52  template <typename ...Args>
53  struct SimplifyConfig {
54  static constexpr const auto expand_to_Polynomial = stator::orphan::is_present<sym::expand_to_Polynomial, Args...>::value;
55  static constexpr const auto expand_Constants = stator::orphan::is_present<sym::expand_Constants, Args...>::value;
57  };
58 
60 
61 
63 
68  template<class Config = DefaultSimplifyConfig> void simplify();
69 
70  namespace detail {
71  template<class Config, class T>
72  auto try_simplify_imp(const T& a, detail::choice<0>) -> STATOR_AUTORETURN(simplify<Config>(a));
73 
74  template<class Config, class T>
76  return a;
77  }
78  }
79 
83  template<class Config = DefaultSimplifyConfig, class T>
84  auto try_simplify(const T& a) -> decltype(detail::try_simplify_imp<Config>(a, detail::select_overload{})) {
85  return detail::try_simplify_imp<Config>(a, detail::select_overload{});
86  }
87 
90  > ExpandConfig;
91 
95  template<class T> auto expand(const T& a)
96  -> STATOR_AUTORETURN(simplify<ExpandConfig>(a));
97 
101  template<class T> auto try_expand(const T& a)
102  -> STATOR_AUTORETURN(try_simplify<ExpandConfig>(a));
103 
105 
109  template<class T> auto N(const T& a)
110  -> STATOR_AUTORETURN(simplify<NConfig>(a));
111 
115  template<class T> auto try_N(const T& a)
116  -> STATOR_AUTORETURN(try_simplify<NConfig>(a));
117 
119  //
120  // Here we perform different simplifications with different
121  // priority. We must attempt to prune the expression tree as fast
122  // as possible to minimise template depth. Then we try
123  // permutations.
124 
125  // Prune expressions which do not require the BinaryOp framework
126  // as their are higher precedent operator implementations// .
127  template<class Config, class LHS, class RHS, class Op>
129  -> typename std::enable_if<!std::is_same<decltype(Op::apply(f._l, f._r)), BinaryOp<LHS, Op, RHS> >::value, decltype(Op::apply(f._l, f._r))>::type
130  { return Op::apply(f._l, f._r); };
131 
132  // Convert any zero operations into the zero
133  template<class Config, class LHS, class RHS, class Op,
134  typename = typename std::enable_if<std::is_same<RHS, typename Op::right_zero>::value >::type>
135  typename Op::right_zero simplify_BinaryOp(const BinaryOp<LHS, Op, RHS>&, detail::choice<0>) { return {}; };
136 
137  template<class Config, class LHS, class RHS, class Op,
138  typename = typename std::enable_if<std::is_same<LHS, typename Op::left_zero>::value && !std::is_same<RHS, typename Op::right_zero>::value>::type>
139  typename Op::left_zero simplify_BinaryOp(const BinaryOp<LHS, Op, RHS>&, detail::choice<0>) { return {}; };
140 
141  // Eliminate any identity operations
142  template<class Config, class LHS, class Op>
144 
145  template<class Config, class RHS, class Op,
146  typename = typename std::enable_if<!std::is_same<RHS, typename Op::right_identity>::value>::type>
148 
149  //Special case for divide
150  template<class Config, class ...VarArgs1, class ...VarArgs2,
151  typename = typename enable_if_var_in<Var<VarArgs1...>, Var<VarArgs2...> >::type>
153  { return {};}
154 
155  //Special case for the subtraction binary operator becoming the unary negation operator
156  template<class Config, class RHS, typename = typename std::enable_if<!std::is_same<RHS, Null>::value>::type>
157  RHS simplify_BinaryOp(const SubtractOp<Null, RHS>& r, detail::choice<0>) { return try_simplify<Config>(-r._r); }
158 
159  //Transformations to power-ops where possible
160  template<class Config, class ...VarArgs1, class ...VarArgs2,
161  typename = typename enable_if_var_in<Var<VarArgs1...>, Var<VarArgs2...> >::type>
164 
165  template<class Config, class ...VarArgs1, class ...VarArgs2, class Order,
166  typename = typename enable_if_var_in<Var<VarArgs1...>, Var<VarArgs2...> >::type>
168  -> STATOR_AUTORETURN(sym::pow(typename variable_combine<Var<VarArgs1...>, Var<VarArgs2...> >::type {}, f._l._r + C<1>()));
169 
170  template<class Config, class ...VarArgs1, class ...VarArgs2, class Order,
171  typename = typename enable_if_var_in<Var<VarArgs1...>, Var<VarArgs2...> >::type>
173  -> STATOR_AUTORETURN(sym::pow(typename variable_combine<Var<VarArgs1...>, Var<VarArgs2...> >::type {}, f._r._r + C<1>()));
174 
175  // Simplification of both arguments available
176  template<class Config, class LHS, class RHS, class Op>
178  -> STATOR_AUTORETURN(try_simplify<Config>(Op::apply(simplify<Config>(f._l), simplify<Config>(f._r))));
179 
180  // Simplification of only one argument available
181  template<class Config, class LHS, class RHS, class Op>
183  -> STATOR_AUTORETURN(try_simplify<Config>(Op::apply(simplify<Config>(f._l), f._r)));
184 
185  template<class Config, class LHS, class RHS, class Op>
187  -> STATOR_AUTORETURN(try_simplify<Config>(Op::apply(f._l, simplify<Config>(f._r))));
188 
190 
191  template<class Config, class Arg, std::intmax_t Power>
193  -> STATOR_AUTORETURN(try_simplify<Config>(PowerOpSub<Power>::eval(simplify<Config>(f._l))));
194 
195  template<class Config, class Arg, std::intmax_t Power>
197  -> STATOR_AUTORETURN(simplify<Config>(PowerOpSub<Power>::eval(f._l)));
198 
199  //Disable expansion of PowerOps of variables (otherwise we will recurse to death)
200  template<class T> struct PowerOpEnableExpansion { static const bool value = true; };
201  template<class ...VarArgs> struct PowerOpEnableExpansion<Var<VarArgs...> > { static const bool value = false; };
202 
208  template<class Config = DefaultSimplifyConfig, class Arg, std::intmax_t Power,
209  typename = typename std::enable_if<PowerOpEnableExpansion<Arg>::value>::type>
210  auto simplify(const PowerOp<Arg, C<Power, 1> >& f) -> STATOR_AUTORETURN(simplify_powerop_impl<Config>(f, detail::select_overload{}));
211 
212 
213  //Implement other simplifications at least at choice<5> or above, reordering should be a last case option!
214 
215  // Reorder to find further simplifications
216  //
217  // If you're trying to check if there is a simplification for a
218  // reordering, you must create the new BinaryOp's yourself and not
219  // use Op::apply, as the arguments may have their own ::operatorX
220  // methods which are simpler but do not simplify(). To detect this
221  // we rely on the first BinaryOp simplification rule which detects
222  // arguments having their own specialised operators.
223 
224  // For associative operators, try (A*B)*C as A*(B*C) (but only do this if B*C has a simplification)
225  template<class Config, class Arg1, class Arg2, class Arg3, class Op,
226  typename = typename std::enable_if<Op::associative>::type>
228  -> STATOR_AUTORETURN(try_simplify<Config>(Op::apply(f._l._l, simplify<Config>(BinaryOp<Arg2, Op, Arg3>(f._l._r, f._r)))));
229 
230  // For associative operators, try A*(B*C) as (A*B)*C (but only do this if A*B has a simplification)
231  template<class Config, class Arg1, class Arg2, class Arg3, class Op,
232  typename = typename std::enable_if<Op::associative>::type>
234  -> STATOR_AUTORETURN(try_simplify<Config>(Op::apply(simplify<Config>(BinaryOp<Arg1, Op, Arg2>(f._l, f._r._l)), f._r._r)));
235 
236  // For associative and commutative operators, try (A*B)*C as (A*C)*B (but only do this if A*C has a simplification)
237  template<class Config, class Arg1, class Arg2, class Arg3, class Op,
238  typename = typename std::enable_if<Op::associative>::type>
240  -> STATOR_AUTORETURN(try_simplify<Config>(Op::apply(simplify<Config>(BinaryOp<Arg1, Op, Arg3>(f._l._l, f._r)), f._l._r)));
241 
242  // For associative and commutative operators, try A*(B*C) as (A*C)*B (but only do this if A*C has a simplification)
243  template<class Config, class Arg1, class Arg2, class Arg3, class Op,
244  typename = typename std::enable_if<Op::associative>::type>
246  -> STATOR_AUTORETURN(try_simplify<Config>(Op::apply(simplify<Config>(BinaryOp<Arg1, Op, Arg3>(f._l, f._r._r)), f._r._l)));
247 
248 
249  // Finally, the gateway to the above series of simplifications for BinaryOps!
250  template<class Config = DefaultSimplifyConfig, class L, class Op, class R>
251  auto simplify(BinaryOp<L,Op,R> t) -> STATOR_AUTORETURN(simplify_BinaryOp<Config>(t, detail::select_overload{}));
252 
253 
265  template<class Config = DefaultSimplifyConfig, class PolyVar, class ...VarArgs, size_t Order, class Real,
266  typename = typename std::enable_if<Config::expand_to_Polynomial && variable_in<Var<VarArgs...>, PolyVar>::value>::type>
268  {
270  retval[0] = empty_sum(retval[0]);
271  std::copy(f._r.begin(), f._r.end(), retval.begin() + 1);
272  return retval;
273  }
274 
277  template<class Config = DefaultSimplifyConfig, class PolyVar, class ...VarArgs, size_t Order, class Real,
278  typename = typename std::enable_if<(Config::expand_to_Polynomial && variable_in<Var<VarArgs...>, PolyVar>::value)>::type>
280  {
281  Polynomial<Order+1, Real, typename variable_combine<PolyVar, Var<VarArgs...> >::type> retval;
282  retval[0] = empty_sum(retval[0]);
283  std::copy(f._l.begin(), f._l.end(), retval.begin() + 1);
284  return retval;
285  }
286 
288  template<class Config = DefaultSimplifyConfig, class ...VarArgs,
289  typename = typename std::enable_if<Config::expand_to_Polynomial>::type>
291 
295  template<class Config = DefaultSimplifyConfig, class ...VarArgs, std::intmax_t Power,
296  typename = typename std::enable_if<Config::expand_to_Polynomial>::type>
297  Polynomial<Power, int, Var<VarArgs...>> simplify(const PowerOp<Var<VarArgs...>, C<Power,1> >&) {
298  Polynomial<Power, int, Var<VarArgs...> > retval;
299  retval[Power] = 1;
300  return retval;
301  }
302 
305  template<class T,
306  typename = typename std::enable_if<std::is_arithmetic<T>::value || std::is_base_of<Eigen::EigenBase<T>, T>::value>::type>
307  auto toArithmetic(T val) -> STATOR_AUTORETURN_BYVALUE(val);
308 
309  template<class T,
310  typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
311  auto toArithmetic(std::complex<T> val) -> STATOR_AUTORETURN_BYVALUE(val);
312 
313  template<std::intmax_t n1, std::intmax_t d1,
314  typename = typename std::enable_if<!(n1 % d1)>::type>
315  std::intmax_t toArithmetic(C<n1,d1> val) { return n1 / d1; }
316 
317  template<std::intmax_t n1, std::intmax_t d1,
318  typename = typename std::enable_if<n1 % d1>::type>
319  double toArithmetic(C<n1,d1> val) { return double(n1) / double(d1); }
320 
321  template<class Config, std::intmax_t num, std::intmax_t den,
322  typename = typename std::enable_if<Config::expand_Constants>::type>
323  auto simplify(const C<num, den>& f) -> STATOR_AUTORETURN(typename Config::expand_Constants_to_t(num)/typename Config::expand_Constants_to_t(den));
324 
327  template<class Config, class PolyVar, size_t Order, class Real, class Op, class Real2,
328  typename = typename std::enable_if<Config::expand_to_Polynomial && detail::IsConstant<Real2>::value>::type>
330  -> STATOR_AUTORETURN(try_simplify<Config>(Op::apply(f._l, Polynomial<0, decltype(toArithmetic(f._r)), PolyVar>{toArithmetic(f._r)})));
331 
334  template<class Config, class PolyVar, size_t Order, class Real, class Op, class Real2,
335  typename = typename std::enable_if<Config::expand_to_Polynomial && detail::IsConstant<Real2>::value>::type>
337  -> STATOR_AUTORETURN(try_simplify<Config>(Op::apply(Polynomial<0, decltype(toArithmetic(f._l)), PolyVar>{toArithmetic(f._l)}, f._r)));
338 
339  namespace detail {
340  constexpr size_t max_order(size_t N, size_t M)
341  { return N > M ? N : M; }
342  }// namespace detail
343 
346  template<class Config = DefaultSimplifyConfig, class Real1, size_t N, class Real2, size_t M, class PolyVar1, class PolyVar2, class Op,
347  typename = typename std::enable_if<std::is_same<Op,detail::Add>::value || std::is_same<Op,detail::Subtract>::value>::type,
348  typename = typename enable_if_var_in<PolyVar1, PolyVar2>::type>
350  -> Polynomial<detail::max_order(M, N), decltype(store(Op::apply(f._l[0],f._r[0]))), typename variable_combine<PolyVar1, PolyVar2>::type>
351  {
352  Polynomial<detail::max_order(M, N), decltype(store(Op::apply(f._l[0], f._r[0]))), typename variable_combine<PolyVar1, PolyVar2>::type> retval;
353 
354  for (size_t i(0); i <= std::min(N, M); ++i)
355  retval[i] = Op::apply(f._l[i], f._r[i]);
356 
357  for (size_t i(std::min(N, M)+1); i <= N; ++i)
358  retval[i] = Op::apply(f._l[i], empty_sum(f._l[i]));
359 
360  for (size_t i(std::min(N, M)+1); i <= M; ++i)
361  retval[i] = Op::apply(empty_sum(f._r[i]), f._r[i]);
362 
363  return retval;
364  }
365 
368  template<class Config = DefaultSimplifyConfig, class Real1, class Real2, size_t M, size_t N,
369  class PolyVar1, class PolyVar2, class Op,
370  typename = typename std::enable_if<std::is_same<Op,detail::Multiply>::value>::type>
372  -> Polynomial<M + N, decltype(store(Op::apply(f._l[0], f._r[0]))), typename variable_combine<PolyVar1, PolyVar2>::type>
373  {
374  Polynomial<M + N, decltype(store(Op::apply(f._l[0], f._r[0]))), typename variable_combine<PolyVar1, PolyVar2>::type> retval;
375  for (size_t i(0); i <= N+M; ++i)
376  for (size_t j(i>N?i-N:0); (j <= i) && (j <=M); ++j)
377  retval[i] += Op::apply(f._l[j], f._r[i-j]);
378  return retval;
379  }
380 
383  template<class Config = DefaultSimplifyConfig, class Real1, class Real2, size_t M, class PolyVar1, class PolyVar2>
385  -> Polynomial<M, decltype(store(f._l[0] / f._r[0])), typename variable_combine<PolyVar1, PolyVar2>::type>
386  {
387  Polynomial<M, decltype(store(f._l[0] / f._r[0])), typename variable_combine<PolyVar1, PolyVar2>::type> retval;
388  for (size_t i(0); i <= M; ++i)
389  retval[i] += f._l[i] / f._r[0];
390  return retval;
391  }
392 
394  //template<class Config = DefaultSimplifyConfig, size_t Power, class Matrix, size_t N, char Letter,
395  // typename = typename std::enable_if<(Power==2) && std::is_base_of<Eigen::EigenBase<Matrix>, Matrix>::value>::type>
396  //auto simplify(const PowerOp<Polynomial<N, Matrix, Letter>, Power>& f)
397  // -> Polynomial<2 * N, STORETYPE(f._arg[0].dot(f.arg[0])), Letter>
398  //{
399  // Polynomial<2 * N, STORETYPE(f._arg[0].dot(f._arg[0])), Letter> retval;
400  // for (size_t i(0); i <= 2 * N; ++i)
401  // for (size_t j(i>N?i-N:0); (j <= i) && (j <=N); ++j)
402  // retval[i] += f._arg[j].dot(f._arg[i-j]);
403  // return retval;
404  //}
405  //
407  //template<class Config = DefaultSimplifyConfig, class Real1, class Real2, size_t N, char Letter,
408  // typename = typename std::enable_if<detail::distribute_poly<Real1, Real2>::value>::type>
409  //auto simplify(const DivideOp<Polynomial<N, Real1, Letter>, Real2> & f) -> Polynomial<N, STORETYPE(f._l[0] / f._r), Letter>
410  //{
411  // Polynomial<N, STORETYPE(f._l[0] / f._r), Letter> retval;
412  // for (size_t i(0); i <= N; ++i)
413  // retval[i] = f._l[i] / f._r;
414  // return retval;
415  //}
416 
417  // FUNCTION SIMPLIFICATION
418 
419  template<class Config, class Arg>
420  auto simplify_UnaryOp(const UnaryOp<UnaryOp<Arg, detail::Arbsign>, detail::Arbsign>& f, detail::choice<0>)
421  -> STATOR_AUTORETURN(try_simplify<Config>(detail::Arbsign::apply(f._arg._arg)));
422 
423  //Simplify the argument only (if such a simplification exists
424  template<class Config, class Arg, class Op>
425  auto simplify_UnaryOp(const UnaryOp<Arg, Op>& f, detail::last_choice)
426  -> STATOR_AUTORETURN(try_simplify<Config>(Op::apply(simplify<Config>(f._arg))));
427 
428  // The gateway to the simplifcation of unary operations
429  template<class Config = DefaultSimplifyConfig, class Arg, class Op>
430  auto simplify(const UnaryOp<Arg, Op>& f)
431  -> STATOR_AUTORETURN(simplify_UnaryOp<Config>(f, detail::select_overload{}));
432 
433  //Sign propagation through multipliction or division
434  template<class Config = DefaultSimplifyConfig, class Arg1, class Arg2, class Op,
435  typename = typename std::enable_if<std::is_same<Op,detail::Multiply>::value
436  || std::is_same<Op,detail::Divide>::value>::type>
438  -> STATOR_AUTORETURN(try_simplify<Config>(detail::Arbsign::apply(Op::apply(f._l._arg, f._r._arg))));
439 
440  template<class Config, class LHS, class Arg, class Op,
441  typename = typename std::enable_if<std::is_same<Op,detail::Multiply>::value
442  || std::is_same<Op,detail::Divide>::value>::type>
444  -> STATOR_AUTORETURN(try_simplify<Config>(detail::Arbsign::apply(Op::apply(f._l, f._r._arg))));
445 
446  template<class Config, class RHS, class Arg, class Op,
447  typename = typename std::enable_if<std::is_same<Op,detail::Multiply>::value
448  || std::is_same<Op,detail::Divide>::value>::type>
450  -> STATOR_AUTORETURN(try_simplify<Config>(detail::Arbsign::apply(Op::apply(f._l._arg, f._r))));
451 
452  //For even powers, remove the sign term
453  template<class Config = DefaultSimplifyConfig, class Arg, std::intmax_t Power>
455  -> typename std::enable_if<!(Power % 2), decltype(try_simplify<Config>(pow(f._l._arg, C<Power>())))>::type
456  { return try_simplify<Config>(pow(f._l._arg, C<Power>())); }
457 
458  //For odd powers, move the sign term outside
459  template<class Config = DefaultSimplifyConfig, class Arg, std::intmax_t Power>
461  -> typename std::enable_if<Power % 2, decltype(try_simplify<Config>(arbsign(pow(f._l._arg, C<Power>()))))>::type
462  { return try_simplify<Config>(arbsign(pow(f._l._arg, C<Power,1>()))); }
463 
464 }
465 
SimplifyConfig<> DefaultSimplifyConfig
Definition: simplify.hpp:59
#define STATOR_AUTORETURN_BYVALUE(EXPR)
A convenience Macro for defining auto by-value return type functions.
Definition: config.hpp:107
A class which recursively inherits from itself to allow ambiguous function definition ordering...
Definition: config.hpp:65
auto try_simplify(const T &a) -> decltype(detail::try_simplify_imp< Config >(a, detail::select_overload
A method to apply simplification only if it is available.
Definition: simplify.hpp:84
Symbolic representation of a variable.
Definition: symbolic.hpp:94
SimplifyConfig< expand_to_Polynomial, expand_Constants > ExpandConfig
Definition: simplify.hpp:84
auto N(const T &a) -> STATOR_AUTORETURN(simplify< NConfig >(a))
A variant of simplify that converts compile time symbols into numbers.
auto simplify_powerop_impl(const PowerOp< Arg, C< Power, 1 > > &f, detail::choice< 0 >) -> STATOR_AUTORETURN(try_simplify< Config >(PowerOpSub< Power >::eval(simplify< Config >(f._l))))
Polynomial< Order+1, Real, PolyVar > simplify(MultiplyOp< Var< VarArgs... >, Polynomial< Order, Real, PolyVar > > &f)
Type trait which determines if an operation (multiplication, addition) can be distributed over the co...
Definition: simplify.hpp:267
static auto apply(const Arg &a) -> STATOR_AUTORETURN((UnaryOp< decltype(store(a)), Arbsign >(a)))
auto simplify_UnaryOp(const UnaryOp< UnaryOp< Arg, detail::Arbsign >, detail::Arbsign > &f, detail::choice< 0 >) -> STATOR_AUTORETURN(try_simplify< Config >(detail::Arbsign::apply(f._arg._arg)))
Specialisation for squares of matrix expressions.
auto try_N(const T &a) -> STATOR_AUTORETURN(try_simplify< NConfig >(a))
A variant of try_simplify that converts compile time symbols into numbers.
A class representing a compile-time rational constant (i.e., std::ratio).
Definition: constants.hpp:31
choice< LAST_OVERLOAD_LVL > last_choice
Definition: config.hpp:73
auto expand(const T &a) -> STATOR_AUTORETURN(simplify< ExpandConfig >(a))
A variant of simplify that expands into Polynomial types aggressively.
Symbolic representation of a binary symbolic operation.
Definition: binary_ops.hpp:33
Expr simplify(const Expr &f)
Definition: runtime.hpp:511
auto toArithmetic(T val) -> STATOR_AUTORETURN_BYVALUE(val)
A converter to arithmetic types.
#define STATOR_AUTORETURN(EXPR)
A convenience Macro for defining auto return type functions.
Definition: config.hpp:51
The stator symbolic math library.
T empty_sum(const T &)
Returns the empty sum of a type.
Definition: symbolic.hpp:153
auto simplify_BinaryOp(const BinaryOp< LHS, Op, RHS > &f, detail::choice< 0 >) -> typename std::enable_if<!std::is_same< decltype(Op::apply(f._l, f._r)), BinaryOp< LHS, Op, RHS > >::value, decltype(Op::apply(f._l, f._r))>::type
Definition: simplify.hpp:128
auto arbsign(const Arg &arg) -> STATOR_AUTORETURN((UnaryOp< decltype(store(arg)), detail::Arbsign >(arg)))
constexpr size_t max_order(size_t N, size_t M)
Definition: simplify.hpp:340
typename stator::orphan::get_type< sym::expand_Constants_to< double >, Args... >::value expand_Constants_to_t
Definition: simplify.hpp:56
const RHS _r
Definition: binary_ops.hpp:35
const LHS _l
Definition: binary_ops.hpp:34
auto pow(const LHS &l, const RHS &r) -> STATOR_AUTORETURN(std::pow(l, r))
SimplifyConfig< expand_Constants > NConfig
Definition: simplify.hpp:104
Symbolic representation of a unary operator (i.e., sin(x)).
Definition: unary_ops.hpp:30
A class used to start the ambiguous function definition ordering calculation.
Definition: config.hpp:76
auto try_simplify_imp(const T &a, detail::choice< 0 >) -> STATOR_AUTORETURN(simplify< Config >(a))
auto store(const T &val) -> decltype(store_impl(val, select_overload
Definition: config.hpp:94
auto try_expand(const T &a) -> STATOR_AUTORETURN(try_simplify< ExpandConfig >(a))
A variant of try_simplify that expands into Polynomial types aggressively.
Array representation of Polynomial.
Definition: polynomial.hpp:63