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