1 // 2 // func.h 3 // Gravity 4 // 5 // Created by Hijazi, Hassan on 25 Oct 18. 6 // 7 // 8 9 #ifndef expr_h 10 #define expr_h 11 12 #include <gravity/poly.h> 13 #include <stdio.h> 14 #include <map> 15 #include <iterator> 16 #include <queue> 17 #include <list> 18 #include <limits> 19 #include <set> 20 21 using namespace std; 22 23 string operator_str(gravity::OperatorType ot); 24 25 namespace gravity { 26 class func_; 27 /** Backbone class for unary and binary expressions. */ 28 template<typename type = double> 29 class expr: public constant_{ 30 protected: 31 public: 32 type _coef = unit<type>().eval(); /**< coefficient multpying the expression */ 33 Convexity _all_convexity = linear_; /**< If all instances of this expression have the same convexity type, it stores it here, i.e. linear, convex, concave, otherwise it stores unknown. >>**/ 34 Sign _all_sign = zero_; /**< If all instances of this expression have the same sign, it stores it here, otherwise it stores unknown. >>**/ 35 36 shared_ptr<pair<type,type>> _range; /**< (Min,Max) values of expression **/ 37 string _to_str; /**< A string representation of the expression */ 38 in(const indices & ids)39 virtual void in(const indices& ids){}; get_lson()40 virtual shared_ptr<constant_> get_lson() const {return nullptr;}; get_rson()41 virtual shared_ptr<constant_> get_rson() const {return nullptr;}; scale_coefs(double unit)42 virtual void scale_coefs(double unit){}; scale_vars(double unit)43 virtual void scale_vars(double unit){}; uneval()44 virtual void uneval(){}; update_double_index()45 virtual void update_double_index(){}; propagate_dim(size_t d)46 void propagate_dim(size_t d){ 47 if(_is_transposed){ 48 _dim[1] = d; 49 } 50 else { 51 _dim[0] = d; 52 } 53 } 54 reverse_sign()55 void reverse_sign(){ _coef *= -1.; }; 56 }; 57 58 59 /** Class uexpr (unary expression), stores a unary expression tree. */ 60 template<typename type = double> 61 class uexpr: public expr<type>{ 62 63 public: 64 OperatorType _otype = id_; 65 shared_ptr<constant_> _son = nullptr; 66 67 68 reset()69 void reset(){ 70 _son = nullptr; 71 _otype = id_; 72 this->_to_str = "noname"; 73 this->_coef = 1.; 74 }; 75 76 get_otype()77 OperatorType get_otype() const{ 78 return _otype; 79 }; 80 81 /** Operators */ 82 copy()83 shared_ptr<constant_> copy()const{return make_shared<uexpr>(*this);}; 84 85 86 bool operator!=(const uexpr& c) const{ 87 return !(*this==c); 88 }; 89 propagate_dim(size_t d)90 void propagate_dim(size_t d){ 91 if(this->_is_transposed){ 92 this->_dim[1] = d; 93 } 94 else { 95 this->_dim[0] = d; 96 } 97 _son->propagate_dim(d); 98 } 99 update_double_index()100 void update_double_index(){ 101 _son->update_double_index(); 102 } 103 104 // template<typename T=type, 105 // typename std::enable_if<is_same<T,double>::value>::type* = nullptr> 106 // void scale_vars(double unit){ 107 // if(_son->is_function()){ 108 // auto f = static_pointer_cast<func<type>>(_son); 109 // f->scale_vars(unit); 110 // } 111 // else{ 112 // /* TODO: param or var cases */ 113 // } 114 // }; 115 // 116 // template<typename T=type, 117 // typename std::enable_if<is_same<T,double>::value>::type* = nullptr> 118 // void scale_coefs(double unit){ 119 // if(_son->is_function()){ 120 // auto f = static_pointer_cast<func<type>>(_son); 121 // f->scale_coefs(unit); 122 // } 123 // else{ 124 // /* TODO: param or var cases */ 125 // } 126 // }; 127 uneval()128 void uneval(){ 129 _son->uneval(); 130 } 131 132 /** allocates memory for current and all sub-functions */ allocate_mem()133 void allocate_mem(){ 134 _son->allocate_mem(); 135 }; 136 in(const indices & ids)137 void in(const indices& ids){ 138 if(_son->is_function()){ 139 auto f = static_pointer_cast<func<type>>(_son); 140 f->in(ids); 141 } 142 }; 143 get_all_sign()144 Sign get_all_sign() const{ 145 return unknown_;// TO UPDATE 146 } 147 148 template<class T2, typename enable_if<is_convertible<T2, type>::value && sizeof(T2) < sizeof(type)>::type* = nullptr> 149 uexpr(const uexpr<T2>& exp){ 150 *this = exp; 151 } 152 153 template<class T2, typename enable_if<is_convertible<T2, type>::value && sizeof(T2) < sizeof(type)>::type* = nullptr> 154 uexpr(uexpr<T2>&& exp){ 155 *this = move(exp); 156 } 157 uexpr(const uexpr & exp)158 uexpr(const uexpr& exp){ 159 *this = exp; 160 } 161 uexpr(uexpr && exp)162 uexpr(uexpr&& exp){ 163 *this = move(exp); 164 } 165 uexpr(OperatorType ot,shared_ptr<constant_> son)166 uexpr(OperatorType ot, shared_ptr<constant_> son){ 167 _otype = ot; 168 _son = son; 169 this->_range = make_shared<pair<type,type>>(); 170 this->_type = uexp_c; 171 this->_dim[0] = son->_dim[0]; 172 this->_dim[1] = son->_dim[1]; 173 this->_to_str = this->to_str(); 174 this->_is_vector = son->_is_vector; 175 this->_is_transposed = son->_is_transposed; 176 } 177 178 template<class T2, typename enable_if<is_convertible<T2, type>::value && sizeof(T2) < sizeof(type)>::type* = nullptr> 179 uexpr& operator=(uexpr<T2>&& exp){ 180 this->_type = uexp_c; 181 _son = move(exp._son); 182 _otype = exp._otype; 183 this->_all_convexity = exp._all_convexity; 184 this->_all_sign = exp._all_sign; 185 if(exp._range){ 186 this->_range = make_shared<pair<type,type>>(); 187 this->_range->first = exp._range->first; 188 this->_range->second = exp._range->second; 189 } 190 this->_to_str = exp._to_str; 191 this->_coef = exp._coef; 192 this->_is_vector = exp._is_vector; 193 this->_is_transposed = exp._is_transposed; 194 this->_dim[0] = exp._dim[0]; this->_dim[1] = exp._dim[1]; 195 return *this; 196 } 197 198 199 uexpr& operator=(uexpr&& exp){ 200 this->_type = uexp_c; 201 _son = move(exp._son); 202 _otype = exp._otype; 203 this->_all_convexity = exp._all_convexity; 204 this->_all_sign = exp._all_sign; 205 this->_range = move(exp._range); 206 this->_to_str = exp._to_str; 207 this->_coef = exp._coef; 208 this->_is_vector = exp._is_vector; 209 this->_is_transposed = exp._is_transposed; 210 this->_dim[0] = exp._dim[0]; this->_dim[1] = exp._dim[1]; 211 return *this; 212 } 213 214 bool operator==(const uexpr &c)const{ 215 // return (_otype == c._otype && equals(_son,c._son)); 216 return (this->_to_str.compare(c._to_str)==0); 217 } 218 219 220 221 222 /* UNARY EXPRESSIONS */ 223 uexpr()224 uexpr(){ 225 this->_type = uexp_c; 226 this->_range = make_shared<pair<type,type>>(); 227 } 228 print()229 void print() { 230 cout << this->_to_str << endl; 231 } 232 233 234 template<class T2, typename enable_if<is_convertible<T2, type>::value && sizeof(T2) < sizeof(type)>::type* = nullptr> 235 uexpr& operator=(const uexpr<T2>& exp){ 236 this->_type = uexp_c; 237 _son = exp._son->copy(); 238 _otype = exp._otype; 239 this->_all_convexity = exp._all_convexity; 240 this->_all_sign = exp._all_sign; 241 if(exp._range){ 242 this->_range = make_shared<pair<type,type>>(); 243 this->_range->first = exp._range->first; 244 this->_range->second = exp._range->second; 245 } 246 this->_to_str = exp._to_str; 247 this->_coef = exp._coef; 248 this->_is_vector = exp._is_vector; 249 this->_is_transposed = exp._is_transposed; 250 this->_dim[0] = exp._dim[0]; this->_dim[1] = exp._dim[1]; 251 return *this; 252 } 253 254 uexpr& operator=(const uexpr& exp){ 255 this->_type = uexp_c; 256 _son = exp._son->copy(); 257 _otype = exp._otype; 258 this->_all_convexity = exp._all_convexity; 259 this->_all_sign = exp._all_sign; 260 if(exp._range){ 261 this->_range = make_shared<pair<type,type>>(); 262 this->_range->first = exp._range->first; 263 this->_range->second = exp._range->second; 264 } 265 this->_to_str = exp._to_str; 266 this->_coef = exp._coef; 267 this->_is_vector = exp._is_vector; 268 this->_is_transposed = exp._is_transposed; 269 this->_dim[0] = exp._dim[0]; this->_dim[1] = exp._dim[1]; 270 return *this; 271 } 272 to_str()273 string to_str(){ 274 string str; 275 if (this->_coef!=unit<type>().eval()) { 276 if (this->_coef!=-1.*unit<type>().eval()) { 277 str+= to_string_with_precision(this->_coef,3); 278 } 279 else { 280 str+= "-"; 281 } 282 } 283 str += operator_str(_otype) +"("+_son->to_str()+")"; 284 return str; 285 } 286 287 to_str(int prec)288 string to_str(int prec){ 289 string str; 290 if (this->_coef!=unit<type>().eval()) { 291 if (this->_coef!=-1.*unit<type>().eval()) { 292 str+= to_string_with_precision(this->_coef,prec); 293 } 294 else { 295 str+= "-"; 296 } 297 } 298 str += operator_str(_otype) +"("+_son->to_str(prec)+")"; 299 return str; 300 } 301 to_str(size_t inst,int prec)302 string to_str(size_t inst, int prec) { 303 string str; 304 if (this->_coef!=unit<type>().eval()) { 305 if (this->_coef!=-1.*unit<type>().eval()) { 306 str+= to_string_with_precision(this->_coef,prec); 307 } 308 else { 309 str+= "-"; 310 } 311 } 312 str += operator_str(_otype) +"("+_son->to_str(inst,prec)+")"; 313 return str; 314 } 315 to_str(size_t inst1,size_t inst2,int prec)316 string to_str(size_t inst1, size_t inst2, int prec) { 317 string str; 318 if (this->_coef!=unit<type>().eval()) { 319 if (this->_coef!=-1.*unit<type>().eval()) { 320 str+= to_string_with_precision(this->_coef,prec); 321 } 322 else { 323 str+= "-"; 324 } 325 } 326 str += operator_str(_otype) +"("+_son->to_str(inst1,inst2,prec)+")"; 327 return str; 328 } 329 330 }; 331 332 template<typename type = double> 333 class bexpr: public expr<type>{ 334 private: 335 336 public: 337 OperatorType _otype = id_; 338 shared_ptr<constant_> _lson = nullptr; 339 shared_ptr<constant_> _rson = nullptr; 340 341 342 bexpr()343 bexpr(){ 344 this->_type = bexp_c; 345 this->_to_str = "noname"; 346 this->_range = make_shared<pair<type,type>>(); 347 } 348 get_lson()349 shared_ptr<constant_> get_lson() const {return _lson;}; get_rson()350 shared_ptr<constant_> get_rson() const {return _rson;}; 351 352 template<class T2, typename enable_if<is_convertible<T2, type>::value && sizeof(T2) < sizeof(type)>::type* = nullptr> 353 bexpr(const bexpr<T2>& exp){ /**< Copy constructor from binary expression tree */ 354 *this = exp; 355 }; 356 bexpr(const bexpr & exp)357 bexpr(const bexpr& exp){ /**< Copy constructor from binary expression tree */ 358 *this = exp; 359 }; 360 361 362 template<class T2, typename enable_if<is_convertible<T2, type>::value && sizeof(T2) < sizeof(type)>::type* = nullptr> 363 bexpr(bexpr<T2>&& exp){ /**< Move constructor from binary expression tree */ 364 *this = move(exp); 365 }; 366 bexpr(bexpr && exp)367 bexpr(bexpr&& exp){ /**< Move constructor from binary expression tree */ 368 *this = move(exp); 369 }; 370 371 template<class T2, typename enable_if<is_convertible<T2, type>::value && sizeof(T2) < sizeof(type)>::type* = nullptr> 372 bexpr& operator=(bexpr<T2>&& exp){ 373 this->_type = bexp_c; 374 _lson = move(exp._lson); 375 _rson = move(exp._rson); 376 _otype = exp._otype; 377 this->_all_convexity = exp._all_convexity; 378 this->_all_sign = exp._all_sign; 379 if(exp._range){ 380 this->_range = make_shared<pair<type,type>>(); 381 this->_range->first = exp._range->first; 382 this->_range->second = exp._range->second; 383 } 384 this->_to_str = exp._to_str; 385 this->_coef = exp._coef; 386 this->_is_vector = exp._is_vector; 387 this->_is_transposed = exp._is_transposed; 388 this->_dim[0] = exp._dim[0]; this->_dim[1] = exp._dim[1]; 389 return *this; 390 } 391 392 bexpr& operator=(bexpr&& exp){ 393 this->_type = bexp_c; 394 _lson = move(exp._lson); 395 _rson = move(exp._rson); 396 _otype = exp._otype; 397 this->_all_convexity = exp._all_convexity; 398 this->_all_sign = exp._all_sign; 399 this->_range = move(exp._range); 400 this->_to_str = exp._to_str; 401 this->_coef = exp._coef; 402 this->_is_vector = exp._is_vector; 403 this->_is_transposed = exp._is_transposed; 404 this->_dim[0] = exp._dim[0]; this->_dim[1] = exp._dim[1]; 405 return *this; 406 } 407 408 bool operator==(const bexpr &c)const{ 409 // return (_otype == c._otype && equals(_lson,c._lson) && equals(_rson,c._rson)); 410 return (this->_to_str.compare(c._to_str)==0); 411 } 412 413 // void scale_vars(double unit){ 414 // if(_lson->is_function()){ 415 // auto f = static_pointer_cast<func<type>>(_lson); 416 // f->scale_vars(unit); 417 // } 418 // else { 419 // /* TODO: param/var cases */ 420 // } 421 // if(_rson->is_function()){ 422 // auto f = static_pointer_cast<func<type>>(_rson); 423 // f->scale_vars(unit); 424 // } 425 // else { 426 // /* TODO: param/var cases */ 427 // } 428 // }; 429 430 // void scale_coefs(double unit){ 431 // if(_lson->is_function()){ 432 // auto f = static_pointer_cast<func<type>>(_lson); 433 // f->scale_coefs(unit); 434 // } 435 // else { 436 // /* TODO: param/var cases */ 437 // } 438 // if(_rson->is_function()){ 439 // auto f = static_pointer_cast<func<type>>(_rson); 440 // f->scale_coefs(unit); 441 // } 442 // else { 443 // /* TODO: param/var cases */ 444 // } 445 // }; 446 in(const indices & ids)447 void in(const indices& ids){ 448 if(_lson->is_function()){ 449 auto f = static_pointer_cast<func<type>>(_lson); 450 f->in(ids); 451 } 452 if(_rson->is_function()){ 453 auto f = static_pointer_cast<func<type>>(_rson); 454 f->in(ids); 455 } 456 }; 457 update_double_index()458 void update_double_index(){ 459 _lson->update_double_index(); 460 _rson->update_double_index(); 461 } 462 propagate_dim(size_t d)463 void propagate_dim(size_t d){ 464 if(this->_is_transposed){ 465 this->_dim[1] = d; 466 } 467 else { 468 this->_dim[0] = d; 469 } 470 _lson->propagate_dim(d); 471 _rson->propagate_dim(d); 472 } 473 uneval()474 void uneval(){ 475 _lson->uneval(); 476 _rson->uneval(); 477 } 478 479 /** allocates memory for current and all sub-functions */ allocate_mem()480 void allocate_mem(){ 481 _lson->allocate_mem(); 482 _rson->allocate_mem(); 483 }; 484 print()485 void print() { 486 cout << this->_to_str << endl; 487 } 488 to_str()489 string to_str() { 490 string str; 491 if (this->_coef!=unit<type>().eval()) { 492 if (this->_coef!=-1.*unit<type>().eval()) { 493 str+= to_string_with_precision(this->_coef, 3); 494 } 495 else { 496 str+= "-"; 497 } 498 str+="("; 499 } 500 if(_otype==min_){ 501 str += "min("+_lson->to_str()+", "+_rson->to_str()+")"; 502 } 503 else if(_otype==max_){ 504 str += "max("+_lson->to_str()+", "+_rson->to_str()+")"; 505 } 506 else { 507 if((_otype==product_ || _otype==div_) && (_lson->get_type()==uexp_c || _lson->get_type()==bexp_c)) { 508 str += "("; 509 str+= _lson->to_str(); 510 str += ")"; 511 } 512 else 513 str+= _lson->to_str(); 514 515 if (_otype==plus_) { 516 str+= " + "; 517 } 518 if (_otype==minus_) { 519 str+= " - "; 520 } 521 if (_otype==product_) { 522 str+= " * "; 523 } 524 if (_otype==div_) { 525 str+= "/"; 526 } 527 528 if (_otype==power_) { 529 str+= "^"; 530 } 531 532 if (_otype==plus_ || (_rson->get_type()!=uexp_c && _rson->get_type()!=bexp_c)) { 533 str+= _rson->to_str(); 534 } 535 else { 536 str+= "("; 537 str+= _rson->to_str(); 538 str+= ")"; 539 } 540 } 541 if (this->_coef!=unit<type>().eval()) { 542 str += ")"; 543 } 544 return str; 545 } 546 to_str(int prec)547 string to_str(int prec) { 548 string str; 549 if (this->_coef!=unit<type>().eval()) { 550 if (this->_coef!=-1.*unit<type>().eval()) { 551 str+= to_string_with_precision(this->_coef, prec); 552 } 553 else { 554 str+= "-"; 555 } 556 str+="("; 557 } 558 if((_otype==product_ || _otype==div_) && (_lson->get_type()==uexp_c || _lson->get_type()==bexp_c)) { 559 str += "("; 560 str+= _lson->to_str(prec); 561 str += ")"; 562 } 563 else 564 str+= _lson->to_str(prec); 565 566 if (_otype==plus_) { 567 str+= " + "; 568 } 569 if (_otype==minus_) { 570 str+= " - "; 571 } 572 if (_otype==product_) { 573 str+= " * "; 574 } 575 if (_otype==div_) { 576 str+= "/"; 577 } 578 579 if (_otype==power_) { 580 str+= "^"; 581 } 582 583 if (_otype==plus_ || (_rson->get_type()!=uexp_c && _rson->get_type()!=bexp_c)) { 584 str+= _rson->to_str(prec); 585 } 586 else { 587 str+= "("; 588 str+= _rson->to_str(prec); 589 str+= ")"; 590 } 591 if (this->_coef!=unit<type>().eval()) { 592 str += ")"; 593 } 594 return str; 595 } 596 print_transposed(size_t inst,int prec)597 string print_transposed(size_t inst, int prec){ 598 string str; 599 auto dim = _lson->get_dim(inst); 600 if(_rson->is_matrix_indexed()){ 601 dim = _rson->get_dim(inst); 602 } 603 if(dim==0){ 604 return str; 605 } 606 for (auto idx = 0; idx <dim; idx++) { 607 str += to_str(inst,idx,prec); 608 } 609 return str; 610 } 611 612 to_str(size_t inst,int prec)613 string to_str(size_t inst,int prec) { 614 if(_otype==product_ && (_lson->is_matrix_indexed() || _rson->is_matrix_indexed())){ 615 return print_transposed(inst,prec); 616 } 617 string str; 618 if (this->_coef!=unit<type>().eval()) { 619 auto coef = to_string_with_precision(this->_coef, prec); 620 str += clean_print(true,coef); 621 str+="("; 622 } 623 if((_otype==min_ || _otype==max_)) { 624 str += operator_str(_otype)+"("; 625 str+= _lson->to_str(inst,prec); 626 str += ","; 627 str+= _rson->to_str(inst,prec); 628 str += ")"; 629 if (this->_coef!=unit<type>().eval()) { 630 str += ")"; 631 } 632 return str; 633 } 634 if((_otype==product_ || _otype==div_) && (_lson->get_type()==uexp_c || _lson->get_type()==bexp_c)) { 635 str += "("; 636 str+= _lson->to_str(inst,prec); 637 str += ")"; 638 } 639 else 640 str+= _lson->to_str(inst,prec); 641 642 if (_otype==plus_) { 643 if (this->_coef!=1. && this->_coef!=-1.) { 644 str+= " + "; 645 } 646 } 647 else if (_otype==minus_) { 648 if (this->_coef==-1.) { 649 str += " + "; 650 } 651 if (this->_coef==1.){ 652 str = str.substr(1); 653 str+= " - "; 654 } 655 } 656 else if (_otype==product_) { 657 str+= " * "; 658 } 659 else if (_otype==div_) { 660 str+= "/"; 661 } 662 else if (_otype==power_) { 663 str+= "^"; 664 } 665 666 if (_otype==plus_ || (_rson->get_type()!=uexp_c && _rson->get_type()!=bexp_c)) { 667 str+= _rson->to_str(inst,prec); 668 } 669 else { 670 str+= "("; 671 str+= _rson->to_str(inst,prec); 672 str+= ")"; 673 } 674 if (this->_coef!=unit<type>().eval()) { 675 str += ")"; 676 } 677 return str; 678 } 679 to_str(size_t inst1,size_t inst2,int prec)680 string to_str(size_t inst1,size_t inst2,int prec) { 681 string str; 682 if (this->_coef!=unit<type>().eval()) { 683 auto coef = to_string_with_precision(this->_coef, prec); 684 str += clean_print(true,coef); 685 str+="("; 686 } 687 if((_otype==product_ || _otype==div_) && (_lson->get_type()==uexp_c || _lson->get_type()==bexp_c)) { 688 str += "("; 689 str+= _lson->to_str(inst1,inst2,prec); 690 str += ")"; 691 } 692 else 693 str+= _lson->to_str(inst1,inst2,prec); 694 695 if (_otype==plus_) { 696 if (this->_coef!=1. && this->_coef!=-1.) { 697 str+= " + "; 698 } 699 } 700 if (_otype==minus_) { 701 if (this->_coef==-1.) { 702 str += " + "; 703 } 704 if (this->_coef==1.){ 705 str = str.substr(1); 706 str+= " - "; 707 } 708 } 709 if (_otype==product_) { 710 str+= " * "; 711 } 712 if (_otype==div_) { 713 str+= "/"; 714 } 715 716 if (_otype==power_) { 717 str+= "^"; 718 } 719 720 if (_otype==plus_ || (_rson->get_type()!=uexp_c && _rson->get_type()!=bexp_c)) { 721 str+= _rson->to_str(inst1,inst2,prec); 722 } 723 else { 724 str+= "("; 725 str+= _rson->to_str(inst1,inst2,prec); 726 str+= ")"; 727 } 728 if (this->_coef!=unit<type>().eval()) { 729 str += ")"; 730 } 731 return str; 732 } 733 is_inner_product()734 bool is_inner_product() const{ 735 return _otype==product_ && (_lson->get_dim(1)==_rson->get_dim(0) || (_lson->_is_transposed && _lson->get_dim(0)==_rson->get_dim(0))); 736 } 737 738 739 bexpr(OperatorType otype, shared_ptr<constant_> lson, shared_ptr<constant_> rson); 740 741 template<class T2, typename enable_if<is_convertible<T2, type>::value && sizeof(T2) < sizeof(type)>::type* = nullptr> 742 bexpr& operator=(const bexpr<T2>& exp){ 743 this->_type = bexp_c; 744 _lson = exp._lson->copy(); 745 _rson = exp._rson->copy(); 746 _otype = exp._otype; 747 this->_all_convexity = exp._all_convexity; 748 this->_all_sign = exp._all_sign; 749 if(exp._range){ 750 this->_range = make_shared<pair<type,type>>(); 751 this->_range->first = exp._range->first; 752 this->_range->second = exp._range->second; 753 } 754 this->_to_str = exp._to_str; 755 this->_coef = exp._coef; 756 this->_is_vector = exp._is_vector; 757 this->_is_transposed = exp._is_transposed; 758 this->_dim[0] = exp._dim[0]; this->_dim[1] = exp._dim[1]; 759 return *this; 760 } 761 762 bexpr& operator=(const bexpr& exp){ 763 this->_type = bexp_c; 764 _lson = exp._lson->copy(); 765 _rson = exp._rson->copy(); 766 _otype = exp._otype; 767 this->_all_convexity = exp._all_convexity; 768 this->_all_sign = exp._all_sign; 769 if(exp._range){ 770 this->_range = make_shared<pair<type,type>>(); 771 this->_range->first = exp._range->first; 772 this->_range->second = exp._range->second; 773 } 774 this->_to_str = exp._to_str; 775 this->_coef = exp._coef; 776 this->_is_vector = exp._is_vector; 777 this->_is_transposed = exp._is_transposed; 778 this->_dim[0] = exp._dim[0]; this->_dim[1] = exp._dim[1]; 779 return *this; 780 } 781 782 783 784 785 }; 786 787 } 788 #endif /* expr_h */ 789 790