sx_elem.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "sx_elem.hpp"
27 #include "sx.hpp"
28 #include <stack>
29 #include <cassert>
30 #include "calculus.hpp"
31 #include "constant_sx.hpp"
32 #include "symbolic_sx.hpp"
33 #include "unary_sx.hpp"
34 #include "binary_sx.hpp"
35 #include "call_sx.hpp"
36 #include "output_sx.hpp"
37 #include "global_options.hpp"
38 #include "sx_function.hpp"
39 
40 namespace casadi {
41 
42 
43 
44  // Allocate storage for the caching
45  CACHING_MAP<casadi_int, IntegerSX*> IntegerSX::cached_constants_;
46  CACHING_MAP<double, RealtypeSX*> RealtypeSX::cached_constants_;
47 
48 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
49  std::mutex IntegerSX::mutex_cached_constants;
50  std::mutex RealtypeSX::mutex_cached_constants;
51 #endif //CASADI_WITH_THREADSAFE_SYMBOLICS
52 
54  node = casadi_limits<SXElem>::nan.node;
55  node->count++;
56  }
57 
58  SXElem::SXElem(SXNode* node_, bool dummy) : node(node_) {
59  node->count++;
60  }
61 
63  return SXElem(node, false);
64  }
65 
66  SXElem::SXElem(const SXElem& scalar) {
67  node = scalar.node;
68  node->count++;
69  }
70 
71  SXElem::SXElem(double val) {
72  // Only ints fit here, not casadi_int
73  int intval = static_cast<int>(val);
74  if (val-static_cast<double>(intval) == 0) { // check if integer
75  if (intval == 0) node = casadi_limits<SXElem>::zero.node;
76  else if (intval == 1) node = casadi_limits<SXElem>::one.node;
77  else if (intval == 2) node = casadi_limits<SXElem>::two.node;
78  else if (intval == -1) node = casadi_limits<SXElem>::minus_one.node;
79  else node = IntegerSX::create(intval);
80  node->count++;
81  } else {
82  if (isnan(val)) node = casadi_limits<SXElem>::nan.node;
83  else if (isinf(val)) node = val > 0 ? casadi_limits<SXElem>::inf.node :
85  else node = RealtypeSX::create(val);
86  node->count++;
87  }
88  }
89 
90  SXElem SXElem::sym(const std::string& name) {
91  return create(new SymbolicSX(name));
92  }
93 
95  if (--node->count == 0) delete node;
96  }
97 
98  SXElem& SXElem::operator=(const SXElem &scalar) {
99  // quick return if the old and new pointers point to the same object
100  if (node == scalar.node) return *this;
101 
102  // decrease the counter and delete if this was the last pointer
103  if (--node->count == 0) delete node;
104 
105  // save the new pointer
106  node = scalar.node;
107  node->count++;
108  return *this;
109  }
110 
111  void SXElem::assignIfDuplicate(const SXElem& scalar, casadi_int depth) {
112  casadi_assert_dev(depth>=1);
113  if (!is_equal(*this, scalar, 0) && is_equal(*this, scalar, depth)) {
114  *this = scalar;
115  }
116  }
117 
119  // Return value
120  SXNode* ret = node;
121 
122  // quick return if the old and new pointers point to the same object
123  if (node == scalar.node) return ret;
124 
125  // decrease the counter but do not delete if this was the last pointer
126  --node->count;
127 
128  // save the new pointer
129  node = scalar.node;
130  node->count++;
131 
132  // Return a pointer to the old node
133  return ret;
134  }
135 
136  SXElem& SXElem::operator=(double scalar) {
137  return *this = SXElem(scalar);
138  }
139 
140  void SXElem::disp(std::ostream& stream, bool more) const {
141  node->disp(stream, more);
142  }
143 
145  if (is_op(OP_NEG))
146  return dep();
147  else if (is_zero())
148  return 0;
149  else if (is_minus_one())
150  return 1;
151  else if (is_one())
152  return -1;
153  else
154  return UnarySX::create(OP_NEG, *this);
155  }
156 
157  bool SXElem::__nonzero__() const {
158  if (is_constant()) return !is_zero();
159  casadi_error("Cannot compute the truth value of a CasADi SXElem symbolic expression.");
160  }
161 
162  bool SXElem::is_doubled() const {
163  return is_op(OP_ADD) && is_equal(dep(0), dep(1), SXNode::eq_depth_);
164  }
165 
166  SXElem SXElem::inv() const {
167  if (is_op(OP_INV)) {
168  return dep(0);
169  } else {
170  return UnarySX::create(OP_INV, *this);
171  }
172  }
173 
174  SXNode* SXElem::get() const {
175  return node;
176  }
177 
178  const SXNode* SXElem::operator->() const {
179  return node;
180  }
181 
183  return node;
184  }
185 
186  SXElem SXElem::binary(casadi_int op, const SXElem& x, const SXElem& y) {
187  // If-else-zero nodes are always simplified at top level to avoid NaN propagation
188  if (y.op() == OP_IF_ELSE_ZERO) {
189  if (op == OP_MUL) {
190  // (Rule 1.) x * if_else_zero(c, y), simplified to if_else_zero(c, x * y)
191  // Background: x is often a partial derivative and may evaluate to INF or NAN.
192  // The simplification ensures that the zero seed corresponding to an inactive branch does
193  // not give rise to any NaN contribution to the derivative due to NaN * 0 == NaN.
194  return if_else_zero(y.dep(0), x * y.dep(1));
195  } else if (op == OP_ADD && x.op() == OP_IF_ELSE_ZERO && is_equal(x.dep(0), y.dep(0))) {
196  // (Rule 2.) if_else_zero(c, x) + if_else_zero(c, y) is simplified to if_else_zero(c, x + y)
197  // Background: During the backward propagation, seeds are added together. Without this rule,
198  // the addition node can prevent rule (1.) from working in subsequent steps.
199  return if_else_zero(y.dep(0), x.dep(1) + y.dep(1));
200  }
201  } else if (x.op() == OP_IF_ELSE_ZERO && op == OP_MUL) {
202  // Same as Rule 1. above, but with factors swapped. For symmetry.
203  return if_else_zero(x.dep(0), x.dep(1) * y);
204  }
205  // Simplifications
207  switch (op) {
208  case OP_ADD:
209  if (x.is_zero())
210  return y;
211  else if (y->is_zero()) // term2 is zero
212  return x;
213  else if (y.is_op(OP_NEG)) // x + (-y) -> x - y
214  return x - (-y);
215  else if (x.is_op(OP_NEG)) // (-x) + y -> y - x
216  return y - x.dep();
217  else if (x.is_op(OP_MUL) && y.is_op(OP_MUL) &&
218  x.dep(0).is_constant() && static_cast<double>(x.dep(0))==0.5 &&
219  y.dep(0).is_constant() && static_cast<double>(y.dep(0))==0.5 &&
220  is_equal(y.dep(1), x.dep(1), SXNode::eq_depth_)) // 0.5x+0.5x = x
221  return x.dep(1);
222  else if (x.is_op(OP_DIV) && y.is_op(OP_DIV) &&
223  x.dep(1).is_constant() && static_cast<double>(x.dep(1))==2 &&
224  y.dep(1).is_constant() && static_cast<double>(y.dep(1))==2 &&
225  is_equal(y.dep(0), x.dep(0), SXNode::eq_depth_)) // x/2+x/2 = x
226  return x.dep(0);
227  else if (x.is_op(OP_SUB) && is_equal(x.dep(1), y, SXNode::eq_depth_))
228  return x.dep(0);
229  else if (y.is_op(OP_SUB) && is_equal(x, y.dep(1), SXNode::eq_depth_))
230  return y.dep(0);
231  else if (x.is_op(OP_SQ) && y.is_op(OP_SQ) &&
232  ((x.dep().is_op(OP_SIN) && y.dep().is_op(OP_COS))
233  || (x.dep().is_op(OP_COS) && y.dep().is_op(OP_SIN)))
234  && is_equal(x.dep().dep(), y.dep().dep(), SXNode::eq_depth_))
235  return 1; // sin^2 + cos^2 -> 1
236  break;
237  case OP_SUB:
238  if (y->is_zero()) // term2 is zero
239  return x;
240  if (x.is_zero()) // term1 is zero
241  return -y;
242  if (is_equal(x, y, SXNode::eq_depth_)) // the terms are equal
243  return 0;
244  else if (y.is_op(OP_NEG)) // x - (-y) -> x + y
245  return x + y.dep();
246  else if (x.is_op(OP_ADD) && is_equal(x.dep(1), y, SXNode::eq_depth_))
247  return x.dep(0);
248  else if (x.is_op(OP_ADD) && is_equal(x.dep(0), y, SXNode::eq_depth_))
249  return x.dep(1);
250  else if (y.is_op(OP_ADD) && is_equal(x, y.dep(1), SXNode::eq_depth_))
251  return -y.dep(0);
252  else if (y.is_op(OP_ADD) && is_equal(x, y.dep(0), SXNode::eq_depth_))
253  return -y.dep(1);
254  else if (x.is_op(OP_NEG))
255  return -(x.dep() + y);
256  break;
257  case OP_MUL:
258  if (is_equal(y, x, SXNode::eq_depth_))
259  return sq(x);
260  else if (!x.is_constant() && y.is_constant())
261  return y * x;
262  else if (x.is_zero() || y->is_zero()) // one of the terms is zero
263  return 0;
264  else if (x.is_one()) // term1 is one
265  return y;
266  else if (y->is_one()) // term2 is one
267  return x;
268  else if (y->is_minus_one())
269  return -x;
270  else if (x.is_minus_one())
271  return -y;
272  else if (y.is_op(OP_INV))
273  return x/y.inv();
274  else if (x.is_op(OP_INV))
275  return y / x.inv();
276  else if (x.is_constant() && y.is_op(OP_MUL) && y.dep(0).is_constant() &&
277  static_cast<double>(x)*static_cast<double>(y.dep(0))==1) // 5*(0.2*x) = x
278  return y.dep(1);
279  else if (x.is_constant() && y.is_op(OP_DIV) && y.dep(1).is_constant() &&
280  static_cast<double>(x)==static_cast<double>(y.dep(1))) // 5*(x/5) = x
281  return y.dep(0);
282  else if (x.is_op(OP_DIV) && is_equal(x.dep(1), y, SXNode::eq_depth_)) // ((2/x)*x)
283  return x.dep(0);
284  else if (y.is_op(OP_DIV) &&
285  is_equal(y.dep(1), x, SXNode::eq_depth_)) // ((2/x)*x)
286  return y.dep(0);
287  else if (x.is_op(OP_NEG))
288  return -(x.dep() * y);
289  else if (y.is_op(OP_NEG))
290  return -(x * y.dep());
291  break;
292  case OP_DIV:
293  if (y->is_zero()) // term2 is zero
295  else if (x.is_zero()) // term1 is zero
296  return 0;
297  else if (y->is_one()) // term2 is one
298  return x;
299  else if (y->is_minus_one())
300  return -x;
301  else if (is_equal(x, y, SXNode::eq_depth_)) // terms are equal
302  return 1;
303  else if (x.is_doubled() && is_equal(y, 2))
304  return x.dep(0);
305  else if (x.is_op(OP_MUL) && is_equal(y, x.dep(0), SXNode::eq_depth_))
306  return x.dep(1);
307  else if (x.is_op(OP_MUL) && is_equal(y, x.dep(1), SXNode::eq_depth_))
308  return x.dep(0);
309  else if (x.is_one())
310  return y.inv();
311  else if (y.is_op(OP_INV))
312  return x*y.inv();
313  else if (x.is_doubled() && y.is_doubled())
314  return x.dep(0) / y->dep(0);
315  else if (y.is_constant() && x.is_op(OP_DIV) && x.dep(1).is_constant() &&
316  static_cast<double>(y)*static_cast<double>(x.dep(1))==1) // (x/5)/0.2
317  return x.dep(0);
318  else if (y.is_op(OP_MUL) &&
319  is_equal(y.dep(1), x, SXNode::eq_depth_)) // x/(2*x) = 1/2
320  return BinarySX::create(OP_DIV, 1, y.dep(0));
321  else if (x.is_op(OP_NEG) &&
322  is_equal(x.dep(0), y, SXNode::eq_depth_)) // (-x)/x = -1
323  return -1;
324  else if (y.is_op(OP_NEG) &&
325  is_equal(y.dep(0), x, SXNode::eq_depth_)) // x/(-x) = 1
326  return -1;
327  else if (y.is_op(OP_NEG) && x.is_op(OP_NEG) &&
328  is_equal(x.dep(0), y.dep(0), SXNode::eq_depth_)) // (-x)/(-x) = 1
329  return 1;
330  else if (x.is_op(OP_DIV) && is_equal(y, x.dep(0), SXNode::eq_depth_))
331  return x.dep(1).inv();
332  else if (x.is_op(OP_NEG))
333  return -(x.dep() / y);
334  else if (y.is_op(OP_NEG))
335  return -(x / y.dep());
336  break;
337  case OP_POW:
338  if (y->is_constant()) {
339  if (y->is_integer()) {
340  casadi_int nn = y->to_int();
341  if (nn == 0) {
342  return 1;
343  } else if (nn>100 || nn<-100) { // maximum depth
344  return binary(OP_CONSTPOW, x, nn);
345  } else if (nn<0) { // negative power
346  return 1/pow(x, -nn);
347  } else if (nn%2 == 1) { // odd power
348  return x*pow(x, nn-1);
349  } else { // even power
350  SXElem rt = pow(x, static_cast<casadi_int>(nn/2));
351  return rt*rt;
352  }
353  } else if (y->to_double()==0.5) {
354  return sqrt(x);
355  } else {
356  return binary(OP_CONSTPOW, x, y);
357  }
358  }
359  break;
360  case OP_LE:
361  if ((y-x).is_nonnegative())
362  return 1;
363  break;
364  case OP_FMIN:
365  if (x.is_inf()) return y;
366  if (y.is_inf()) return x;
367  if (x.is_minus_inf() || y.is_minus_inf()) return -std::numeric_limits<double>::infinity();
368  if (is_equal(x, y, SXNode::eq_depth_)) return x;
369  break;
370  case OP_FMAX:
371  if (x.is_minus_inf()) return y;
372  if (y.is_minus_inf()) return x;
373  if (x.is_inf() || y.is_inf()) return std::numeric_limits<double>::infinity();
374  if (is_equal(x, y, SXNode::eq_depth_)) return x;
375  break;
376  case OP_LT:
377  if (((x)-y).is_nonnegative())
378  return 0;
379  break;
380  case OP_EQ:
381  if (is_equal(x, y))
382  return 1;
383  break;
384  case OP_NE:
385  if (is_equal(x, y))
386  return 0;
387  break;
388  case OP_IF_ELSE_ZERO:
389  if (y->is_zero()) {
390  return y;
391  } else if (x.is_constant()) {
392  if (static_cast<double>(x)!=0) {
393  return y;
394  } else {
395  return 0;
396  }
397  }
398  }
399  }
400  return BinarySX::create(Operation(op), x, y);
401  }
402 
403  std::vector<SXElem> SXElem::call(const Function& f, const std::vector<SXElem>& deps) {
404  SXElem c = CallSX::create(f, deps);
405  return OutputSX::split(c, f.nnz_out());
406  }
407 
408  SXElem SXElem::unary(casadi_int op, const SXElem& x) {
409  // Simplifications
411  switch (op) {
412  case OP_SQ:
413  if (x.is_op(OP_SQRT))
414  return x.dep();
415  else if (x.is_op(OP_NEG))
416  return sq(x.dep());
417  break;
418  case OP_FABS:
419  if (x.is_op(OP_FABS) || x.is_op(OP_SQ))
420  return x;
421  break;
422  case OP_NOT:
423  if (x.is_op(OP_NOT))
424  return x.dep();
425  break;
426  case OP_SINH:
427  case OP_TANH:
428  case OP_ATANH:
429  case OP_ACOSH:
430  case OP_ASINH:
431  if (x.is_zero())
432  return 0;
433  break;
434  case OP_COSH:
435  if (x.is_zero())
436  return 1;
437  break;
438  case OP_SQRT:
439  if (x.is_op(OP_SQ))
440  return fabs(x.dep());
441  break;
442  }
443  }
444  return UnarySX::create(Operation(op), x);
445  }
446 
447  bool SXElem::is_leaf() const {
448  if (!node) return true;
449  return is_constant() || is_symbolic();
450  }
451 
452  bool SXElem::is_commutative() const {
453  casadi_assert(n_dep(), "SX::is_commutative: must be binary");
454  return operation_checker<CommChecker>(op());
455  }
456 
457  bool SXElem::is_constant() const {
458  return node->is_constant();
459  }
460 
461  bool SXElem::is_call() const {
462  return node->is_call();
463  }
464 
465  bool SXElem::is_output() const {
466  return node->is_output();
467  }
468 
469  bool SXElem::has_output() const {
470  return node->has_output();
471  }
472 
474  return node->which_function();
475  }
476 
477  casadi_int SXElem::which_output() const {
478  return node->which_output();
479  }
480 
481  bool SXElem::is_integer() const {
482  return node->is_integer();
483  }
484 
485  bool SXElem::is_symbolic() const {
486  return node->is_symbolic();
487  }
488 
489  bool SXElem::is_zero() const {
490  return node->is_zero();
491  }
492 
493  bool SXElem::is_almost_zero(double tol) const {
494  return node->is_almost_zero(tol);
495  }
496 
497  bool SXElem::is_one() const {
498  return node->is_one();
499  }
500 
501  bool SXElem::is_minus_one() const {
502  return node->is_minus_one();
503  }
504 
505  bool SXElem::is_nan() const {
506  return node->is_nan();
507  }
508 
509  bool SXElem::is_inf() const {
510  return node->is_inf();
511  }
512 
513  bool SXElem::is_minus_inf() const {
514  return node->is_minus_inf();
515  }
516 
517  const std::string& SXElem::name() const {
518  return node->name();
519  }
520 
521  casadi_int SXElem::op() const {
522  return node->op();
523  }
524 
525  bool SXElem::is_op(casadi_int op) const {
526  return node->is_op(op);
527  }
528 
529  bool SXElem::is_equal(const SXElem& x, const SXElem& y, casadi_int depth) {
530  SXNode *x_node = x.get(), *y_node = y.get();
531  if (x_node==y_node) {
532  return true;
533  } else if (depth>0) {
534  return x_node->is_equal(y_node, depth);
535  } else {
536  return false;
537  }
538  }
539 
540  bool SXElem::is_nonnegative() const {
541  if (is_constant()) {
542  return static_cast<double>(*this)>=0;
543  } else if (is_op(OP_SQ) || is_op(OP_FABS)) {
544  return true;
545  } else {
546  return false;
547  }
548  }
549 
550  SXElem::operator double() const {
551  return node->to_double();
552  }
553 
554  SXElem::operator casadi_int() const {
555  return node->to_int();
556  }
557 
558  SXElem SXElem::dep(casadi_int ch) const {
559  casadi_assert_dev(ch >= 0 || ch < n_dep());
560  return node->dep(ch);
561  }
562 
563  casadi_int SXElem::n_dep() const {
564  return node->n_dep();
565  }
566 
567  SXElem SXElem::get_output(casadi_int oind) const {
568  return node->get_output(oind);
569  }
570 
571  casadi_int SXElem::__hash__() const {
572  return reinterpret_cast<casadi_int>(node);
573  }
574 
575  // node corresponding to a constant 0
577  // node corresponding to a constant 1
579  // node corresponding to a constant 2
581  // node corresponding to a constant -1
586 
588  return val.is_zero();
589  }
590 
591  bool casadi_limits<SXElem>::is_equal(const SXElem& x, const SXElem& y, casadi_int depth) {
592  return SXElem::is_equal(x, y, depth);
593  }
594 
595  bool casadi_limits<SXElem>::is_almost_zero(const SXElem& val, double tol) {
596  return val.is_almost_zero(tol);
597  }
598 
600  return val.is_one();
601  }
602 
604  return val.is_minus_one();
605  }
606 
608  return val.is_constant();
609  }
610 
612  return val.is_integer();
613  }
614 
616  return val.is_inf();
617  }
618 
620  return val.is_minus_inf();
621  }
622 
624  return val.is_nan();
625  }
626 
627  SXElem::operator SX() const {
628  return SX(Sparsity::scalar(), *this, false);
629  }
630 
631  int SXElem::get_temp() const {
632  return (*this)->temp;
633  }
634 
635  void SXElem::set_temp(int t) const {
636  (*this)->temp = t;
637  }
638 
639  bool SXElem::marked() const {
640  return (*this)->marked();
641  }
642 
643  void SXElem::mark() const {
644  (*this)->mark();
645  }
646 
647  bool SXElem::is_regular() const {
648  if (is_constant()) {
649  return !(is_nan() || is_inf() || is_minus_inf());
650  } else {
651  casadi_error("Cannot check regularity for symbolic SXElem");
652  }
653  }
654 
656  return (*this)->serialize(s);
657  }
658 
661  }
662 
663 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
664  std::mutex SXElem::mutex_temp;
665 #endif //CASADI_WITH_THREADSAFE_SYMBOLICS
666 
667 } // namespace casadi
668 
669 using namespace casadi;
670 namespace std {
671  SXElem std::numeric_limits<SXElem>::infinity() throw() {
673  }
674 
675  SXElem std::numeric_limits<SXElem>::quiet_NaN() throw() {
677  }
678 
679  SXElem std::numeric_limits<SXElem>::min() throw() {
680  return SXElem(std::numeric_limits<double>::min());
681  }
682 
683  SXElem std::numeric_limits<SXElem>::max() throw() {
684  return SXElem(std::numeric_limits<double>::max());
685  }
686 
687  SXElem std::numeric_limits<SXElem>::epsilon() throw() {
688  return SXElem(std::numeric_limits<double>::epsilon());
689  }
690 
691  SXElem std::numeric_limits<SXElem>::round_error() throw() {
692  return SXElem(std::numeric_limits<double>::round_error());
693  }
694 
695 } // namespace std
static SXElem create(unsigned char op, const SXElem &dep0, const SXElem &dep1)
Create a binary expression.
Definition: binary_sx.hpp:55
static SXElem create(const Function &f, const std::vector< SXElem > &dep)
Create a binary expression.
Definition: call_sx.hpp:57
Helper class for Serialization.
Function object.
Definition: function.hpp:60
casadi_int nnz_out() const
Get number of output nonzeros.
Definition: function.cpp:855
static bool simplification_on_the_fly
Indicates whether simplifications should be made on the fly.
static InfSX * singleton()
static CACHING_MAP< casadi_int, IntegerSX * > cached_constants_
Hash map of all constants currently allocated.
static IntegerSX * create(casadi_int value)
Static creator function (use instead of constructor)
static MinusInfSX * singleton()
static MinusOneSX * singleton()
static NanSX * singleton()
static OneSX * singleton()
static std::vector< SXElem > split(const SXElem &e, casadi_int n)
Definition: output_sx.hpp:139
static CACHING_MAP< double, RealtypeSX * > cached_constants_
Hash map of all constants currently allocated.
static RealtypeSX * create(double value)
Static creator function (use instead of constructor)
The basic scalar symbolic class of CasADi.
Definition: sx_elem.hpp:75
void serialize(SerializingStream &s) const
Serialize an object.
Definition: sx_elem.cpp:655
bool is_nan() const
Definition: sx_elem.cpp:505
void set_temp(int t) const
Set the temporary variable.
Definition: sx_elem.cpp:635
bool is_zero() const
Definition: sx_elem.cpp:489
bool is_output() const
Definition: sx_elem.cpp:465
void assignIfDuplicate(const SXElem &scalar, casadi_int depth=1)
Assign to another expression, if a duplicate.
Definition: sx_elem.cpp:111
bool is_regular() const
Checks if expression does not contain NaN or Inf.
Definition: sx_elem.cpp:647
SXElem dep(casadi_int ch=0) const
Definition: sx_elem.cpp:558
bool marked() const
Check if marked (i.e. temporary is negative)
Definition: sx_elem.cpp:639
void disp(std::ostream &stream, bool more=false) const
Print a description of the object.
Definition: sx_elem.cpp:140
bool is_call() const
Definition: sx_elem.cpp:461
bool __nonzero__() const
Check the truth value of this node.
Definition: sx_elem.cpp:157
static std::vector< SXElem > call(const Function &f, const std::vector< SXElem > &deps)
Definition: sx_elem.cpp:403
~SXElem()
Destructor.
Definition: sx_elem.cpp:94
bool is_minus_inf() const
Definition: sx_elem.cpp:513
bool has_output() const
Definition: sx_elem.cpp:469
bool is_leaf() const
check if this SXElem is a leaf of the SX graph
Definition: sx_elem.cpp:447
SXElem inv() const
Element-wise inverse.
Definition: sx_elem.cpp:166
bool is_symbolic() const
Definition: sx_elem.cpp:485
static SXElem create(SXNode *node)
Definition: sx_elem.cpp:62
bool is_minus_one() const
Definition: sx_elem.cpp:501
const SXNode * operator->() const
Access functions of the node.
Definition: sx_elem.cpp:178
SXElem operator-() const
Negation.
Definition: sx_elem.cpp:144
void mark() const
Mark by flipping the sign of the temporary and decreasing by one.
Definition: sx_elem.cpp:643
bool is_integer() const
Definition: sx_elem.cpp:481
Function which_function() const
Definition: sx_elem.cpp:473
SXElem get_output(casadi_int oind) const
Get an output.
Definition: sx_elem.cpp:567
int get_temp() const
Definition: sx_elem.cpp:631
bool is_doubled() const
Check if the node is the sum of two equal expressions.
Definition: sx_elem.cpp:162
casadi_int op() const
Definition: sx_elem.cpp:521
static SXElem unary(casadi_int op, const SXElem &x)
Definition: sx_elem.cpp:408
bool is_commutative() const
Check whether a binary SXElem is commutative.
Definition: sx_elem.cpp:452
bool is_constant() const
Definition: sx_elem.cpp:457
SXNode * assignNoDelete(const SXElem &scalar)
Assign the node to something, without invoking the deletion of the node,.
Definition: sx_elem.cpp:118
static SXElem binary(casadi_int op, const SXElem &x, const SXElem &y)
Perform operations by ID.
Definition: sx_elem.cpp:186
bool is_almost_zero(double tol) const
Definition: sx_elem.cpp:493
bool is_op(casadi_int op) const
Definition: sx_elem.cpp:525
SXNode * get() const
Get a pointer to the node.
Definition: sx_elem.cpp:174
static SXElem deserialize(DeserializingStream &s)
Definition: sx_elem.cpp:659
casadi_int which_output() const
Definition: sx_elem.cpp:477
bool is_one() const
Definition: sx_elem.cpp:497
const std::string & name() const
Definition: sx_elem.cpp:517
casadi_int __hash__() const
Returns a number that is unique for a given SXNode.
Definition: sx_elem.cpp:571
casadi_int n_dep() const
Get the number of dependencies of a binary SXElem.
Definition: sx_elem.cpp:563
static bool is_equal(const SXElem &x, const SXElem &y, casadi_int depth=0)
Check equality up to a given depth.
Definition: sx_elem.cpp:529
SXElem()
Default constructor (not-a-number)
Definition: sx_elem.cpp:53
static SXElem sym(const std::string &name)
Create a symbolic primitive.
Definition: sx_elem.cpp:90
SXElem & operator=(const SXElem &scalar)
Assignment.
Definition: sx_elem.cpp:98
bool is_inf() const
Definition: sx_elem.cpp:509
bool is_nonnegative() const
Check if a value is always nonnegative (false negatives are allowed)
Definition: sx_elem.cpp:540
Internal node class for SX.
Definition: sx_node.hpp:49
virtual SXElem get_output(casadi_int oind) const
Get an output.
Definition: sx_node.cpp:227
virtual const SXElem & dep(casadi_int i) const
get the reference of a child
Definition: sx_node.cpp:80
virtual Function which_function() const
Get called function.
Definition: sx_node.cpp:64
virtual bool is_zero() const
check properties of a node
Definition: sx_node.hpp:72
virtual bool is_minus_one() const
check properties of a node
Definition: sx_node.hpp:76
static SXNode * deserialize(DeserializingStream &s)
Definition: sx_node.cpp:243
virtual bool is_almost_zero(double tol) const
check properties of a node
Definition: sx_node.hpp:74
virtual bool is_one() const
check properties of a node
Definition: sx_node.hpp:75
virtual casadi_int n_dep() const
Number of dependencies.
Definition: sx_node.hpp:124
virtual bool is_nan() const
check properties of a node
Definition: sx_node.hpp:77
virtual casadi_int to_int() const
Get value of a constant node.
Definition: sx_node.cpp:60
virtual bool is_call() const
check properties of a node
Definition: sx_node.hpp:80
unsigned int count
Definition: sx_node.hpp:197
virtual bool is_equal(const SXNode *node, casadi_int depth) const
Check if two nodes are equivalent up to a given depth.
Definition: sx_node.cpp:72
virtual const std::string & name() const
Definition: sx_node.cpp:76
virtual bool is_integer() const
check properties of a node
Definition: sx_node.hpp:70
virtual double to_double() const
Get value of a constant node.
Definition: sx_node.cpp:56
virtual bool is_inf() const
check properties of a node
Definition: sx_node.hpp:78
virtual bool is_symbolic() const
check properties of a node
Definition: sx_node.hpp:71
virtual bool is_op(casadi_int op) const
check properties of a node
Definition: sx_node.hpp:73
virtual bool is_output() const
check properties of a node
Definition: sx_node.hpp:81
static casadi_int eq_depth_
Definition: sx_node.hpp:179
virtual casadi_int op() const =0
get the operation
virtual bool has_output() const
check properties of a node
Definition: sx_node.hpp:82
virtual bool is_constant() const
check properties of a node
Definition: sx_node.hpp:69
virtual bool is_minus_inf() const
check properties of a node
Definition: sx_node.hpp:79
virtual void disp(std::ostream &stream, bool more) const
print
Definition: sx_node.cpp:88
virtual casadi_int which_output() const
Get function output.
Definition: sx_node.cpp:68
Helper class for Serialization.
static Sparsity scalar(bool dense_scalar=true)
Create a scalar sparsity pattern *.
Definition: sparsity.hpp:153
Represents a scalar symbolic expression.
Definition: symbolic_sx.hpp:42
static SXElem create(unsigned char op, const SXElem &dep)
Create a unary expression.
Definition: unary_sx.hpp:55
static ZeroSX * singleton()
casadi_limits class
static bool is_inf(const T &val)
static const T minus_one
static bool is_almost_zero(const T &val, double tol)
static bool is_constant(const T &val)
static bool is_equal(const T &x, const T &y, casadi_int depth)
static bool is_one(const T &val)
static bool is_minus_inf(const T &val)
static bool is_integer(const T &val)
static bool is_minus_one(const T &val)
static bool is_nan(const T &val)
static bool is_zero(const T &val)
static SXElem sqrt(const SXElem &x)
Square root: x -> sqrt(x)
static SXElem if_else_zero(const SXElem &x, const SXElem &y)
Conditional assignment: (x,y) -> x ? y : 0.
static SXElem sq(const SXElem &x)
Square: x -> x^2.
static SXElem pow(const SXElem &x, const SXElem &y)
Elementwise power: (x,y) -> x.^y.
friend SXElem fabs(const SXElem &x)
The casadi namespace.
Definition: archiver.cpp:28
Matrix< SXElem > SX
Definition: sx_fwd.hpp:32
Operation
Enum for quick access to any node.
Definition: calculus.hpp:60
@ OP_COS
Definition: calculus.hpp:68
@ OP_NE
Definition: calculus.hpp:70
@ OP_FMAX
Definition: calculus.hpp:72
@ OP_SINH
Definition: calculus.hpp:74
@ OP_COSH
Definition: calculus.hpp:74
@ OP_ASINH
Definition: calculus.hpp:75
@ OP_IF_ELSE_ZERO
Definition: calculus.hpp:71
@ OP_SQRT
Definition: calculus.hpp:67
@ OP_INV
Definition: calculus.hpp:73
@ OP_SIN
Definition: calculus.hpp:68
@ OP_LT
Definition: calculus.hpp:70
@ OP_ACOSH
Definition: calculus.hpp:75
@ OP_EQ
Definition: calculus.hpp:70
@ OP_SUB
Definition: calculus.hpp:65
@ OP_ATANH
Definition: calculus.hpp:75
@ OP_FMIN
Definition: calculus.hpp:72
@ OP_POW
Definition: calculus.hpp:66
@ OP_FABS
Definition: calculus.hpp:71
@ OP_TANH
Definition: calculus.hpp:74
@ OP_ADD
Definition: calculus.hpp:65
@ OP_LE
Definition: calculus.hpp:70
@ OP_DIV
Definition: calculus.hpp:65
@ OP_NEG
Definition: calculus.hpp:66
@ OP_CONSTPOW
Definition: calculus.hpp:66
@ OP_NOT
Definition: calculus.hpp:70
@ OP_MUL
Definition: calculus.hpp:65
@ OP_SQ
Definition: calculus.hpp:67