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