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  // Check for nan/inf first to avoid undefined behavior from static_cast<int>
73  if (isnan(val)) {
74  node = casadi_limits<SXElem>::nan.node;
75  } else if (isinf(val)) {
76  node = val > 0 ? casadi_limits<SXElem>::inf.node :
78  } else {
79  // Only ints fit here, not casadi_int
80  int intval = static_cast<int>(val);
81  if (val-static_cast<double>(intval) == 0) { // check if integer
82  if (intval == 0) node = casadi_limits<SXElem>::zero.node;
83  else if (intval == 1) node = casadi_limits<SXElem>::one.node;
84  else if (intval == 2) node = casadi_limits<SXElem>::two.node;
85  else if (intval == -1) node = casadi_limits<SXElem>::minus_one.node;
86  else node = IntegerSX::create(intval);
87  } else {
88  node = RealtypeSX::create(val);
89  }
90  }
91  node->count++;
92  }
93 
94  SXElem SXElem::sym(const std::string& name) {
95  return create(new SymbolicSX(name));
96  }
97 
99  if (--node->count == 0) delete node;
100  }
101 
102  SXElem& SXElem::operator=(const SXElem &scalar) {
103  if (this == &scalar) return *this;
104 
105  // quick return if the old and new pointers point to the same object
106  if (node == scalar.node) return *this;
107 
108  // decrease the counter and delete if this was the last pointer
109  if (--node->count == 0) delete node;
110 
111  // save the new pointer
112  node = scalar.node;
113  node->count++;
114  return *this;
115  }
116 
117  void SXElem::assignIfDuplicate(const SXElem& scalar, casadi_int depth) {
118  casadi_assert_dev(depth>=1);
119  if (!is_equal(*this, scalar, 0) && is_equal(*this, scalar, depth)) {
120  *this = scalar;
121  }
122  }
123 
125  // Return value
126  SXNode* ret = node;
127 
128  // quick return if the old and new pointers point to the same object
129  if (node == scalar.node) return ret;
130 
131  // decrease the counter but do not delete if this was the last pointer
132  --node->count;
133 
134  // save the new pointer
135  node = scalar.node;
136  node->count++;
137 
138  // Return a pointer to the old node
139  return ret;
140  }
141 
142  SXElem& SXElem::operator=(double scalar) {
143  return *this = SXElem(scalar);
144  }
145 
146  void SXElem::disp(std::ostream& stream, bool more) const {
147  node->disp(stream, more);
148  }
149 
151  if (is_op(OP_NEG))
152  return dep();
153  else if (is_zero())
154  return 0;
155  else if (is_minus_one())
156  return 1;
157  else if (is_one())
158  return -1;
159  else
160  return unary(OP_NEG, *this);
161  }
162 
163  bool SXElem::__nonzero__() const {
164  if (is_constant()) return !is_zero();
165  casadi_error("Cannot compute the truth value of a CasADi SXElem symbolic expression.");
166  }
167 
168  bool SXElem::is_doubled() const {
169  return (is_op(OP_ADD) && is_equal(dep(0), dep(1), SXNode::eq_depth_)) ||
170  (is_op(OP_TWICE));
171  }
172 
173  SXElem SXElem::inv() const {
174  return unary(OP_INV, *this);
175  }
176 
177  SXNode* SXElem::get() const {
178  return node;
179  }
180 
181  const SXNode* SXElem::operator->() const {
182  return node;
183  }
184 
186  return node;
187  }
188 
189  SXElem SXElem::binary(casadi_int op, const SXElem& x, const SXElem& y,
190  bool unique_x, bool unique_y) {
191  // If-else-zero nodes are always simplified at top level to avoid NaN propagation
192  if (y.op() == OP_IF_ELSE_ZERO) {
193  if (op == OP_MUL) {
194  // (Rule 1.) x * if_else_zero(c, y), simplified to if_else_zero(c, x * y)
195  // Background: x is often a partial derivative and may evaluate to INF or NAN.
196  // The simplification ensures that the zero seed corresponding to an inactive branch does
197  // not give rise to any NaN contribution to the derivative due to NaN * 0 == NaN.
198  return if_else_zero(y.dep(0), x * y.dep(1));
199  } else if (op == OP_ADD && x.op() == OP_IF_ELSE_ZERO && is_equal(x.dep(0), y.dep(0))) {
200  // (Rule 2.) if_else_zero(c, x) + if_else_zero(c, y) is simplified to if_else_zero(c, x + y)
201  // Background: During the backward propagation, seeds are added together. Without this rule,
202  // the addition node can prevent rule (1.) from working in subsequent steps.
203  return if_else_zero(y.dep(0), x.dep(1) + y.dep(1));
204  }
205  } else if (x.op() == OP_IF_ELSE_ZERO && op == OP_MUL) {
206  // Same as Rule 1. above, but with factors swapped. For symmetry.
207  return if_else_zero(x.dep(0), x.dep(1) * y);
208  }
209  // Simplifications
211  bool hit;
213  [](casadi_int op, const SXElem& a) { return unary(op, a);},
214  [](casadi_int op, const SXElem& a, const SXElem& b) { return binary(op, a, b);},
215  unique_x,
216  unique_y,
217  hit);
218  if (hit) return ret;
219  switch (op) {
220  case OP_MUL:
221  if (x.is_constant() && y.is_op(OP_TWICE))
222  return (x*2)*y.dep(); // a*(2*x) -> (a*2)*x
223  else if (y.is_constant() && x.is_op(OP_TWICE))
224  return (2*y)*x.dep(); // (2*x)*b -> (2*b)*x
225  break;
226  }
227 
228  }
229  return BinarySX::create(Operation(op), x, y);
230  }
231 
232  std::vector<SXElem> SXElem::call(const Function& f, const std::vector<SXElem>& deps) {
233  SXElem c = CallSX::create(f, deps);
234  return OutputSX::split(c, f.nnz_out());
235  }
236 
237  SXElem SXElem::unary(casadi_int op, const SXElem& x, bool unique) {
238  // Simplifications
240  switch (op) {
241  case OP_NOT:
242  if (x.is_op(OP_NOT))
243  return x.dep(); // This looks problematic
244  break;
245  case OP_TWICE:
246  if (x.is_op(OP_MUL) && x.dep(0).is_constant())
247  return (2*x.dep(0))*x.dep(1); // (2*a)*x = (2*a)*x
248  else if (x.is_op(OP_MUL) && x.dep(1).is_constant())
249  return (2*x.dep(1))*x.dep(0); // x*(2*a) = (2*a)*x
250  else if (x.is_op(OP_TWICE))
251  return 4*x.dep(); // 2*(2*x) = 4*x
252  break;
253  }
254  // Simplifications
255  bool hit;
257  [](casadi_int op, const SXElem& a) { return unary(op, a);},
258  unique,
259  hit);
260  if (hit) return ret;
261  }
262  return UnarySX::create(Operation(op), x);
263  }
264 
265  bool SXElem::is_leaf() const {
266  if (!node) return true;
267  return is_constant() || is_symbolic();
268  }
269 
270  bool SXElem::is_commutative() const {
271  casadi_assert(n_dep(), "SX::is_commutative: must be binary");
272  return operation_checker<CommChecker>(op());
273  }
274 
275  bool SXElem::is_constant() const {
276  return node->is_constant();
277  }
278 
279  bool SXElem::is_call() const {
280  return node->is_call();
281  }
282 
283  bool SXElem::is_output() const {
284  return node->is_output();
285  }
286 
287  bool SXElem::has_output() const {
288  return node->has_output();
289  }
290 
292  return node->which_function();
293  }
294 
295  casadi_int SXElem::which_output() const {
296  return node->which_output();
297  }
298 
299  bool SXElem::is_integer() const {
300  return node->is_integer();
301  }
302 
303  bool SXElem::is_symbolic() const {
304  return node->is_symbolic();
305  }
306 
307  bool SXElem::is_zero() const {
308  return node->is_zero();
309  }
310 
311  bool SXElem::is_almost_zero(double tol) const {
312  return node->is_almost_zero(tol);
313  }
314 
315  bool SXElem::is_one() const {
316  return node->is_one();
317  }
318 
319  bool SXElem::is_minus_one() const {
320  return node->is_minus_one();
321  }
322 
323  bool SXElem::is_half() const {
324  return node->is_half();
325  }
326 
327  bool SXElem::is_value(double val) const {
328  return node->is_value(val);
329  }
330 
331  bool SXElem::is_nan() const {
332  return node->is_nan();
333  }
334 
335  bool SXElem::is_inf() const {
336  return node->is_inf();
337  }
338 
339  bool SXElem::is_minus_inf() const {
340  return node->is_minus_inf();
341  }
342 
343  const std::string& SXElem::name() const {
344  return node->name();
345  }
346 
347  casadi_int SXElem::op() const {
348  return node->op();
349  }
350 
351  bool SXElem::is_op(casadi_int op) const {
352  return node->is_op(op);
353  }
354 
355  bool SXElem::is_equal(const SXElem& x, const SXElem& y, casadi_int depth) {
356  SXNode *x_node = x.get(), *y_node = y.get();
357  if (x_node==y_node) {
358  return true;
359  } else if (depth>0) {
360  return x_node->is_equal(y_node, depth);
361  } else {
362  return false;
363  }
364  }
365 
366  bool SXElem::is_nonnegative() const {
367  if (is_constant()) {
368  return static_cast<double>(*this)>=0;
369  } else if (casadi_math<SXElem>::is_unary(node->op())) {
370  return operation_checker<NonnegativeChecker>(node->op());
371  } else {
372  return false;
373  }
374  }
375 
376  SXElem::operator double() const {
377  return node->to_double();
378  }
379 
380  SXElem::operator casadi_int() const {
381  return node->to_int();
382  }
383 
384  SXElem SXElem::dep(casadi_int ch) const {
385  casadi_assert_dev(ch >= 0 || ch < n_dep());
386  return node->dep(ch);
387  }
388 
389  casadi_int SXElem::n_dep() const {
390  return node->n_dep();
391  }
392 
393  SXElem SXElem::get_output(casadi_int oind) const {
394  return node->get_output(oind);
395  }
396 
397  casadi_int SXElem::__hash__() const {
398  return reinterpret_cast<casadi_int>(node);
399  }
400 
401  // node corresponding to a constant 0
403  // node corresponding to a constant 1
405  // node corresponding to a constant 2
407  // node corresponding to a constant -1
412 
414  return val.is_zero();
415  }
416 
417  bool casadi_limits<SXElem>::is_equal(const SXElem& x, const SXElem& y, casadi_int depth) {
418  return SXElem::is_equal(x, y, depth);
419  }
420 
421  bool casadi_limits<SXElem>::is_almost_zero(const SXElem& val, double tol) {
422  return val.is_almost_zero(tol);
423  }
424 
426  return val.is_one();
427  }
428 
430  return val.is_minus_one();
431  }
432 
434  return val.is_half();
435  }
436 
437  bool casadi_limits<SXElem>::is_value(const SXElem& val, double v) {
438  return val.is_value(v);
439  }
440 
442  return val.is_nonnegative();
443  }
444 
446  return val.is_constant();
447  }
448 
450  return val.is_integer();
451  }
452 
454  return val.is_inf();
455  }
456 
458  return val.is_minus_inf();
459  }
460 
462  return val.is_nan();
463  }
464 
465  SXElem::operator SX() const {
466  return SX(Sparsity::scalar(), *this, false);
467  }
468 
469  int SXElem::get_temp() const {
470  return (*this)->temp;
471  }
472 
473  void SXElem::set_temp(int t) const {
474  (*this)->temp = t;
475  }
476 
477  bool SXElem::marked() const {
478  return (*this)->marked();
479  }
480 
481  void SXElem::mark() const {
482  (*this)->mark();
483  }
484 
485  bool SXElem::is_regular() const {
486  if (is_constant()) {
487  return !(is_nan() || is_inf() || is_minus_inf());
488  } else {
489  casadi_error("Cannot check regularity for symbolic SXElem");
490  }
491  }
492 
494  (*this)->serialize(s);
495  }
496 
499  }
500 
501 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
502  std::mutex SXElem::mutex_temp;
503 #endif //CASADI_WITH_THREADSAFE_SYMBOLICS
504 
505 } // namespace casadi
506 
507 using namespace casadi;
508 namespace std {
509  SXElem std::numeric_limits<SXElem>::infinity() throw() {
511  }
512 
513  SXElem std::numeric_limits<SXElem>::quiet_NaN() throw() {
515  }
516 
517  SXElem std::numeric_limits<SXElem>::min() throw() {
518  return SXElem(std::numeric_limits<double>::min());
519  }
520 
521  SXElem std::numeric_limits<SXElem>::max() throw() {
522  return SXElem(std::numeric_limits<double>::max());
523  }
524 
525  SXElem std::numeric_limits<SXElem>::epsilon() throw() {
526  return SXElem(std::numeric_limits<double>::epsilon());
527  }
528 
529  SXElem std::numeric_limits<SXElem>::round_error() throw() {
530  return SXElem(std::numeric_limits<double>::round_error());
531  }
532 
533 } // 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:1007
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:493
bool is_nan() const
Definition: sx_elem.cpp:331
void set_temp(int t) const
Set the temporary variable.
Definition: sx_elem.cpp:473
bool is_zero() const
Definition: sx_elem.cpp:307
bool is_output() const
Definition: sx_elem.cpp:283
void assignIfDuplicate(const SXElem &scalar, casadi_int depth=1)
Assign to another expression, if a duplicate.
Definition: sx_elem.cpp:117
bool is_regular() const
Checks if expression does not contain NaN or Inf.
Definition: sx_elem.cpp:485
SXElem dep(casadi_int ch=0) const
Definition: sx_elem.cpp:384
bool marked() const
Check if marked (i.e. temporary is negative)
Definition: sx_elem.cpp:477
bool is_half() const
Definition: sx_elem.cpp:323
void disp(std::ostream &stream, bool more=false) const
Print a description of the object.
Definition: sx_elem.cpp:146
bool is_call() const
Definition: sx_elem.cpp:279
bool __nonzero__() const
Check the truth value of this node.
Definition: sx_elem.cpp:163
static std::vector< SXElem > call(const Function &f, const std::vector< SXElem > &deps)
Definition: sx_elem.cpp:232
bool is_value(double val) const
Definition: sx_elem.cpp:327
~SXElem()
Destructor.
Definition: sx_elem.cpp:98
bool is_minus_inf() const
Definition: sx_elem.cpp:339
bool has_output() const
Definition: sx_elem.cpp:287
bool is_leaf() const
check if this SXElem is a leaf of the SX graph
Definition: sx_elem.cpp:265
SXElem inv() const
Element-wise inverse.
Definition: sx_elem.cpp:173
bool is_symbolic() const
Definition: sx_elem.cpp:303
static SXElem create(SXNode *node)
Definition: sx_elem.cpp:62
bool is_minus_one() const
Definition: sx_elem.cpp:319
const SXNode * operator->() const
Access functions of the node.
Definition: sx_elem.cpp:181
SXElem operator-() const
Negation.
Definition: sx_elem.cpp:150
void mark() const
Mark by flipping the sign of the temporary and decreasing by one.
Definition: sx_elem.cpp:481
static SXElem unary(casadi_int op, const SXElem &x, bool unique=false)
Definition: sx_elem.cpp:237
bool is_integer() const
Definition: sx_elem.cpp:299
Function which_function() const
Definition: sx_elem.cpp:291
SXElem get_output(casadi_int oind) const
Get an output.
Definition: sx_elem.cpp:393
int get_temp() const
Definition: sx_elem.cpp:469
bool is_doubled() const
Check if the node is the sum of two equal expressions.
Definition: sx_elem.cpp:168
casadi_int op() const
Definition: sx_elem.cpp:347
bool is_commutative() const
Check whether a binary SXElem is commutative.
Definition: sx_elem.cpp:270
bool is_constant() const
Definition: sx_elem.cpp:275
SXNode * assignNoDelete(const SXElem &scalar)
Assign the node to something, without invoking the deletion of the node,.
Definition: sx_elem.cpp:124
bool is_almost_zero(double tol) const
Definition: sx_elem.cpp:311
bool is_op(casadi_int op) const
Definition: sx_elem.cpp:351
SXNode * get() const
Get a pointer to the node.
Definition: sx_elem.cpp:177
static SXElem deserialize(DeserializingStream &s)
Definition: sx_elem.cpp:497
casadi_int which_output() const
Definition: sx_elem.cpp:295
bool is_one() const
Definition: sx_elem.cpp:315
const std::string & name() const
Definition: sx_elem.cpp:343
casadi_int __hash__() const
Returns a number that is unique for a given SXNode.
Definition: sx_elem.cpp:397
casadi_int n_dep() const
Get the number of dependencies of a binary SXElem.
Definition: sx_elem.cpp:389
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:355
static SXElem binary(casadi_int op, const SXElem &x, const SXElem &y, bool unique_x=false, bool unique_y=false)
Perform operations by ID.
Definition: sx_elem.cpp:189
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:94
SXElem & operator=(const SXElem &scalar)
Assignment.
Definition: sx_elem.cpp:102
bool is_inf() const
Definition: sx_elem.cpp:335
bool is_nonnegative() const
Check if a value is always nonnegative (false negatives are allowed)
Definition: sx_elem.cpp:366
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_half() const
check properties of a node
Definition: sx_node.hpp:77
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:126
virtual bool is_value(double val) const
check properties of a node
Definition: sx_node.hpp:78
virtual bool is_nan() const
check properties of a node
Definition: sx_node.hpp:79
virtual bool is_call() const
check properties of a node
Definition: sx_node.hpp:82
unsigned int count
Definition: sx_node.hpp:199
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 bool is_inf() const
check properties of a node
Definition: sx_node.hpp:80
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:83
static casadi_int eq_depth_
Definition: sx_node.hpp:181
virtual casadi_int op() const =0
get the operation
virtual bool has_output() const
check properties of a node
Definition: sx_node.hpp:84
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:81
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_nonnegative(const T &val)
static bool is_equal(const T &x, const T &y, casadi_int depth)
static bool is_half(const T &val)
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_value(const T &val, T v)
static bool is_zero(const T &val)
static SXElem if_else_zero(const SXElem &x, const SXElem &y)
Conditional assignment: (x,y) -> x ? y : 0.
The casadi namespace.
Definition: archiver.cpp:28
Matrix< SXElem > SX
Definition: sx_fwd.hpp:32
T common_simp_binary(casadi_int op, const T &x, const T &y, casadi_int depth, SU &&gen_unary, SB &&gen_binary, bool unique_x, bool unique_y, bool &hit)
Definition: calculus.hpp:1871
T common_simp_unary(casadi_int op, const T &x, casadi_int depth, SU &&gen_unary, bool unique, bool &hit)
Definition: calculus.hpp:1813
Operation
Enum for quick access to any node.
Definition: calculus.hpp:60
@ OP_IF_ELSE_ZERO
Definition: calculus.hpp:71
@ OP_INV
Definition: calculus.hpp:73
@ OP_TWICE
Definition: calculus.hpp:67
@ OP_ADD
Definition: calculus.hpp:65
@ OP_NEG
Definition: calculus.hpp:66
@ OP_NOT
Definition: calculus.hpp:70
@ OP_MUL
Definition: calculus.hpp:65
Definition: sx_elem.cpp:508
Easy access to all the functions for a particular type.
Definition: calculus.hpp:1135