26 #ifndef CASADI_BINARY_MX_IMPL_HPP
27 #define CASADI_BINARY_MX_IMPL_HPP
29 #include "binary_mx.hpp"
30 #include "casadi_misc.hpp"
31 #include "global_options.hpp"
32 #include "serializing_stream.hpp"
38 template<
bool ScX,
bool ScY>
39 BinaryMX<ScX, ScY>::BinaryMX(Operation op,
const MX& x,
const MX& y) : op_(op) {
42 set_sparsity(y.sparsity());
44 set_sparsity(x.sparsity());
48 template<
bool ScX,
bool ScY>
49 BinaryMX<ScX, ScY>::~BinaryMX() {
52 template<
bool ScX,
bool ScY>
53 std::string BinaryMX<ScX, ScY>::disp(
const std::vector<std::string>& arg)
const {
54 return casadi_math<double>::print(op_, arg.at(0), arg.at(1));
57 template<
bool ScX,
bool ScY>
58 bool BinaryMX<ScX, ScY>::is_nonnegative()
const {
59 return operation_checker<NonnegativeChecker>(op_);
62 template<
bool ScX,
bool ScY>
63 void BinaryMX<ScX, ScY>::eval_mx(
const std::vector<MX>& arg, std::vector<MX>& res,
64 const std::vector<bool>& unique)
const {
65 bool unique_x = !unique.empty() && unique[0];
66 bool unique_y = unique.size() >= 2 && unique[1];
67 res[0] = MX::binary(op_, arg[0], arg[1], unique_x, unique_y);
70 template<
bool ScX,
bool ScY>
71 void BinaryMX<ScX, ScY>::eval_linear(
const std::vector<std::array<MX, 3> >& arg,
72 std::vector<std::array<MX, 3> >& res)
const {
73 casadi_math<MX>::fun_linear(op_, arg[0].data(), arg[1].data(), res[0].data());
76 template<
bool ScX,
bool ScY>
77 void BinaryMX<ScX, ScY>::ad_forward(
const std::vector<std::vector<MX> >& fseed,
78 std::vector<std::vector<MX> >& fsens)
const {
81 casadi_math<MX>::der(op_, dep(0), dep(1), shared_from_this<MX>(), pd);
84 for (casadi_int d=0; d<fsens.size(); ++d) {
85 if (op_ == OP_IF_ELSE_ZERO) {
86 fsens[d][0] = if_else_zero(pd[1], fseed[d][1]);
88 fsens[d][0] = pd[0]*fseed[d][0] + pd[1]*fseed[d][1];
93 template<
bool ScX,
bool ScY>
94 void BinaryMX<ScX, ScY>::ad_reverse(
const std::vector<std::vector<MX> >& aseed,
95 std::vector<std::vector<MX> >& asens)
const {
98 casadi_math<MX>::der(op_, dep(0), dep(1), shared_from_this<MX>(), pd);
101 for (casadi_int d=0; d<aseed.size(); ++d) {
103 if (op_ == OP_IF_ELSE_ZERO) {
105 if (!s.is_scalar() && dep(1).is_scalar()) {
106 asens[d][1] += dot(dep(0), s);
108 asens[d][1] += if_else_zero(dep(0), s);
112 for (casadi_int c=0; c<2; ++c) {
117 if (!t.is_scalar() && t.size() != dep(c).size()) {
118 if (pd[c].size()!=s.size()) pd[c] = MX(s.sparsity(), pd[c]);
129 template<
bool ScX,
bool ScY>
130 void BinaryMX<ScX, ScY>::
131 generate(CodeGenerator& g,
132 const std::vector<casadi_int>& arg,
const std::vector<casadi_int>& res,
133 const std::vector<bool>& arg_is_ref, std::vector<bool>& res_is_ref)
const {
135 if (nnz()==0)
return;
144 inplace = res[0]==arg[0] && !arg_is_ref[0];
152 std::string r = g.workel(res[0]);
153 std::string x = g.workel(arg[0]);
154 std::string y = g.workel(arg[1]);
157 if (op_==OP_DIV && g.codegen_scalars && dep(1).nnz()==1) {
164 g.local(
"rr",
"casadi_real",
"*");
165 g.local(
"i",
"casadi_int");
166 g <<
"for (i=0, " <<
"rr=" << g.work(res[0], nnz(),
false);
170 if (!ScX && !inplace) {
171 g.local(
"cr",
"const casadi_real",
"*");
172 g <<
", cr=" << g.work(arg[0], dep(0).nnz(), arg_is_ref[0]);
173 if (op_==OP_OR || op_==OP_AND) {
184 g.local(
"cs",
"const casadi_real",
"*");
185 g <<
", cs=" << g.work(arg[1], dep(1).nnz(), arg_is_ref[1]);
186 if (op_==OP_OR || op_==OP_AND || op_==OP_IF_ELSE_ZERO) {
195 g <<
"; i<" << nnz() <<
"; ++i) ";
201 g << casadi_math<double>::sep(op_) <<
"= " << y;
203 g <<
" = " << g.print_op(op_, x, y);
208 template<
bool ScX,
bool ScY>
209 int BinaryMX<ScX, ScY>::
210 eval(
const double** arg,
double** res, casadi_int* iw,
double* w)
const {
211 return eval_gen<double>(arg, res, iw, w);
214 template<
bool ScX,
bool ScY>
215 int BinaryMX<ScX, ScY>::
216 eval_sx(
const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w)
const {
217 return eval_gen<SXElem>(arg, res, iw, w);
220 template<
bool ScX,
bool ScY>
222 int BinaryMX<ScX, ScY>::
223 eval_gen(
const T*
const* arg, T*
const* res, casadi_int* iw, T* w)
const {
226 const T* input0 = arg[0];
227 const T* input1 = arg[1];
230 casadi_math<T>::fun(op_, input0, input1, output0, nnz());
232 casadi_math<T>::fun(op_, *input0, input1, output0, nnz());
234 casadi_math<T>::fun(op_, input0, *input1, output0, nnz());
239 template<
bool ScX,
bool ScY>
240 int BinaryMX<ScX, ScY>::
241 sp_forward(
const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w)
const {
242 const bvec_t *a0=arg[0], *a1=arg[1];
245 for (casadi_int i=0; i<n; ++i) {
248 else if (ScX && !ScY)
250 else if (!ScX && ScY)
253 *r++ = *a0++ | *a1++;
258 template<
bool ScX,
bool ScY>
259 int BinaryMX<ScX, ScY>::
260 eval_activity(
const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w)
const {
262 const bool f00 = operation_checker<F00Checker>(op_);
263 const bool f0x = operation_checker<F0XChecker>(op_);
264 const bool fx0 = operation_checker<FX0Checker>(op_);
265 const bvec_t nz = ~static_cast<bvec_t>(0);
266 const bvec_t *a0=arg[0], *a1=arg[1];
269 for (casadi_int i=0; i<n; ++i) {
270 const bool z0 = (*a0)!=0;
271 const bool z1 = (*a1)!=0;
273 if (!z0 && !z1) out = f00 ? 0 : nz;
274 else if (!z0 && z1) out = f0x ? 0 : nz;
275 else if ( z0 && !z1) out = fx0 ? 0 : nz;
284 template<
bool ScX,
bool ScY>
285 int BinaryMX<ScX, ScY>::
286 sp_reverse(bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w)
const {
287 bvec_t *a0=arg[0], *a1=arg[1], *r = res[0];
289 for (casadi_int i=0; i<n; ++i) {
304 template<
bool ScX,
bool ScY>
305 MX BinaryMX<ScX, ScY>::_get_binary(casadi_int op,
const MX& y,
bool scX,
bool scY,
306 bool unique_x,
bool unique_y)
const {
307 if (!GlobalOptions::simplification_on_the_fly)
308 return MXNode::_get_binary(op, y, scX, scY, unique_x, unique_y);
312 if (op==OP_SUB && MX::is_equal(y, dep(0), maxDepth()))
return dep(1);
313 if (op==OP_SUB && MX::is_equal(y, dep(1), maxDepth()))
return dep(0);
316 if (op==OP_SUB && MX::is_equal(y, dep(0), maxDepth()))
return -dep(1);
317 if (op==OP_ADD && MX::is_equal(y, dep(1), maxDepth()))
return dep(0);
323 return MXNode::_get_binary(op, y, scX, scY, unique_x, unique_y);
326 template<
bool ScX,
bool ScY>
327 void BinaryMX<ScX, ScY>::serialize_body(SerializingStream& s)
const {
328 MXNode::serialize_body(s);
329 s.pack(
"BinaryMX::op",
static_cast<int>(op_));
332 template<
bool ScX,
bool ScY>
333 void BinaryMX<ScX, ScY>::serialize_type(SerializingStream& s)
const {
334 MXNode::serialize_type(s);
337 char type = type_x | (type_y << 1);
338 s.pack(
"BinaryMX::scalar_flags", type);
341 template<
bool ScX,
bool ScY>
342 MXNode* BinaryMX<ScX, ScY>::deserialize(DeserializingStream& s) {
344 s.unpack(
"BinaryMX::scalar_flags", t);
349 if (scY)
return new BinaryMX<true, true>(s);
350 return new BinaryMX<true, false>(s);
352 if (scY)
return new BinaryMX<false, true>(s);
353 return new BinaryMX<false, false>(s);
357 template<
bool ScX,
bool ScY>
358 BinaryMX<ScX, ScY>::BinaryMX(DeserializingStream& s) : MXNode(s) {
360 s.unpack(
"BinaryMX::op", op);
364 template<
bool ScX,
bool ScY>
365 MX BinaryMX<ScX, ScY>::get_solve_triu(
const MX& r,
bool tr)
const {
367 if (!ScX && !ScY && op_ == OP_SUB) {
369 if (dep(0).is_op(OP_PROJECT) && dep(0).dep(0).is_eye()) {
371 if (dep(1).is_op(OP_PROJECT) && dep(1).dep(0).sparsity().is_triu(
true)) {
372 return dep(1).dep(0)->get_solve_triu_unity(r, tr);
377 return MXNode::get_solve_triu(r, tr);
380 template<
bool ScX,
bool ScY>
381 MX BinaryMX<ScX, ScY>::get_solve_tril(
const MX& r,
bool tr)
const {
383 if (!ScX && !ScY && op_ == OP_SUB) {
385 if (dep(0).is_op(OP_PROJECT) && dep(0).dep(0).is_eye()) {
387 if (dep(1).is_op(OP_PROJECT) && dep(1).dep(0).sparsity().is_tril(
true)) {
388 return dep(1).dep(0)->get_solve_tril_unity(r, tr);
393 return MXNode::get_solve_tril(r, tr);