1 // -*- C++ -*-
2 /**
3 * @brief symbolic expression (base classes and functionality)
4 *
5 * Copyright (C) 2008-2010 Leo Liberti
6 *
7 * This library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include <string>
23 #include <sstream>
24 #include <cmath>
25 #include <algorithm>
26 #include <cassert>
27 #include <iomanip>
28
29 #include "expression.h"
30
31 namespace Ev3
32 {
33
34 ////////////// auxiliary functions ///////////////
35
36 //#define VNAMEIDXCHAR "_"
37 #define VNAMEIDXCHAR ""
38
39 #define ISINTTOLERANCE 1e-8
40
is_integer(double a)41 static bool is_integer(double a)
42 {
43 double b = std::abs(a);
44 int bi = (int) round(b);
45 return (std::abs(b - bi) < ISINTTOLERANCE);
46 }
47
is_even(double a)48 static bool is_even(double a)
49 {
50 if (is_integer(a))
51 {
52 int ai = (int) round(a);
53 return (ai % 2 == 0);
54 }
55 return false;
56 }
57
is_odd(double a)58 static bool is_odd(double a)
59 {
60 if (is_integer(a))
61 {
62 int ai = (int) round(a);
63 return (ai % 2 == 1);
64 }
65 return false;
66 }
67
Ev3NearZero()68 double Ev3NearZero()
69 {
70 // returns a very small positive value
71 return 1 / LARGE;
72 }
73
Ev3Infinity()74 double Ev3Infinity()
75 {
76 // returns a very large positive value
77 return LARGE;
78 }
79
80 // create empty
BasicExpression()81 BasicExpression::BasicExpression() { }
82
83 // create a constant leaf
BasicExpression(const double t)84 BasicExpression::BasicExpression(const double t) : Operand(t) { }
85
86 // create a constant (integer-valued) leaf
BasicExpression(const Int t)87 BasicExpression::BasicExpression(const Int t) : Operand(t) { }
88
89 // create an (empty) operator or a variable leaf
BasicExpression(const Int t,const bool isvar)90 BasicExpression::BasicExpression(const Int t,
91 const bool isvar) :
92 Operand(t, isvar) { }
93
94 // create a variable leaf and set coefficient
BasicExpression(const double c,const Int t,const std::string & vn)95 BasicExpression::BasicExpression(const double c,
96 const Int t,
97 const std::string & vn) :
98 Operand(c, t, vn) { }
99
100 // user-defined copy constructor with two options
BasicExpression(const Expression & t,const bool iscopy)101 BasicExpression::BasicExpression(const Expression & t,
102 const bool iscopy) :
103 Operand(t.GetPointee())
104 {
105 const Int s = t->GetSize();
106 // create a _copy_ of t, subnode by subnode
107 if (iscopy) for (int i = 0; i < s; i++) nodes.push_back(t->GetCopyOfNode(i));
108 // create a copy of the pointers in t
109 else for (int i = 0; i < s; i++) nodes.push_back(t->GetNode(i));
110 }
111
112 // copy constructor
BasicExpression(const BasicExpression & t)113 BasicExpression::BasicExpression(const BasicExpression & t) : Operand(t)
114 {
115 const Int s = t.GetSize();
116 // necessary for constructs "(BasicExpression) e =" where e already
117 // existed prior to assignment
118 // -- segvs (?)
119 for(int i = 0; i < GetSize(); i++) RecursiveDestroy(GetNodePtr(i));
120 DeleteAllNodes();
121 // create a copy of the subnode pointers in t
122 for (int i = 0; i < s; i++) nodes.push_back(t.GetNode(i));
123 }
124
125 // destructor
~BasicExpression()126 BasicExpression::~BasicExpression() { }
127
128 // BasicExpression class methods:
129
130
Debug() const131 void BasicExpression::Debug () const
132 {
133 Int s = GetSize();
134 std::cerr << "BasicExpression: Debug:\n";
135 std::cerr << "\tthis = " << this << std::endl;
136 std::cerr << "\toptype = " << GetOpType() << std::endl;
137 std::cerr << "\tnodes = " << s << std::endl;
138 for (Int i = 0; i < s; i++) std::cerr << "\tnode " << i << ": " << GetNode(i)->GetOpType() << std::endl;
139 }
140
Zero()141 void BasicExpression::Zero()
142 {
143 // -- segvs (?)
144 for(int i = 0; i < GetSize(); i++) RecursiveDestroy(GetNodePtr(i));
145 DeleteAllNodes();
146 SetCoeff(1.0);
147 SetExponent(1.0);
148 SetValue(0.0);
149 SetOpType(CONST);
150 }
151
One()152 void BasicExpression::One()
153 {
154 // -- segvs (?)
155 for(int i = 0; i < GetSize(); i++) RecursiveDestroy(GetNodePtr(i));
156 DeleteAllNodes();
157 SetCoeff(1.0);
158 SetExponent(1.0);
159 SetValue(1.0);
160 SetOpType(CONST);
161 }
162
PrintTree(const int blanks,const int tabs) const163 std::string BasicExpression::PrintTree(const int blanks,
164 const int tabs) const
165 {
166 std::stringstream outbuf;
167 std::string b(blanks, ' ');
168 if (IsLeaf()) outbuf << b << Operand::ToString();
169 else
170 {
171 outbuf << b << "OP[" << GetOpType() << "](" << std::endl;
172 for(int i = 0; i < GetSize(); i++)
173 {
174 outbuf << GetNode(i)->PrintTree(blanks + tabs, tabs);
175 if (i < GetSize() - 1)
176 {
177 outbuf << ",";
178 }
179 outbuf << std::endl;
180 }
181 outbuf << b << ")";
182 }
183 return outbuf.str();
184 }
185
186
operator <<(std::ostream & outbuf,const BasicExpression & expr)187 std::ostream & operator<< (std::ostream & outbuf, const BasicExpression & expr)
188 {
189 Int i, s;
190 if (expr.IsLeaf())
191 {
192 // leaf node, use Operand::ToString()
193 outbuf << Operand(expr);
194
195 }
196 else
197 {
198 double tc( expr.GetCoeff());
199 // operator node
200 if (tc != 1)
201 {
202 if (tc != -1) outbuf << "(" << tc << "*(";
203 else outbuf << "(-(";
204 }
205 s = expr.GetSize();
206 if (s > 1)
207 {
208 for (i = 0; i < s; i++)
209 {
210 outbuf << "(" << expr.GetNode(i) << ")";
211 if (i < s - 1)
212 {
213 switch( expr.GetOpType())
214 {
215 case SUM:
216 outbuf << "+";
217 break;
218 case DIFFERENCE:
219 outbuf << "-";
220 break;
221 case PRODUCT:
222 outbuf << "*";
223 break;
224 case FRACTION:
225 outbuf << "/";
226 break;
227 case POWER:
228 outbuf << "^";
229 break;
230 default:
231 outbuf << "UNKNOWNOP";
232 break;
233 }
234 }
235 }
236 }
237 else
238 {
239 switch( expr.GetOpType())
240 {
241 case PLUS:
242 break;
243 case MINUS:
244 outbuf << "-";
245 break;
246 case SIN:
247 outbuf << "sin";
248 break;
249 case COS:
250 outbuf << "cos";
251 break;
252 case TAN:
253 outbuf << "tan";
254 break;
255 case ASIN:
256 outbuf << "asin";
257 break;
258 case ACOS:
259 outbuf << "acos";
260 break;
261 case ATAN:
262 outbuf << "atan";
263 break;
264 case SINH:
265 outbuf << "sinh";
266 break;
267 case COSH:
268 outbuf << "cosh";
269 break;
270 case TANH:
271 outbuf << "tanh";
272 break;
273 case ASINH:
274 outbuf << "asinh";
275 break;
276 case ACOSH:
277 outbuf << "acosh";
278 break;
279 case ATANH:
280 outbuf << "atanh";
281 break;
282 case LOG2:
283 outbuf << "log2";
284 break;
285 case LOG10:
286 outbuf << "log10";
287 break;
288 case LOG:
289 outbuf << "log";
290 break;
291 case LN:
292 outbuf << "ln";
293 break;
294 case LNGAMMA:
295 outbuf << "lngamma";
296 break;
297 case GAMMA:
298 outbuf << "gamma";
299 break;
300 case EXP:
301 outbuf << "exp";
302 break;
303 case ERF:
304 outbuf << "erf";
305 break;
306 case ERFC:
307 outbuf << "erfc";
308 break;
309 case SQRT:
310 outbuf << "sqrt";
311 break;
312 case CBRT:
313 outbuf << "cbrt";
314 break;
315 case BESSELJ0:
316 outbuf << "besselJ0";
317 break;
318 case BESSELJ1:
319 outbuf << "besselJ1";
320 break;
321 case BESSELY0:
322 outbuf << "besselY0";
323 break;
324 case BESSELY1:
325 outbuf << "besselY1";
326 break;
327 case SIGN:
328 outbuf << "sign";
329 break;
330 case RINT:
331 outbuf << "rint";
332 break;
333 case ABS:
334 outbuf << "abs";
335 break;
336 case COT:
337 outbuf << "cot";
338 break;
339 case COTH:
340 outbuf << "coth";
341 break;
342 default:
343 outbuf << "UNKNOWNOP";
344 }
345 if (s == 1)
346 {
347 outbuf << "(" << expr.GetNode(0) << ")";
348 }
349 else
350 {
351 // no arguments - error
352 outbuf << "(NOARG)";
353 }
354 }
355 if ( expr.GetCoeff() != 1)
356 {
357 outbuf << "))";
358 }
359 }
360 return outbuf;
361 }
362
363
ToString() const364 std::string BasicExpression::ToString() const
365 {
366 std::stringstream outbuf;
367 outbuf << *this;
368 return outbuf.str();
369 }
370
operator <<(std::ostream & outbuf,const Expression & expr)371 std::ostream & operator<< (std::ostream & outbuf, const Expression & expr)
372 {
373 outbuf << expr.GetPointee();
374 return outbuf;
375 }
376
377 // is expression this == expression t?
IsEqualTo(const Expression & t) const378 bool BasicExpression::IsEqualTo(const Expression& t) const
379 {
380 //Just in case constant value not consolidated in coeff
381 if (GetOpType() == CONST && t->GetOpType() == CONST)
382 {
383 if (GetValue() == t->GetValue())
384 {
385 return true;
386 }
387 else
388 {
389 return false;
390 }
391 }
392
393 if (IsEqualToNoCoeff(t))
394 {
395 if (GetCoeff() == t->GetCoeff())
396 return true;
397 else
398 return false;
399 }
400 else
401 return false;
402 }
403
operator ==(const BasicExpression & t) const404 bool BasicExpression::operator == (const BasicExpression& t) const
405 {
406 // fast checks
407 if (IsLeaf() && t.IsLeaf())
408 {
409 if (GetOpType() == t.GetOpType())
410 {
411 if (GetOpType() == CONST)
412 {
413 // if both are constants, they're always equal up to coefficient
414 return true;
415 }
416 else if (GetOpType() == VAR && GetVarIndex() == t.GetVarIndex() &&
417 GetExponent() == t.GetExponent())
418 return true;
419 else
420 return false;
421 }
422 else
423 return false;
424 }
425 else if ((!IsLeaf()) && (!t.IsLeaf()))
426 {
427 // both BasicExpressions are not leaves, recurse using PRECISE
428 // (i.e. not up to coefficient) form
429 if (GetSize() != t.GetSize())
430 return false;
431 if (GetOpType() != t.GetOpType())
432 return false;
433 Int i;
434 bool ret = true;
435 for (i = 0; i < GetSize(); i++)
436 {
437 if (!(GetNode(i)->IsEqualTo(t.GetNode(i))))
438 {
439 ret = false;
440 break;
441 }
442 }
443 if (ret)
444 {
445 return true;
446 }
447 return false;
448 }
449 else
450 return false;
451 }
452
IsEqualTo(const double t) const453 bool BasicExpression::IsEqualTo(const double t) const
454 {
455 return (IsLeaf() && GetOpType() == CONST && GetValue() == t);
456 }
457
NumberOfVariables() const458 int BasicExpression::NumberOfVariables() const
459 {
460 int maxvi = 0;
461 return NumberOfVariables(maxvi);
462 }
463
NumberOfVariables(int & maxvi) const464 int BasicExpression::NumberOfVariables(int& maxvi) const
465 {
466 int newvi = 0;
467 if (IsVariable())
468 {
469 newvi = GetVarIndex();
470 if (newvi > maxvi)
471 {
472 maxvi = newvi;
473 }
474 return maxvi;
475 }
476 else if (!IsLeaf())
477 {
478 for(int i = 0; i < GetSize(); i++)
479 {
480 newvi = GetNode(i)->NumberOfVariables(maxvi);
481 if (newvi > maxvi)
482 {
483 maxvi = newvi;
484 }
485 }
486 return maxvi;
487 }
488 else
489 {
490 return 0;
491 }
492 }
493
494
495 // taken and adapted from operator ==
IsEqualToNoCoeff(const Expression & t) const496 bool BasicExpression::IsEqualToNoCoeff(const Expression & t) const
497 {
498 // fast checks
499 if (IsLeaf() && t->IsLeaf())
500 {
501 if (GetOpType() == t->GetOpType())
502 {
503 if (GetOpType() == CONST)
504 {
505 // if both are constants, they're always equal up to coefficient
506 return true;
507 }
508 else
509 {
510 if (GetOpType() == VAR && GetVarIndex() == t->GetVarIndex() &&
511 GetExponent() == t->GetExponent())
512 return true;
513 else
514 return false;
515 }
516 }
517 else return false;
518 }
519 else if ((!IsLeaf()) && (!t->IsLeaf()))
520 {
521 // both BasicExpressions are not leaves, recurse using PRECISE
522 // (i.e. not up to coefficient) form
523 if (GetSize() != t->GetSize() || GetOpType() != t->GetOpType() ||
524 GetExponent() != t->GetExponent())
525 {
526 return false;
527 }
528 Int i;
529 bool ret = true;
530 for (i = 0; i < GetSize(); i++)
531 {
532 if (!(GetNode(i)->IsEqualTo(t->GetNode(i))))
533 {
534 ret = false;
535 break;
536 }
537 }
538 if (ret)
539 {
540 return true;
541 }
542 return false;
543 }
544 else
545 return false;
546 }
547
IsEqualBySchema(const Expression & t) const548 bool BasicExpression::IsEqualBySchema(const Expression& t) const
549 {
550 if (IsLeaf() && t->IsLeaf())
551 {
552 if (GetOpType() == t->GetOpType() &&
553 IsLinear() == t->IsLinear())
554 {
555 return true;
556 }
557 else
558 {
559 return false;
560 }
561 }
562 else if ((!IsLeaf()) && (!t->IsLeaf()))
563 {
564 // both BasicExpressions are not leaves, recurse
565 if (GetSize() != t->GetSize())
566 {
567 return false;
568 }
569 if (GetOpType() != t->GetOpType())
570 {
571 return false;
572 }
573 Int i;
574 bool ret = true;
575 for (i = 0; i < GetSize(); i++)
576 {
577 if (!(GetNode(i)->IsEqualBySchema(t->GetNode(i))))
578 {
579 ret = false;
580 break;
581 }
582 }
583 if (ret)
584 {
585 return true;
586 }
587 return false;
588 }
589 else
590 {
591 return false;
592 }
593 }
594
IsEqualByOperator(const int theoplabel) const595 bool BasicExpression::IsEqualByOperator(const int theoplabel) const
596 {
597 if (GetOpType() == theoplabel)
598 {
599 return true;
600 }
601 else
602 {
603 return false;
604 }
605 }
606
DependsOnVariable(Int vi) const607 bool BasicExpression::DependsOnVariable(Int vi) const
608 {
609 if (IsLeaf())
610 {
611 if (GetOpType() == VAR)
612 {
613 if (GetVarIndex() == vi)
614 return true;
615 else
616 return false;
617 }
618 else
619 return false;
620 }
621 else
622 {
623 Int i;
624 bool ret = false;
625 for (i = 0; i < GetSize(); i++)
626 {
627 ret = GetNode(i)->DependsOnVariable(vi);
628 if (ret)
629 return true;
630 }
631 return false;
632 }
633 }
634
DependsLinearlyOnVariable(Int vi) const635 int BasicExpression::DependsLinearlyOnVariable(Int vi) const
636 {
637 if (IsVariable())
638 {
639 if (GetVarIndex() == vi)
640 {
641 if (GetExponent() == 1)
642 {
643 return 1; // depends linearly
644 }
645 else
646 {
647 return 0; // depends nonlinearly
648 }
649 }
650 else
651 {
652 return 2; // doesn't depend on vi at all
653 }
654 }
655 else
656 {
657 int i;
658 int d;
659 bool dependsatall = false;
660 // if node is linear:
661 if (GetOpType() == SUM || GetOpType() == DIFFERENCE ||
662 GetOpType() == PLUS || GetOpType() == MINUS)
663 {
664 for(i = 0; i < GetSize(); i++)
665 {
666 d = GetNode(i)->DependsLinearlyOnVariable(vi);
667 if (d == 0)
668 {
669 // depends nonlinearly, return 0
670 return 0;
671 }
672 if (d == 1)
673 {
674 // depends linearly, record
675 dependsatall = true;
676 }
677 }
678 if (dependsatall)
679 {
680 return 1;
681 }
682 else
683 {
684 return 2;
685 }
686 }
687 else if (GetOpType() == PRODUCT)
688 {
689 int nbBranchesDependingOnVariable = 0;
690 for(i = 0; i < GetSize(); i++)
691 {
692 d = GetNode(i)->DependsLinearlyOnVariable(vi);
693 if (d == 0)
694 return 0;
695
696 if (d == 1)
697 ++nbBranchesDependingOnVariable;
698 }
699
700 if (nbBranchesDependingOnVariable == 0)
701 return 2;
702 else if (nbBranchesDependingOnVariable == 1)
703 return 1;
704 else
705 return 0;
706 }
707 else
708 {
709 if (DependsOnVariable(vi))
710 {
711 return 0; // depends nonlinearly
712 }
713 else
714 {
715 return 2; // doesn't depend on vi at all
716 }
717 }
718 }
719 }
720
ConsolidateProductCoeffs()721 void BasicExpression::ConsolidateProductCoeffs()
722 {
723 if (GetOpType() == PRODUCT)
724 {
725 Int i;
726 double tc = GetCoeff();
727 for (i = 0; i < GetSize(); i++)
728 {
729 tc *= GetNode(i)->GetCoeff();
730 GetNode(i)->SetCoeff(1.0);
731 }
732 if (std::abs(tc) < Ev3NearZero())
733 {
734 Zero();
735 }
736 else
737 {
738 SetCoeff(tc);
739 }
740 }
741 }
742
DistributeCoeffOverSum()743 void BasicExpression::DistributeCoeffOverSum()
744 {
745 if (GetOpType() == SUM)
746 {
747 double tc = GetCoeff();
748 if (tc != 1)
749 {
750 SetCoeff(1.0);
751 Int i;
752 for(i = 0; i < GetSize(); i++)
753 {
754 GetNode(i)->SetCoeff(tc * GetNode(i)->GetCoeff());
755 GetNode(i)->DistributeCoeffOverSum();
756 }
757 }
758 }
759 }
760
DistributeCoeffOverProduct()761 void BasicExpression::DistributeCoeffOverProduct()
762 {
763 if (GetOpType() == PRODUCT)
764 {
765 double tc = GetCoeff();
766 if (tc != 1 && GetSize() > 0)
767 {
768 SetCoeff(1.0);
769 GetNode(0)->SetCoeff(tc * GetNode(0)->GetCoeff());
770 }
771 }
772 }
773
774 // enforce constant dependencies (added for MORON - see ../PROGNOTES)
775 // this only acts on the proper leaf nodes
EnforceDependency()776 void BasicExpression::EnforceDependency()
777 {
778 if (IsLeaf())
779 {
780 // nonrecursive
781 EnforceDependencyOnOperand();
782 }
783 else
784 {
785 // recursive
786 int i;
787 for (i = 0; i < GetSize(); i++)
788 {
789 GetNode(i)->EnforceDependency();
790 }
791 }
792 }
793
794 // substitute a variable with a constant
VariableToConstant(int varindex,double c)795 void BasicExpression::VariableToConstant(int varindex,
796 double c)
797 {
798 if (IsLeaf())
799 {
800 // nonrecursive
801 SubstituteVariableWithConstant(varindex, c);
802 }
803 else
804 {
805 // recursive
806 int i;
807 for (i = 0; i < GetSize(); i++)
808 {
809 GetNode(i)->VariableToConstant(varindex, c);
810 }
811 }
812 }
813
814 // replace variable indexed v1 with variable indexed v2
ReplaceVariable(int v1,int v2,const std::string & vn)815 void BasicExpression::ReplaceVariable(int v1,
816 int v2,
817 const std::string & vn)
818 {
819 if (DependsOnVariable(v1))
820 {
821 if (IsVariable() && GetVarIndex() == v1)
822 {
823 SetVarIndex(v2);
824 SetVarName(vn);
825 }
826 else
827 {
828 int i;
829 for(i = 0; i < GetSize(); i++)
830 {
831 GetNode(i)->ReplaceVariable(v1, v2, vn);
832 }
833 }
834 }
835 }
ReplaceVariable(int v1,int v2,const std::string & vn,double c2)836 void BasicExpression::ReplaceVariable(int v1,
837 int v2,
838 const std::string & vn,
839 double c2)
840 {
841 if (DependsOnVariable(v1))
842 {
843 if (IsVariable() && GetVarIndex() == v1)
844 {
845 SetVarIndex(v2);
846 SetVarName(vn);
847 SetCoeff(GetCoeff() * c2);
848 }
849 else
850 {
851 int i;
852 for(i = 0; i < GetSize(); i++)
853 {
854 GetNode(i)->ReplaceVariable(v1, v2, vn, c2);
855 }
856 }
857 }
858 }
859
860 // replace with a variable the deepest node conforming to schema and
861 // return replaced term or zero expression if no replacement occurs
ReplaceBySchema(int vi,const std::string & vn,const Expression & schema)862 Expression BasicExpression::ReplaceBySchema(int vi,
863 const std::string & vn,
864 const Expression & schema)
865 {
866 Expression ret(0.0);
867 ret = ReplaceBySchemaRecursive(vi, vn, schema);
868 if (ret->IsZero())
869 {
870 // no subnodes with schema found, wor on this one
871 if (IsEqualBySchema(schema))
872 {
873 // this node is according to schema
874 // save (recursively) this into ret
875 ret.SetToCopyOf(*this);
876 // replace with w_vi
877 // -- segvs (?)
878 for(int i = 0; i < GetSize(); i++)
879 {
880 RecursiveDestroy(GetNodePtr(i));
881 }
882 DeleteAllNodes();
883 SetOpType(VAR);
884 SetVarIndex(vi);
885 SetVarName(vn);
886 SetCoeff(1.0);
887 SetExponent(1.0);
888 }
889 }
890 return ret;
891 }
892
893 // recursive version - works on subnodes, not on current node
ReplaceBySchemaRecursive(int vi,const std::string & vn,const Expression & schema)894 Expression BasicExpression::ReplaceBySchemaRecursive(int vi,
895 const std::string & vn,
896 const Expression & schema)
897 {
898 bool done = false;
899 Expression ret(0.0);
900 for(int i = 0; i < GetSize(); i++)
901 {
902 if (!GetNode(i)->IsLeaf())
903 {
904 ret = GetNode(i)->ReplaceBySchemaRecursive(vi, vn, schema);
905 if (!ret->IsZero())
906 {
907 done = true;
908 break;
909 }
910 }
911 if (!done)
912 {
913 if (GetNode(i)->IsEqualBySchema(schema))
914 {
915 ret = GetNode(i);
916 Expression w(1, vi, vn);
917 GetNodePtr(i)->SetTo(w);
918 done = true;
919 break;
920 }
921 }
922 }
923 return ret;
924 }
925
926 // replace with a variable the deepest node with given operator label
927 // return replaced term or zero expression if no replacement occurs
ReplaceByOperator(int vi,const std::string & vn,int theoplabel)928 Expression BasicExpression::ReplaceByOperator(int vi,
929 const std::string & vn,
930 int theoplabel)
931 {
932 Expression ret(0.0);
933 ret = ReplaceByOperatorRecursive(vi, vn, theoplabel);
934 if (ret->IsZero())
935 {
936 // no subnodes with schema found, wor on this one
937 if (IsEqualByOperator(theoplabel))
938 {
939 // this node is according to schema
940 // save (recursively) this into ret
941 ret.SetToCopyOf(*this);
942 // replace with w_vi
943 // -- segvs
944 for(int i = 0; i < GetSize(); i++)
945 {
946 RecursiveDestroy(GetNodePtr(i));
947 }
948 DeleteAllNodes();
949 SetOpType(VAR);
950 SetVarIndex(vi);
951 SetVarName(vn);
952 SetCoeff(1.0);
953 SetExponent(1.0);
954 }
955 }
956 return ret;
957 }
958
959 // recursive version - works on subnodes, not on current node
ReplaceByOperatorRecursive(int vi,const std::string & vn,int theoplabel)960 Expression BasicExpression::ReplaceByOperatorRecursive(int vi,
961 const std::string & vn,
962 int theoplabel)
963 {
964 bool done = false;
965 Expression ret(0.0);
966 for(int i = 0; i < GetSize(); i++)
967 {
968 if (!GetNode(i)->IsLeaf())
969 {
970 ret = GetNode(i)->ReplaceByOperatorRecursive(vi, vn, theoplabel);
971 if (!ret->IsZero())
972 {
973 done = true;
974 break;
975 }
976 }
977 if (!done)
978 {
979 if (GetNode(i)->IsEqualByOperator(theoplabel))
980 {
981 ret = GetNode(i);
982 Expression w(1, vi, vn);
983 GetNodePtr(i)->SetTo(w);
984 done = true;
985 break;
986 }
987 }
988 }
989
990 return ret;
991 }
992
ReplaceWithExpression(const Expression & replace)993 void BasicExpression::ReplaceWithExpression(const Expression & replace)
994 {
995 /* // -- segvs (?)
996 for(int i = 0; i < GetSize(); i++) {
997 RecursiveDestroy(GetNodePtr(i));
998 }
999 */
1000 DeleteAllNodes();
1001 if (replace->GetOpType() == VAR)
1002 {
1003 SetVarIndex(replace->GetVarIndex());
1004 SetVarName(replace->GetVarName());
1005 SetCoeff(replace->GetCoeff());
1006 SetExponent(replace->GetExponent());
1007 }
1008 else if (replace->GetOpType() == CONST)
1009 {
1010 SetValue(replace->GetValue());
1011 }
1012 else
1013 {
1014 SetCoeff(replace->GetCoeff());
1015 SetExponent(replace->GetExponent());
1016 SetOpType(replace->GetOpType());
1017 }
1018 for (int i = 0; i < replace->GetSize(); i++)
1019 {
1020 nodes.push_back(replace->GetNode(i));
1021 }
1022 }
1023
1024
ReplaceSubexpression(const Expression & needle,const Expression & replace)1025 int BasicExpression::ReplaceSubexpression(const Expression & needle,
1026 const Expression & replace)
1027 {
1028 int ret = 0;
1029 if (!IsLeaf())
1030 {
1031 // recurse
1032 for(int i = 0; i < GetSize(); i++)
1033 {
1034 ret += GetNode(i)->ReplaceSubexpression(needle, replace);
1035 }
1036 }
1037 // act on this node
1038 if (IsEqualTo(needle))
1039 {
1040 ret++;
1041 ReplaceWithExpression(replace);
1042 }
1043 return ret;
1044 }
1045
ResetVarNames(const std::string & vn,int lid,int uid)1046 void BasicExpression::ResetVarNames(const std::string & vn,
1047 int lid,
1048 int uid)
1049 {
1050 // set all variable names in the expression to vn
1051 if (!IsLeaf())
1052 {
1053 for(int i = 0; i < GetSize(); i++)
1054 {
1055 GetNode(i)->ResetVarNames(vn, lid, uid);
1056 }
1057 }
1058 else
1059 {
1060 if (GetOpType() == VAR)
1061 {
1062 int vi = GetVarIndex();
1063 if (vi >= lid && vi <= uid)
1064 {
1065 SetVarName(vn);
1066 }
1067 }
1068 }
1069 }
1070
1071
DistributeProductsOverSums()1072 bool BasicExpression::DistributeProductsOverSums()
1073 {
1074 // recursive part
1075 bool ret = false;
1076 if (!IsLeaf())
1077 {
1078 for(int i = 0; i < GetSize(); i++)
1079 {
1080 bool haschanged = GetNode(i)->DistributeProductsOverSums();
1081 if (haschanged)
1082 {
1083 ret = true;
1084 }
1085 }
1086 }
1087 // deal with this node
1088 Expression e(0.0);
1089 if (GetOpType() == PRODUCT)
1090 {
1091 for(int i = 0; i < GetSize(); i++)
1092 {
1093 if (GetNode(i)->GetOpType() == SUM)
1094 {
1095 // found occurrence of *(+), distribute
1096 ret = true;
1097 Expression f = (*this) / GetNode(i);
1098 Simplify(&f);
1099 for(int j = 0; j < GetNode(i)->GetSize(); j++)
1100 {
1101 e = e + f * GetNode(i)->GetNode(j);
1102 }
1103 // now replace this with e
1104 ReplaceWithExpression(e);
1105 }
1106 }
1107 }
1108 return ret;
1109 }
1110
GetVarIndices(std::vector<int> & vidx)1111 void BasicExpression::GetVarIndices(std::vector<int> & vidx)
1112 {
1113 if (!IsLeaf())
1114 {
1115 for(int i = 0; i < GetSize(); i++)
1116 {
1117 GetNode(i)->GetVarIndices(vidx);
1118 }
1119 }
1120 else if (IsVariable())
1121 {
1122 int vi = GetVarIndex();
1123 if (find(vidx.begin(), vidx.end(), vi) == vidx.end())
1124 {
1125 vidx.push_back(vi);
1126 }
1127 }
1128 }
1129
GetVarIndicesInSchema(std::vector<int> & vidx,const Expression & schema)1130 void BasicExpression::GetVarIndicesInSchema(std::vector<int> & vidx,
1131 const Expression & schema)
1132 {
1133 // recurse
1134 if (!IsLeaf())
1135 {
1136 for(int i = 0; i < GetSize(); i++)
1137 {
1138 GetNode(i)->GetVarIndicesInSchema(vidx, schema);
1139 }
1140 }
1141 // deal with this node
1142 if (IsEqualBySchema(schema))
1143 {
1144 GetVarIndices(vidx);
1145 }
1146 }
1147
1148 // find the variable name corresponding to variable index vi
FindVariableName(int vi)1149 std::string BasicExpression::FindVariableName(int vi)
1150 {
1151 std::string vn;
1152 if (IsVariable())
1153 {
1154 if (GetVarIndex() == vi)
1155 {
1156 return GetVarName();
1157 }
1158 else
1159 {
1160 return "";
1161 }
1162 }
1163 else
1164 {
1165 int i;
1166 for(i = 0; i < GetSize(); i++)
1167 {
1168 vn = GetNode(i)->FindVariableName(vi);
1169 if (vn.length() > 0)
1170 {
1171 return vn;
1172 }
1173 }
1174 }
1175 return "";
1176 }
1177
1178 // is this expression linear?
IsLinear() const1179 bool BasicExpression::IsLinear() const
1180 {
1181 if (IsVariable())
1182 {
1183 if (GetExponent() != 0 && GetExponent() != 1)
1184 {
1185 return false;
1186 }
1187 else
1188 {
1189 return true;
1190 }
1191 }
1192 if (IsConstant())
1193 {
1194 return true;
1195 }
1196 if(GetOpType() == SUM || GetOpType() == DIFFERENCE)
1197 {
1198 int i;
1199 for(i = 0; i < GetSize(); i++)
1200 {
1201 if (!GetNode(i)->IsLinear())
1202 {
1203 return false;
1204 }
1205 }
1206 return true;
1207 }
1208 else
1209 {
1210 return false;
1211 }
1212 }
1213
1214 // is this expression a quadratic product?
IsQuadratic(int & prodtype) const1215 bool BasicExpression::IsQuadratic(int& prodtype) const
1216 {
1217 bool ret = false;
1218 if ((GetOpType() == PRODUCT &&
1219 GetNode(0)->GetOpType() == VAR && GetNode(1)->GetOpType() == VAR) ||
1220 (GetOpType() == POWER &&
1221 GetNode(0)->GetOpType() == VAR && GetNode(1)->GetValue() == 2) ||
1222 (GetOpType() == VAR && GetExponent() == 2))
1223 {
1224 prodtype = GetOpType();
1225 ret = true;
1226 }
1227 return ret;
1228 }
IsQuadratic() const1229 bool BasicExpression::IsQuadratic() const
1230 {
1231 int ret = 0;
1232 return IsQuadratic(ret);
1233 }
1234
1235 // return info about the linear part (assumes Simplify() has already been
1236 // called on this) - return false if expression has no linear part
1237 // by "linear part" we mean lin(x) in expr(x,y) = lin(x) + nonlin(y)
GetLinearInfo(std::vector<double> & lincoeff,std::vector<int> & linvi,std::vector<std::string> & linvn,double & c)1238 bool BasicExpression::GetLinearInfo(std::vector<double> & lincoeff,
1239 std::vector<int> & linvi,
1240 std::vector<std::string> & linvn,
1241 double& c)
1242 {
1243 c = 0;
1244 bool ret = false;
1245 Expression nl(GetPureNonlinearPart());
1246 if (IsLinear())
1247 {
1248 nl->Zero();
1249 }
1250 if (lincoeff.size() > 0)
1251 {
1252 lincoeff.erase(lincoeff.begin(), lincoeff.end());
1253 linvi.erase(linvi.begin(), linvi.end());
1254 linvn.erase(linvn.begin(), linvn.end());
1255 }
1256 if (IsLeaf())
1257 {
1258 if (IsConstant())
1259 {
1260 // just a constant
1261 c = GetValue();
1262 ret = true;
1263 }
1264 else if (IsVariable() && GetExponent() == 1)
1265 {
1266 // just a variable
1267 linvi.push_back(GetVarIndex());
1268 lincoeff.push_back(GetCoeff());
1269 linvn.push_back(GetVarName());
1270 ret = true;
1271 }
1272 }
1273 else
1274 {
1275 if (GetOpType() == SUM)
1276 {
1277 int i, vi;
1278 c = 0;
1279 for(i = 0; i < GetSize(); i++)
1280 {
1281 if (GetNode(i)->IsConstant())
1282 {
1283 if (i > 0)
1284 {
1285 //std::cerr << "BasicExpression::GetLinearInfo: WARNING: "
1286 // << "run Simplify() first\n";
1287 }
1288 c += GetNode(i)->GetValue();
1289 }
1290 else if (GetNode(i)->IsVariable() &&
1291 GetNode(i)->GetExponent() == 1)
1292 {
1293 vi = GetNode(i)->GetVarIndex();
1294 if (!nl->DependsOnVariable(vi))
1295 {
1296 // vi depends only linearly on expression
1297 linvi.push_back(vi);
1298 lincoeff.push_back(GetNode(i)->GetCoeff());
1299 linvn.push_back(GetNode(i)->GetVarName());
1300 ret = true;
1301 }
1302 }
1303 }
1304 }
1305 }
1306 return ret;
1307 }
1308
1309 // return info about the purely linear part
1310 // (assumes Simplify() has already been
1311 // called on this) - return false if expression has no linear part
1312 // by "pure linear part" we mean e.g. x+y in x+y+y^2
GetPureLinearInfo(std::vector<double> & lincoeff,std::vector<int> & linvi,std::vector<std::string> & linvn,double & c)1313 bool BasicExpression::GetPureLinearInfo(std::vector<double> & lincoeff,
1314 std::vector<int> & linvi,
1315 std::vector<std::string> & linvn,
1316 double& c)
1317 {
1318 c = 0;
1319 bool ret = false;
1320 int i;
1321 Expression nl(GetPureNonlinearPart());
1322 if (IsLinear())
1323 {
1324 nl->Zero();
1325 }
1326 if (lincoeff.size() > 0)
1327 {
1328 lincoeff.erase(lincoeff.begin(), lincoeff.end());
1329 linvi.erase(linvi.begin(), linvi.end());
1330 linvn.erase(linvn.begin(), linvn.end());
1331 }
1332 if (IsLeaf())
1333 {
1334 if (IsConstant())
1335 {
1336 // just a constant
1337 c = GetValue();
1338 ret = true;
1339 }
1340 else if (IsVariable() && GetExponent() == 1)
1341 {
1342 // just a variable
1343 linvi.push_back(GetVarIndex());
1344 lincoeff.push_back(GetCoeff());
1345 linvn.push_back(GetVarName());
1346 ret = true;
1347 }
1348 }
1349 else
1350 {
1351 if (GetOpType() == SUM)
1352 {
1353 int vi;
1354 c = 0;
1355 for(i = 0; i < GetSize(); i++)
1356 {
1357 if (GetNode(i)->IsConstant())
1358 {
1359 if (i > 0)
1360 {
1361 //std::cerr << "BasicExpression::GetLinearInfo: WARNING: "
1362 // << "run Simplify() first\n";
1363 }
1364 c += GetNode(i)->GetValue();
1365 }
1366 else if (GetNode(i)->IsVariable() &&
1367 GetNode(i)->GetExponent() == 1)
1368 {
1369 vi = GetNode(i)->GetVarIndex();
1370 linvi.push_back(vi);
1371 lincoeff.push_back(GetNode(i)->GetCoeff());
1372 linvn.push_back(GetNode(i)->GetVarName());
1373 ret = true;
1374 }
1375 }
1376
1377 }
1378 }
1379 return ret;
1380 }
1381
1382 // get the linear part - x in x+y+y^2
GetLinearPart()1383 Expression BasicExpression::GetLinearPart()
1384 {
1385 std::vector<double> lincoeff;
1386 std::vector<int> linvi;
1387 std::vector<std::string> linvn;
1388 double c;
1389 GetLinearInfo(lincoeff, linvi, linvn, c);
1390 int i;
1391 Expression ret;
1392 if (lincoeff.size() > 0)
1393 {
1394 ret->SetOpType(VAR);
1395 ret->SetVarIndex(linvi[0]);
1396 ret->SetCoeff(lincoeff[0]);
1397 ret->SetVarName(linvn[0]);
1398 ret->SetExponent(1.0);
1399 if (lincoeff.size() > 1)
1400 {
1401 Expression addend(1.0, -1, NOTVARNAME);
1402 for(i = 1; i < (int) lincoeff.size(); i++)
1403 {
1404 addend->SetVarIndex(linvi[i]);
1405 addend->SetCoeff(lincoeff[i]);
1406 addend->SetVarName(linvn[i]);
1407 ret = ret + addend;
1408 }
1409 }
1410 }
1411 return ret;
1412 }
1413
1414 // get the pure linar part - x+y in x+y+y^2
GetPureLinearPart()1415 Expression BasicExpression::GetPureLinearPart()
1416 {
1417 std::vector<double> lincoeff;
1418 std::vector<int> linvi;
1419 std::vector<std::string> linvn;
1420 double c;
1421 GetPureLinearInfo(lincoeff, linvi, linvn, c);
1422 int i;
1423 Expression ret(0.0);
1424 if (lincoeff.size() > 0)
1425 {
1426 ret->SetOpType(VAR);
1427 ret->SetVarIndex(linvi[0]);
1428 ret->SetCoeff(lincoeff[0]);
1429 ret->SetVarName(linvn[0]);
1430 ret->SetExponent(1.0);
1431 if (lincoeff.size() > 1)
1432 {
1433 for(i = 1; i < (int) lincoeff.size(); i++)
1434 {
1435 Expression addend(lincoeff[i], linvi[i], linvn[i]);
1436 ret = SumLink(ret, addend);
1437 }
1438 }
1439 }
1440 return ret;
1441 }
1442
1443 // get the nonlinear part - nonlin(y) in expr(x,y) = lin(x) + nonlin(y)
GetNonlinearPart()1444 Expression BasicExpression::GetNonlinearPart()
1445 {
1446 Expression ret(GetPureNonlinearPart());
1447 std::vector<double> linval;
1448 std::vector<int> linidx;
1449 std::vector<std::string> linvn;
1450 double c = 0;
1451 GetPureLinearInfo(linval, linidx, linvn, c);
1452 int i;
1453 Expression addend(1.0, -1, NOTVARNAME);
1454 // we cycle backwards to keep the order of addends in ret
1455 for(i = linidx.size() - 1; i >= 0 ; i--)
1456 {
1457 if (ret->DependsOnVariable(linidx[i]))
1458 {
1459 // pure nonlinear part depends on varindex i, add it to ret
1460 addend->SetCoeff(linval[i]);
1461 addend->SetVarIndex(linidx[i]);
1462 addend->SetVarName(linvn[i]);
1463 ret = addend + ret;
1464 }
1465 }
1466 return ret;
1467 }
1468
1469
1470 // get the purely nonlinear part - e.g. only y^2 in x+y+y^2
GetPureNonlinearPart()1471 Expression BasicExpression::GetPureNonlinearPart()
1472 {
1473 Expression ret(0.0);
1474 if (!IsLeaf())
1475 {
1476 if (GetOpType() == SUM)
1477 {
1478 int i;
1479 for(i = 0; i < GetSize(); i++)
1480 {
1481 if (!GetNode(i)->IsLinear())
1482 {
1483 ret = SumLink(ret, GetNode(i));
1484 }
1485 }
1486 }
1487 else if (GetOpType() == DIFFERENCE)
1488 {
1489 int i;
1490 for(i = 0; i < GetSize(); i++)
1491 {
1492 if (!GetNode(i)->IsLinear())
1493 {
1494 ret = ret - GetNode(i);
1495 }
1496 }
1497 }
1498 else if (GetOpType() == PLUS)
1499 {
1500 ret = GetNode(0);
1501 }
1502 else if (GetOpType() == MINUS)
1503 {
1504 ret = GetNode(0);
1505 ret->SetCoeff(-ret->GetCoeff());
1506 }
1507 else
1508 {
1509 ret = *this;
1510 }
1511 }
1512 else
1513 {
1514 // leaf but can be a power
1515 if (GetExponent() != 0 && GetExponent() != 1)
1516 {
1517 ret = *this;
1518 }
1519 }
1520 return ret;
1521 }
1522
1523 // get value of additive constant
GetConstantPart()1524 double BasicExpression::GetConstantPart()
1525 {
1526 double ret = 0;
1527 if (IsConstant())
1528 {
1529 ret = GetValue();
1530 }
1531 else if (!IsLeaf())
1532 {
1533 int op = GetOpType();
1534 if (op == SUM || op == DIFFERENCE)
1535 {
1536 int i = 0;
1537 int sz = GetSize();
1538 while(i < sz)
1539 {
1540 if (GetNode(i)->IsConstant())
1541 {
1542 if (op == SUM || (op == DIFFERENCE && i == 0))
1543 {
1544 ret += GetNode(i)->GetValue();
1545 }
1546 else
1547 {
1548 ret -= GetNode(i)->GetValue();
1549 }
1550 }
1551 i++;
1552 }
1553 }
1554 }
1555 return ret;
1556 }
1557
1558 // doesn't deal with additive constants in PLUS/MINUS operands
RemoveAdditiveConstant()1559 double BasicExpression::RemoveAdditiveConstant()
1560 {
1561 double ret = 0;
1562 if (IsConstant())
1563 {
1564 ret = GetValue();
1565 SetValue(0);
1566 }
1567 else if (!IsLeaf())
1568 {
1569 int op = GetOpType();
1570 if (op == SUM || op == DIFFERENCE)
1571 {
1572 int i = 0;
1573 int sz = GetSize();
1574 while(i < sz)
1575 {
1576 if (GetNode(i)->IsConstant())
1577 {
1578 if (op == SUM || (op == DIFFERENCE && i == 0))
1579 {
1580 ret += GetNode(i)->GetValue();
1581 }
1582 else
1583 {
1584 ret -= GetNode(i)->GetValue();
1585 }
1586 DeleteNode(i);
1587 sz--;
1588 }
1589 else
1590 {
1591 i++;
1592 }
1593 }
1594 }
1595 }
1596 return ret;
1597 }
1598
1599 /************** expression creation (no change to args) ***************/
1600
1601 // BIG FAT WARNING: when you change these operators, also please
1602 // change their "-Link" counterparts!
1603
1604 // sums:
operator +(Expression a,Expression b)1605 Expression operator + (Expression a,
1606 Expression b)
1607 {
1608 Expression ret;
1609 // make a preliminary check
1610 if (a->GetCoeff() == 0 || a->HasValue(0))
1611 {
1612 ret.SetToCopyOf(b);
1613 return ret;
1614 }
1615 if (b->GetCoeff() == 0 || b->HasValue(0))
1616 {
1617 ret.SetToCopyOf(a);
1618 return ret;
1619 }
1620 if (!(a->IsConstant() && b->IsConstant()) && a->IsEqualToNoCoeff(b))
1621 {
1622 a->SetCoeff(a->GetCoeff() + b->GetCoeff());
1623 if (std::abs(a->GetCoeff()) < Ev3NearZero())
1624 {
1625 // simplify to zero - for differences
1626 Expression zero(0.0);
1627 return zero;
1628 }
1629 else
1630 {
1631 ret.SetToCopyOf(a);
1632 return ret;
1633 }
1634 }
1635 // go for it
1636 if (a->IsLeaf() && a->GetOpType() == CONST &&
1637 b->IsLeaf() && b->GetOpType() == CONST)
1638 {
1639 // a, b are numbers - add them
1640 ret.SetToCopyOf(a);
1641 ret->SetValue(a->GetValue() + b->GetValue());
1642 ret->SetCoeff(1.0);
1643 ret->SetExponent(1.0);
1644 return ret;
1645 }
1646 else if (a->IsLeaf() && a->GetOpType() == VAR &&
1647 b->IsLeaf() && b->GetOpType() == VAR &&
1648 a->GetVarIndex() == b->GetVarIndex() &&
1649 a->GetExponent() == b->GetExponent())
1650 {
1651 // a, b are the same variable - add coefficients
1652 ret.SetToCopyOf(a);
1653 ret->SetCoeff(a->GetCoeff() + b->GetCoeff());
1654 return ret;
1655 }
1656 else if (a->GetOpType() == SUM && b->GetOpType() != SUM)
1657 {
1658 // a is a sum and b isn't - just add the term b
1659 ret.SetToCopyOf(a);
1660 ret->DistributeCoeffOverSum();
1661 Int i = 0;
1662 bool couldsimplify = false;
1663 Expression tmp;
1664 // if t is a leaf and there is a like leaf in this,
1665 // just add it to the value/coefficient
1666 if (b->IsLeaf() && b->GetOpType() == CONST)
1667 {
1668 // b is a constant
1669 for (i = 0; i < ret->GetSize(); i++)
1670 {
1671 tmp = ret->GetNode(i);
1672 if (tmp->IsLeaf() && tmp->GetOpType() == CONST)
1673 {
1674 tmp->SetValue(tmp->GetValue() + b->GetValue() / ret->GetCoeff());
1675 tmp->SetCoeff(1.0);
1676 tmp->SetExponent(1.0); // NB: changing tmp should also change a
1677 couldsimplify = true;
1678 break;
1679 }
1680 }
1681 }
1682 else if (b->IsLeaf() && b->GetOpType() == VAR)
1683 {
1684 // b is a variable
1685 for (i = 0; i < ret->GetSize(); i++)
1686 {
1687 if (ret->GetNode(i)->IsLeaf() && ret->GetNode(i)->GetOpType() == VAR &&
1688 b->GetVarIndex() == ret->GetNode(i)->GetVarIndex() &&
1689 b->GetExponent() == ret->GetNode(i)->GetExponent())
1690 {
1691 double tc = ret->GetNode(i)->GetCoeff() +
1692 b->GetCoeff() / ret->GetCoeff();
1693 // warning: tc could be zero, but it would be cumbersome
1694 // to simplify it here - do it in SimplifyConstant
1695 ret->GetNode(i)->SetCoeff(tc);
1696 couldsimplify = true;
1697 break;
1698 }
1699 }
1700 }
1701 else if (!b->IsLeaf())
1702 {
1703 // a is a sum, b is a nonleaf, look for a subnode of a similar to b
1704 for (i = 0; i < ret->GetSize(); i++)
1705 {
1706 if (ret->GetNode(i)->IsEqualTo(b))
1707 {
1708 // found one, add coefficients - notice, as above, coeff could
1709 // be zero, but deal with that case in SimplifyConstant
1710 ret->GetNode(i)->SetCoeff(ret->GetNode(i)->GetCoeff()
1711 + b->GetCoeff());
1712 couldsimplify = true;
1713 break;
1714 }
1715 }
1716 }
1717 if (!couldsimplify)
1718 {
1719 // either could not simplify in steps above, or b is an operator
1720 ret->AddCopyOfNode(b);
1721 }
1722 return ret;
1723 }
1724 else if (a->GetOpType() == SUM && b->GetOpType() == SUM)
1725 {
1726 // a, b are sums - add terms of b to a
1727 b->DistributeCoeffOverSum();
1728 ret.SetToCopyOf(a);
1729 Int i = 0;
1730 Int s = b->GetSize();
1731 for (i = 0; i < s; i++)
1732 {
1733 ret = ret + b->GetNode(i);
1734 }
1735 return ret;
1736 }
1737 else if (a->GetOpType() != SUM && b->GetOpType() == SUM)
1738 {
1739 // a is not a sum but b is - transform this into a sum
1740 ret.SetToCopyOf(b);
1741 ret = ret + a;
1742 return ret;
1743 }
1744 else
1745 {
1746 // all other cases - make new node on top of the addends
1747 ret->SetOpType(SUM);
1748 ret->SetCoeff(1.0);
1749 ret->SetExponent(1.0);
1750 ret->AddCopyOfNode(a);
1751 ret->AddCopyOfNode(b);
1752 return ret;
1753 }
1754 }
1755
1756
1757 // product
operator *(Expression a,Expression t)1758 Expression operator * (Expression a,
1759 Expression t)
1760 {
1761 Expression ret;
1762 // make a preliminary check
1763 if (a->GetCoeff() == 0 || t->GetCoeff() == 0 ||
1764 a->HasValue(0) || t->HasValue(0))
1765 {
1766 Expression zero(0.0);
1767 return zero;
1768 }
1769 if (a->HasValue(1))
1770 {
1771 return t;
1772 }
1773 if (t->HasValue(1))
1774 {
1775 return a;
1776 }
1777 if (!(a->IsConstant() && t->IsConstant()) && a->IsEqualToNoCoeff(t))
1778 {
1779 Expression two(2.0);
1780 ret.SetToCopyOf(a);
1781 ret->SetCoeff(1.0);
1782 ret = ret ^ two;
1783 ret->SetCoeff(a->GetCoeff() * t->GetCoeff());
1784 return ret;
1785 }
1786 // go for it
1787 if (a->IsLeaf() && a->GetOpType() == CONST &&
1788 t->IsLeaf() && t->GetOpType() == CONST)
1789 {
1790 // a, t are numbers - multiply them
1791 ret.SetToCopyOf(a);
1792 ret->SetValue(a->GetValue() * t->GetValue());
1793 ret->SetCoeff(1.0);
1794 ret->SetExponent(1.0);
1795 return ret;
1796 }
1797 else if (a->IsLeaf() && a->GetOpType() == VAR &&
1798 t->IsLeaf() && t->GetOpType() == VAR &&
1799 a->GetVarIndex() == t->GetVarIndex())
1800 {
1801 // a, t are the same variable - multiply coefficients
1802 // and add exponents
1803 ret.SetToCopyOf(a);
1804 ret->SetCoeff(a->GetCoeff() * t->GetCoeff());
1805 ret->SetExponent(a->GetExponent() + t->GetExponent());
1806 return ret;
1807 }
1808 else if (t->IsConstant())
1809 {
1810 // t is constant, set coeff of a
1811 ret.SetToCopyOf(a);
1812 ret->SetCoeff(a->GetCoeff() * t->GetValue());
1813 ret->DistributeCoeffOverSum();
1814 return ret;
1815 }
1816 else if (a->IsConstant())
1817 {
1818 // a is constant, set coeff of t
1819 ret.SetToCopyOf(t);
1820 ret->SetCoeff(t->GetCoeff() * a->GetValue());
1821 ret->DistributeCoeffOverSum();
1822 return ret;
1823 }
1824 else if (a->GetOpType() == PRODUCT && t->GetOpType() != PRODUCT)
1825 {
1826 // a is a product and t isn't - just multiply the term t
1827 ret.SetToCopyOf(a);
1828 Int i = 0;
1829 bool couldsimplify = false;
1830 if (t->IsLeaf() && t->GetOpType() == VAR)
1831 {
1832 // t is a variable
1833 Expression tmp;
1834 for (i = 0; i < ret->GetSize(); i++)
1835 {
1836 tmp = ret->GetNode(i);
1837 if (tmp->IsLeaf() && tmp->GetOpType() == VAR &&
1838 t->GetVarIndex() == tmp->GetVarIndex())
1839 {
1840 // found same variable in a, multiply coeffs and add exponents
1841 tmp->SetCoeff(tmp->GetCoeff() * t->GetCoeff());
1842 tmp->SetExponent(tmp->GetExponent() + t->GetExponent());
1843 couldsimplify = true;
1844 break;
1845 }
1846 }
1847 }
1848 // here we shan't try to simplify f*f <-- f^2 (f nonleaf)
1849 // because a product of nonleaves is easier to manipulate than
1850 // a power (as it adds a depth level)
1851 if (!couldsimplify)
1852 {
1853 // either could not simplify in steps above, or t is an operator
1854 ret->AddCopyOfNode(t);
1855 }
1856 return ret;
1857 }
1858 else if (a->GetOpType() == PRODUCT && t->GetOpType() == PRODUCT)
1859 {
1860 // a, t are products - multiply terms of t to a
1861 t->DistributeCoeffOverProduct();
1862 ret.SetToCopyOf(a);
1863 Int s = t->GetSize();
1864 for (Int i = 0; i < s; i++)
1865 {
1866 ret = ret * t->GetNode(i);
1867 }
1868 return ret;
1869 }
1870 else if (a->GetOpType() != PRODUCT && t->GetOpType() == PRODUCT)
1871 {
1872 // a is not a products but t is - transform this into a product
1873 ret.SetToCopyOf(t);
1874 ret = ret * a;
1875 return ret;
1876 }
1877 else
1878 {
1879 // all other cases - make new node on top of the addends
1880 ret->SetCoeff(1.0);
1881 ret->SetExponent(1.0);
1882 ret->SetOpType(PRODUCT);
1883 ret->AddCopyOfNode(a);
1884 ret->AddCopyOfNode(t);
1885 return ret;
1886 }
1887 }
1888
1889 // fractions:
operator /(Expression a,Expression t)1890 Expression operator / (Expression a,
1891 Expression t)
1892 {
1893 Expression ret;
1894 // make a preliminary check
1895 if (t->GetCoeff() == 0)
1896 {
1897 // divide by zero
1898 unsigned long mycode(0);
1899 std::string myif("Expression Building");
1900 std::string myscope("operator/");
1901 std::string myop("t.GetCoeff()==0");
1902 std::string mydesc("Divisor cannot be zero");
1903 std::string myinfo(HELPURL);
1904 std::string mydiv(NONE);
1905 throw ErrDivideByZero(mycode, myif, myscope, myop, mydesc, myinfo, mydiv);
1906 }
1907 if (a->GetCoeff() == 0 || a->HasValue(0))
1908 {
1909 // dividend has zero coeff, return zero
1910 Expression zero(0.0);
1911 return zero;
1912 }
1913 if (t->HasValue(1))
1914 {
1915 ret.SetToCopyOf(a);
1916 return ret;
1917 }
1918 if (!(a->IsConstant() && t->IsConstant()) && a->IsEqualToNoCoeff(t))
1919 {
1920 // dividend = divisor, return ratio of coefficients
1921 Expression one(1.0);
1922 one->SetCoeff(a->GetCoeff() / t->GetCoeff());
1923 return one;
1924 }
1925 // go for it
1926 if (a->IsLeaf() && a->GetOpType() == CONST &&
1927 t->IsLeaf() && t->GetOpType() == CONST)
1928 {
1929 // a, t are numbers - divide them
1930 if (t->GetValue() == 0)
1931 {
1932 unsigned long mycode(0);
1933 std::string myif("Expression Building");
1934 std::string myscope("operator/");
1935 std::string myop("t.GetValue()==0");
1936 std::string mydesc("Divisor cannot be zero");
1937 std::string myinfo(HELPURL);
1938 std::string mydiv(NONE);
1939 throw ErrDivideByZero(mycode, myif, myscope, myop, mydesc, myinfo, mydiv);
1940 }
1941 else
1942 {
1943 ret.SetToCopyOf(a);
1944 ret->SetValue(a->GetValue() / t->GetValue());
1945 ret->SetCoeff(1.0);
1946 ret->SetExponent(1.0);
1947 return ret;
1948 }
1949 }
1950 else if (t->HasValue(1))
1951 {
1952 // divide by constant 1, don't do anything
1953 ret.SetToCopyOf(a);
1954 return ret;
1955 }
1956 else if (t->IsConstant())
1957 {
1958 // t is constant, set coeff of a
1959 ret.SetToCopyOf(a);
1960 ret->SetCoeff(a->GetCoeff() / t->GetValue());
1961 ret->DistributeCoeffOverSum();
1962 return ret;
1963 }
1964 else if (a->IsVariable() && t->IsVariable() &&
1965 a->GetVarIndex() == t->GetVarIndex())
1966 {
1967 // cx^e / dx^f = (c/d)x^(e-f)
1968 ret.SetToCopyOf(a);
1969 double te = a->GetExponent() - t->GetExponent();
1970 double tc = a->GetCoeff() / t->GetCoeff();
1971 if (std::abs(te) < Ev3NearZero())
1972 {
1973 Expression c(tc);
1974 return c;
1975 }
1976 ret->SetCoeff(tc);
1977 ret->SetExponent(te);
1978 return ret;
1979 }
1980 else if (a->IsVariable() && t->GetOpType() == PRODUCT)
1981 {
1982 // a is a variable, t is a product - see if a appears in t
1983 // and cancel common term
1984 // first simplify coeffs of divisor
1985 Expression at;
1986 at.SetToCopyOf(a);
1987 ret.SetToCopyOf(t);
1988 ret->ConsolidateProductCoeffs();
1989 // denominator
1990 if (std::abs(ret->GetCoeff()) < Ev3NearZero())
1991 {
1992 // divide by zero
1993 unsigned long mycode(22);
1994 std::string myif("Expression Building");
1995 std::string myscope("operator/");
1996 std::string myop("t->GetCoeff()");
1997 std::string mydesc("Divisor cannot be zero");
1998 std::string myinfo(HELPURL);
1999 std::string mydiv(NONE);
2000 throw ErrDivideByZero(mycode, myif, myscope, myop, mydesc, myinfo, mydiv);
2001 }
2002 if (std::abs(at->GetCoeff()) < Ev3NearZero())
2003 {
2004 Expression zero(0.0);
2005 return zero;
2006 }
2007 double accumulatedcoeff = at->GetCoeff() / ret->GetCoeff();
2008 at->SetCoeff(1.0);
2009 ret->SetCoeff(1.0);
2010 // now try simplification
2011 Int i;
2012 for (i = 0; i < ret->GetSize(); i++)
2013 {
2014 if (ret->GetNode(i)->GetOpType() == VAR &&
2015 at->GetVarIndex() == ret->GetNode(i)->GetVarIndex())
2016 {
2017 double te = at->GetExponent() - ret->GetNode(i)->GetExponent();
2018 if (std::abs(te) < Ev3NearZero())
2019 {
2020 // exponents are the same, just cancel
2021 at->One();
2022 ret->DeleteNode(i);
2023 }
2024 else if (te > 0)
2025 {
2026 // numerator remains, cancel denominator
2027 at->SetExponent(te);
2028 ret->DeleteNode(i);
2029 }
2030 else if (te < 0)
2031 {
2032 // numerator goes to one, denominator remains
2033 at->One();
2034 ret->GetNode(i)->SetExponent(-te);
2035 }
2036 // exit loop
2037 break;
2038 }
2039 }
2040 // check that denominator (t) has more than one operand;
2041 // if not, bring up a rank level
2042 if (ret->GetSize() == 1)
2043 {
2044 ret = ret->GetNode(0);
2045 }
2046 // build ratio
2047 Expression ret2;
2048 ret2->SetOpType(FRACTION);
2049 ret2->SetCoeff(accumulatedcoeff);
2050 ret2->SetExponent(1.0);
2051 ret2->AddCopyOfNode(at);
2052 ret2->AddCopyOfNode(ret);
2053 return ret2;
2054 }
2055 else if (t->IsVariable() && a->GetOpType() == PRODUCT)
2056 {
2057 // t is a variable, a is a product - see if t appears in a
2058 // and cancel common term
2059 // first simplify coeffs of divisor
2060 Expression bt;
2061 bt.SetToCopyOf(t);
2062 ret.SetToCopyOf(a);
2063 ret->ConsolidateProductCoeffs();
2064 // denominator - already checked
2065 if (std::abs(ret->GetCoeff()) < Ev3NearZero())
2066 {
2067 Expression zero(0.0);
2068 return zero;
2069 }
2070 double accumulatedcoeff = ret->GetCoeff() / bt->GetCoeff();
2071 ret->SetCoeff(1.0);
2072 bt->SetCoeff(1.0);
2073 // now try simplification
2074 Int i;
2075 for (i = 0; i < ret->GetSize(); i++)
2076 {
2077 if (ret->GetNode(i)->GetOpType() == VAR &&
2078 bt->GetVarIndex() == ret->GetNode(i)->GetVarIndex())
2079 {
2080 double te = ret->GetNode(i)->GetExponent() - bt->GetExponent();
2081 if (std::abs(te) < Ev3NearZero())
2082 {
2083 // exponents are the same, just cancel
2084 bt->One();
2085 ret->DeleteNode(i);
2086 }
2087 else if (te > 0)
2088 {
2089 // numerator remains, cancel denominator
2090 bt->One();
2091 ret->GetNode(i)->SetExponent(te);
2092 }
2093 else if (te < 0)
2094 {
2095 // numerator goes to one, denominator remains
2096 bt->SetExponent(-te);
2097 ret->DeleteNode(i);
2098 }
2099 // exit loop
2100 break;
2101 }
2102 }
2103 // check that numerator (a) has more than one operands;
2104 // if not, bring up a rank level
2105 if (ret->GetSize() == 1)
2106 {
2107 ret = ret->GetNode(0);
2108 }
2109 // build ratio
2110 Expression ret2;
2111 ret2->SetOpType(FRACTION);
2112 ret2->SetCoeff(accumulatedcoeff);
2113 ret2->SetExponent(1.0);
2114 ret2->AddCopyOfNode(ret);
2115 ret2->AddCopyOfNode(bt);
2116 return ret2;
2117 }
2118 else if (a->GetOpType() == PRODUCT && t->GetOpType() == PRODUCT)
2119 {
2120 // a, t are products, try to cancel common terms
2121 Expression at;
2122 Expression bt;
2123 at.SetToCopyOf(a);
2124 bt.SetToCopyOf(t);
2125 Int i = 0, j = 0;
2126 double accumulatedcoeff;
2127 // first simplify coefficients of operands
2128 at->ConsolidateProductCoeffs();
2129 bt->ConsolidateProductCoeffs();
2130 // denominator
2131 if (std::abs(bt->GetCoeff()) < Ev3NearZero())
2132 {
2133 // divide by zero
2134 unsigned long mycode(21);
2135 std::string myif("Expression Building");
2136 std::string myscope("operator/");
2137 std::string myop("t->GetCoeff()");
2138 std::string mydesc("Divisor cannot be zero");
2139 std::string myinfo(HELPURL);
2140 std::string mydiv(NONE);
2141 throw ErrDivideByZero(mycode, myif, myscope, myop, mydesc, myinfo, mydiv);
2142 }
2143 if (std::abs(at->GetCoeff()) < Ev3NearZero())
2144 {
2145 Expression zero(0.0);
2146 return zero;
2147 }
2148 // save ratio of coeffs of products
2149 accumulatedcoeff = at->GetCoeff() / bt->GetCoeff();
2150 at->SetCoeff(1.0);
2151 bt->SetCoeff(1.0);
2152 // now try simplification
2153 i = 0;
2154 bool isnumeratorempty = false;
2155 bool isdenominatorempty = false;
2156 int szi = at->GetSize();
2157 int szj = bt->GetSize();
2158 while(!isnumeratorempty && !isdenominatorempty && i < szi)
2159 {
2160 j = 0;
2161 while(!isnumeratorempty && !isdenominatorempty && j < szj)
2162 {
2163 if (at->GetNode(i)->IsEqualTo(bt->GetNode(j)))
2164 {
2165 // found like terms i and j
2166 at->DeleteNode(i);
2167 szi--;
2168 if(szi == 0)
2169 {
2170 isnumeratorempty = true;
2171 at->One();
2172 }
2173 bt->DeleteNode(j);
2174 szj--;
2175 if (szj == 0)
2176 {
2177 isdenominatorempty = true;
2178 bt->One();
2179 }
2180 i--; // cancel the effect of the later i++
2181 break; // go to outer cycle
2182 }
2183 else
2184 {
2185 j++;
2186 }
2187 }
2188 i++;
2189 }
2190 if (bt->HasValue(1))
2191 {
2192 // denominator is 1, return a
2193 at->SetCoeff(accumulatedcoeff);
2194 return at;
2195 }
2196 // now construct fraction
2197 // check that numerator, denominator have more than one operands;
2198 // if not, bring up a rank level
2199 if (at->GetSize() == 1)
2200 {
2201 at = at->GetNode(0);
2202 }
2203 if (bt->GetSize() == 1)
2204 {
2205 bt = bt->GetNode(0);
2206 }
2207 ret->SetCoeff(accumulatedcoeff); // already contains coeffs of a, t
2208 ret->SetExponent(1.0);
2209 ret->SetOpType(FRACTION);
2210 ret->AddCopyOfNode(at);
2211 ret->AddCopyOfNode(bt);
2212 return ret;
2213 }
2214 else
2215 {
2216 Expression at;
2217 Expression bt;
2218 at.SetToCopyOf(a);
2219 bt.SetToCopyOf(t);
2220 ret->SetCoeff(at->GetCoeff() / bt->GetCoeff());
2221 at->SetCoeff(1.0);
2222 bt->SetCoeff(1.0);
2223 ret->SetExponent(1.0);
2224 ret->SetOpType(FRACTION);
2225 ret->AddCopyOfNode(at);
2226 ret->AddCopyOfNode(bt);
2227 return ret;
2228 }
2229 }
2230
2231 // unary minus:
operator -(Expression a)2232 Expression operator - (Expression a)
2233 {
2234 Expression ret;
2235 ret.SetToCopyOf(a);
2236 if (ret->IsLeaf() && ret->GetOpType() == CONST)
2237 {
2238 ret->SetValue(- ret->GetValue());
2239 ret->SetCoeff(1.0);
2240 ret->SetExponent(1.0);
2241 }
2242 else
2243 {
2244 ret->SetCoeff(- ret->GetCoeff());
2245 }
2246 return ret;
2247 }
2248
2249 // binary minus:
operator -(Expression a,Expression b)2250 Expression operator - (Expression a,
2251 Expression b)
2252 {
2253 Expression ret;
2254 if (a->HasValue(0))
2255 return -b;
2256 if (b->HasValue(0))
2257 {
2258 ret.SetToCopyOf(a);
2259 return a;
2260 }
2261 ret = a + (-b);
2262 return ret;
2263 }
2264
2265 // power:
operator ^(Expression a,Expression t)2266 Expression operator ^ (Expression a,
2267 Expression t)
2268 {
2269 // make a preliminary check
2270 Expression ret;
2271 if (a->GetCoeff() == 0)
2272 {
2273 // *this is zero, just return zero
2274 Expression zero(0.0);
2275 return zero;
2276 }
2277 if (t->HasValue(0.0))
2278 {
2279 // exponent is 0, just return 1
2280 Expression one(1.0);
2281 return one;
2282 }
2283 else if (t->HasValue(1.0))
2284 {
2285 // exponent is 1, just return a
2286 ret.SetToCopyOf(a);
2287 return ret;
2288 }
2289 if (a->HasValue(0.0))
2290 {
2291 // base is zero, return 0
2292 Expression zero(0.0);
2293 return zero;
2294 }
2295 else if (a->HasValue(1.0))
2296 {
2297 // base is one, return 1
2298 Expression one(1.0);
2299 return one;
2300 }
2301 // go for it
2302 if (a->IsLeaf() && a->GetOpType() == CONST &&
2303 t->IsLeaf() && t->GetOpType() == CONST)
2304 {
2305 // constant to constant
2306 ret.SetToCopyOf(a);
2307 ret->SetValue(pow(ret->GetValue(), t->GetValue()));
2308 ret->SetCoeff(1.0);
2309 ret->SetExponent(1.0);
2310 return ret;
2311 }
2312 else if (a->IsLeaf() && a->GetOpType() == VAR &&
2313 t->IsLeaf() && t->GetOpType() == CONST)
2314 {
2315 // variable to constant
2316 ret.SetToCopyOf(a);
2317 ret->SetCoeff(pow(ret->GetCoeff(), t->GetValue()));
2318 ret->SetExponent(ret->GetExponent() * t->GetValue());
2319 return ret;
2320 }
2321 else
2322 {
2323 ret->SetCoeff(1.0);
2324 ret->SetExponent(1.0);
2325 ret->SetOpType(POWER);
2326 ret->AddCopyOfNode(a);
2327 ret->AddCopyOfNode(t);
2328 return ret;
2329 }
2330 }
2331
Sin(Expression a)2332 Expression Sin(Expression a)
2333 {
2334 // go for it
2335 if (a->IsLeaf() && a->GetOpType() == CONST)
2336 {
2337 Expression ret;
2338 ret.SetToCopyOf(a);
2339 ret->SetCoeff(1.0);
2340 ret->SetValue(sin(a->GetValue()));
2341 ret->SetExponent(1.0);
2342 ret->SetOpType(CONST);
2343 return ret;
2344 }
2345 else
2346 {
2347 Expression ret;
2348 ret->SetCoeff(1.0);
2349 ret->SetExponent(1.0);
2350 ret->SetOpType(SIN);
2351 ret->AddCopyOfNode(a);
2352 return ret;
2353 }
2354 }
2355
Cos(Expression a)2356 Expression Cos(Expression a)
2357 {
2358 // go for it
2359 if (a->IsLeaf() && a->GetOpType() == CONST)
2360 {
2361 Expression ret;
2362 ret.SetToCopyOf(a);
2363 ret->SetCoeff(1.0);
2364 ret->SetValue(cos(a->GetValue()));
2365 ret->SetExponent(1.0);
2366 ret->SetOpType(CONST);
2367 return ret;
2368 }
2369 else
2370 {
2371 Expression ret;
2372 ret->SetCoeff(1.0);
2373 ret->SetExponent(1.0);
2374 ret->SetOpType(COS);
2375 ret->AddCopyOfNode(a);
2376 return ret;
2377 }
2378 }
2379
Tan(Expression a)2380 Expression Tan(Expression a)
2381 {
2382 // go for it
2383 if (a->IsLeaf() && a->GetOpType() == CONST)
2384 {
2385 Expression ret;
2386 ret.SetToCopyOf(a);
2387 ret->SetCoeff(1.0);
2388 ret->SetValue(tan(a->GetValue()));
2389 ret->SetExponent(1.0);
2390 ret->SetOpType(CONST);
2391 return ret;
2392 }
2393 else
2394 {
2395 Expression ret;
2396 ret->SetCoeff(1.0);
2397 ret->SetExponent(1.0);
2398 ret->SetOpType(TAN);
2399 ret->AddCopyOfNode(a);
2400 return ret;
2401 }
2402 }
2403
Asin(Expression a)2404 Expression Asin(Expression a)
2405 {
2406 // go for it
2407 if (a->IsLeaf() && a->GetOpType() == CONST)
2408 {
2409 Expression ret;
2410 ret.SetToCopyOf(a);
2411 ret->SetCoeff(1.0);
2412 ret->SetValue(asin(a->GetValue()));
2413 ret->SetExponent(1.0);
2414 ret->SetOpType(CONST);
2415 return ret;
2416 }
2417 else
2418 {
2419 Expression ret;
2420 ret->SetCoeff(1.0);
2421 ret->SetExponent(1.0);
2422 ret->SetOpType(ASIN);
2423 ret->AddCopyOfNode(a);
2424 return ret;
2425 }
2426 }
2427
Acos(Expression a)2428 Expression Acos(Expression a)
2429 {
2430 // go for it
2431 if (a->IsLeaf() && a->GetOpType() == CONST)
2432 {
2433 Expression ret;
2434 ret.SetToCopyOf(a);
2435 ret->SetCoeff(1.0);
2436 ret->SetValue(acos(a->GetValue()));
2437 ret->SetExponent(1.0);
2438 ret->SetOpType(CONST);
2439 return ret;
2440 }
2441 else
2442 {
2443 Expression ret;
2444 ret->SetCoeff(1.0);
2445 ret->SetExponent(1.0);
2446 ret->SetOpType(ACOS);
2447 ret->AddCopyOfNode(a);
2448 return ret;
2449 }
2450 }
2451
Atan(Expression a)2452 Expression Atan(Expression a)
2453 {
2454 // go for it
2455 if (a->IsLeaf() && a->GetOpType() == CONST)
2456 {
2457 Expression ret;
2458 ret.SetToCopyOf(a);
2459 ret->SetCoeff(1.0);
2460 ret->SetValue(atan(a->GetValue()));
2461 ret->SetExponent(1.0);
2462 ret->SetOpType(CONST);
2463 return ret;
2464 }
2465 else
2466 {
2467 Expression ret;
2468 ret->SetCoeff(1.0);
2469 ret->SetExponent(1.0);
2470 ret->SetOpType(ATAN);
2471 ret->AddCopyOfNode(a);
2472 return ret;
2473 }
2474 }
2475
Sinh(Expression a)2476 Expression Sinh(Expression a)
2477 {
2478 // go for it
2479 if (a->IsLeaf() && a->GetOpType() == CONST)
2480 {
2481 Expression ret;
2482 ret.SetToCopyOf(a);
2483 ret->SetCoeff(1.0);
2484 ret->SetValue(sinh(a->GetValue()));
2485 ret->SetExponent(1.0);
2486 ret->SetOpType(CONST);
2487 return ret;
2488 }
2489 else
2490 {
2491 Expression ret;
2492 ret->SetCoeff(1.0);
2493 ret->SetExponent(1.0);
2494 ret->SetOpType(SINH);
2495 ret->AddCopyOfNode(a);
2496 return ret;
2497 }
2498 }
2499
Cosh(Expression a)2500 Expression Cosh(Expression a)
2501 {
2502 // go for it
2503 if (a->IsLeaf() && a->GetOpType() == CONST)
2504 {
2505 Expression ret;
2506 ret.SetToCopyOf(a);
2507 ret->SetCoeff(1.0);
2508 ret->SetValue(cosh(a->GetValue()));
2509 ret->SetExponent(1.0);
2510 ret->SetOpType(CONST);
2511 return ret;
2512 }
2513 else
2514 {
2515 Expression ret;
2516 ret->SetCoeff(1.0);
2517 ret->SetExponent(1.0);
2518 ret->SetOpType(COSH);
2519 ret->AddCopyOfNode(a);
2520 return ret;
2521 }
2522 }
2523
Tanh(Expression a)2524 Expression Tanh(Expression a)
2525 {
2526 // go for it
2527 if (a->IsLeaf() && a->GetOpType() == CONST)
2528 {
2529 Expression ret;
2530 ret.SetToCopyOf(a);
2531 ret->SetCoeff(1.0);
2532 ret->SetValue(tanh(a->GetValue()));
2533 ret->SetExponent(1.0);
2534 ret->SetOpType(CONST);
2535 return ret;
2536 }
2537 else
2538 {
2539 Expression ret;
2540 ret->SetCoeff(1.0);
2541 ret->SetExponent(1.0);
2542 ret->SetOpType(TANH);
2543 ret->AddCopyOfNode(a);
2544 return ret;
2545 }
2546 }
2547
Asinh(Expression a)2548 Expression Asinh(Expression a)
2549 {
2550 // go for it
2551 if (a->IsLeaf() && a->GetOpType() == CONST)
2552 {
2553 Expression ret;
2554 ret.SetToCopyOf(a);
2555 ret->SetCoeff(1.0);
2556 ret->SetValue(asinh(a->GetValue()));
2557 ret->SetExponent(1.0);
2558 ret->SetOpType(CONST);
2559 return ret;
2560 }
2561 else
2562 {
2563 Expression ret;
2564 ret->SetCoeff(1.0);
2565 ret->SetExponent(1.0);
2566 ret->SetOpType(ASINH);
2567 ret->AddCopyOfNode(a);
2568 return ret;
2569 }
2570 }
2571
Acosh(Expression a)2572 Expression Acosh(Expression a)
2573 {
2574 // go for it
2575 if (a->IsLeaf() && a->GetOpType() == CONST)
2576 {
2577 Expression ret;
2578 ret.SetToCopyOf(a);
2579 ret->SetCoeff(1.0);
2580 ret->SetValue(acosh(a->GetValue()));
2581 ret->SetExponent(1.0);
2582 ret->SetOpType(CONST);
2583 return ret;
2584 }
2585 else
2586 {
2587 Expression ret;
2588 ret->SetCoeff(1.0);
2589 ret->SetExponent(1.0);
2590 ret->SetOpType(ACOSH);
2591 ret->AddCopyOfNode(a);
2592 return ret;
2593 }
2594 }
2595
Atanh(Expression a)2596 Expression Atanh(Expression a)
2597 {
2598 // go for it
2599 if (a->IsLeaf() && a->GetOpType() == CONST)
2600 {
2601 Expression ret;
2602 ret.SetToCopyOf(a);
2603 ret->SetCoeff(1.0);
2604 ret->SetValue(atanh(a->GetValue()));
2605 ret->SetExponent(1.0);
2606 ret->SetOpType(CONST);
2607 return ret;
2608 }
2609 else
2610 {
2611 Expression ret;
2612 ret->SetCoeff(1.0);
2613 ret->SetExponent(1.0);
2614 ret->SetOpType(ATANH);
2615 ret->AddCopyOfNode(a);
2616 return ret;
2617 }
2618 }
2619
Log2(Expression a)2620 Expression Log2(Expression a)
2621 {
2622 // make a preliminary check
2623 if (a->IsZero())
2624 {
2625 // *this is zero, can't do
2626 unsigned long mycode(0);
2627 std::string myif("Expression Building");
2628 std::string myscope("Log2");
2629 std::string myop("IsZero()");
2630 std::string mydesc("log2(0) is undefined");
2631 std::string myinfo(HELPURL);
2632 throw ErrNotPermitted(mycode, myif, myscope, myop, mydesc, myinfo);
2633 }
2634 if (a->IsLessThan(0))
2635 {
2636 // argument is < zero, can't do
2637 unsigned long mycode(0);
2638 std::string myif("Expression Building");
2639 std::string myscope("Log2");
2640 std::string myop("value <= 0");
2641 std::string mydesc("log2(<=0) is undefined");
2642 std::string myinfo(HELPURL);
2643 throw ErrNotPermitted(mycode, myif, myscope, myop, mydesc, myinfo);
2644 }
2645 // go for it
2646 if (a->IsLeaf() && a->GetOpType() == CONST)
2647 {
2648 Expression ret;
2649 ret.SetToCopyOf(a);
2650 double t = ret->GetValue();
2651 assert(t >= 0);
2652 ret->SetCoeff(1.0);
2653 ret->SetValue(log2(t));
2654 ret->SetExponent(1.0);
2655 ret->SetOpType(CONST);
2656 return ret;
2657 }
2658 else
2659 {
2660 Expression ret;
2661 ret->SetCoeff(1.0);
2662 ret->SetExponent(1.0);
2663 ret->SetOpType(LOG2);
2664 ret->AddCopyOfNode(a);
2665 return ret;
2666 }
2667 }
2668
Log10(Expression a)2669 Expression Log10(Expression a)
2670 {
2671 // make a preliminary check
2672 if (a->IsZero())
2673 {
2674 // *this is zero, can't do
2675 unsigned long mycode(0);
2676 std::string myif("Expression Building");
2677 std::string myscope("Log10");
2678 std::string myop("IsZero()");
2679 std::string mydesc("log10(0) is undefined");
2680 std::string myinfo(HELPURL);
2681 throw ErrNotPermitted(mycode, myif, myscope, myop, mydesc, myinfo);
2682 }
2683 if (a->IsLessThan(0))
2684 {
2685 // argument is < zero, can't do
2686 unsigned long mycode(0);
2687 std::string myif("Expression Building");
2688 std::string myscope("Log10");
2689 std::string myop("value <= 0");
2690 std::string mydesc("log10(<=0) is undefined");
2691 std::string myinfo(HELPURL);
2692 throw ErrNotPermitted(mycode, myif, myscope, myop, mydesc, myinfo);
2693 }
2694 // go for it
2695 if (a->IsLeaf() && a->GetOpType() == CONST)
2696 {
2697 Expression ret;
2698 ret.SetToCopyOf(a);
2699 double t = ret->GetValue();
2700 assert(t >= 0);
2701 ret->SetCoeff(1.0);
2702 ret->SetValue(log10(t));
2703 ret->SetExponent(1.0);
2704 ret->SetOpType(CONST);
2705 return ret;
2706 }
2707 else
2708 {
2709 Expression ret;
2710 ret->SetCoeff(1.0);
2711 ret->SetExponent(1.0);
2712 ret->SetOpType(LOG10);
2713 ret->AddCopyOfNode(a);
2714 return ret;
2715 }
2716 }
2717
Log(Expression a)2718 Expression Log(Expression a)
2719 {
2720 // make a preliminary check
2721 if (a->IsZero())
2722 {
2723 // *this is zero, can't do
2724 unsigned long mycode(0);
2725 std::string myif("Expression Building");
2726 std::string myscope("Log");
2727 std::string myop("IsZero()");
2728 std::string mydesc("log(0) is undefined");
2729 std::string myinfo(HELPURL);
2730 throw ErrNotPermitted(mycode, myif, myscope, myop, mydesc, myinfo);
2731 }
2732 if (a->IsLessThan(0))
2733 {
2734 // argument is < zero, can't do
2735 unsigned long mycode(0);
2736 std::string myif("Expression Building");
2737 std::string myscope("Log");
2738 std::string myop("value <= 0");
2739 std::string mydesc("log(<=0) is undefined");
2740 std::string myinfo(HELPURL);
2741 throw ErrNotPermitted(mycode, myif, myscope, myop, mydesc, myinfo);
2742 }
2743 // go for it
2744 if (a->IsLeaf() && a->GetOpType() == CONST)
2745 {
2746 Expression ret;
2747 ret.SetToCopyOf(a);
2748 double t = ret->GetValue();
2749 assert(t >= 0);
2750 ret->SetCoeff(1.0);
2751 ret->SetValue(log(t));
2752 ret->SetExponent(1.0);
2753 ret->SetOpType(CONST);
2754 return ret;
2755 }
2756 else
2757 {
2758 Expression ret;
2759 ret->SetCoeff(1.0);
2760 ret->SetExponent(1.0);
2761 ret->SetOpType(LOG);
2762 ret->AddCopyOfNode(a);
2763 return ret;
2764 }
2765 }
2766
Ln(Expression a)2767 Expression Ln(Expression a)
2768 {
2769 // make a preliminary check
2770 if (a->IsZero())
2771 {
2772 // *this is zero, can't do
2773 unsigned long mycode(0);
2774 std::string myif("Expression Building");
2775 std::string myscope("Ln");
2776 std::string myop("IsZero()");
2777 std::string mydesc("ln(0) is undefined");
2778 std::string myinfo(HELPURL);
2779 throw ErrNotPermitted(mycode, myif, myscope, myop, mydesc, myinfo);
2780 }
2781 if (a->IsLessThan(0))
2782 {
2783 // argument is < zero, can't do
2784 unsigned long mycode(0);
2785 std::string myif("Expression Building");
2786 std::string myscope("Ln");
2787 std::string myop("value <= 0");
2788 std::string mydesc("ln(<=0) is undefined");
2789 std::string myinfo(HELPURL);
2790 throw ErrNotPermitted(mycode, myif, myscope, myop, mydesc, myinfo);
2791 }
2792 // go for it
2793 if (a->IsLeaf() && a->GetOpType() == CONST)
2794 {
2795 Expression ret;
2796 ret.SetToCopyOf(a);
2797 double t = ret->GetValue();
2798 assert(t >= 0);
2799 ret->SetCoeff(1.0);
2800 ret->SetValue(log(t));
2801 ret->SetExponent(1.0);
2802 ret->SetOpType(CONST);
2803 return ret;
2804 }
2805 else
2806 {
2807 Expression ret;
2808 ret->SetCoeff(1.0);
2809 ret->SetExponent(1.0);
2810 ret->SetOpType(LN);
2811 ret->AddCopyOfNode(a);
2812 return ret;
2813 }
2814 }
2815
Lngamma(Expression a)2816 Expression Lngamma(Expression a)
2817 {
2818 // go for it
2819 if (a->IsLeaf() && a->GetOpType() == CONST)
2820 {
2821 Expression ret;
2822 ret.SetToCopyOf(a);
2823 ret->SetCoeff(1.0);
2824 ret->SetValue(lgamma(a->GetValue()));
2825 ret->SetExponent(1.0);
2826 ret->SetOpType(CONST);
2827 return ret;
2828 }
2829 else
2830 {
2831 Expression ret;
2832 ret->SetCoeff(1.0);
2833 ret->SetExponent(1.0);
2834 ret->SetOpType(LNGAMMA);
2835 ret->AddCopyOfNode(a);
2836 return ret;
2837 }
2838 }
2839
Gamma(Expression a)2840 Expression Gamma(Expression a)
2841 {
2842 // go for it
2843 if (a->IsLeaf() && a->GetOpType() == CONST)
2844 {
2845 Expression ret;
2846 ret.SetToCopyOf(a);
2847 ret->SetCoeff(1.0);
2848 ret->SetValue(exp(lgamma(a->GetValue())));
2849 ret->SetExponent(1.0);
2850 ret->SetOpType(CONST);
2851 return ret;
2852 }
2853 else
2854 {
2855 Expression ret;
2856 ret->SetCoeff(1.0);
2857 ret->SetExponent(1.0);
2858 ret->SetOpType(GAMMA);
2859 ret->AddCopyOfNode(a);
2860 return ret;
2861 }
2862 }
2863
Exp(Expression a)2864 Expression Exp(Expression a)
2865 {
2866 // go for it
2867 if (a->IsLeaf() && a->GetOpType() == CONST)
2868 {
2869 Expression ret;
2870 ret.SetToCopyOf(a);
2871 ret->SetCoeff(1.0);
2872 ret->SetValue(exp(a->GetValue()));
2873 ret->SetExponent(1.0);
2874 ret->SetOpType(CONST);
2875 return ret;
2876 }
2877 else
2878 {
2879 Expression ret;
2880 ret->SetCoeff(1.0);
2881 ret->SetExponent(1.0);
2882 ret->SetOpType(EXP);
2883 ret->AddCopyOfNode(a);
2884 return ret;
2885 }
2886 }
2887
Erf(Expression a)2888 Expression Erf(Expression a)
2889 {
2890 // go for it
2891 if (a->IsLeaf() && a->GetOpType() == CONST)
2892 {
2893 Expression ret;
2894 ret.SetToCopyOf(a);
2895 ret->SetCoeff(1.0);
2896 ret->SetValue(erf(a->GetValue()));
2897 ret->SetExponent(1.0);
2898 ret->SetOpType(CONST);
2899 return ret;
2900 }
2901 else
2902 {
2903 Expression ret;
2904 ret->SetCoeff(1.0);
2905 ret->SetExponent(1.0);
2906 ret->SetOpType(ERF);
2907 ret->AddCopyOfNode(a);
2908 return ret;
2909 }
2910 }
2911
Erfc(Expression a)2912 Expression Erfc(Expression a)
2913 {
2914 // go for it
2915 if (a->IsLeaf() && a->GetOpType() == CONST)
2916 {
2917 Expression ret;
2918 ret.SetToCopyOf(a);
2919 ret->SetCoeff(1.0);
2920 ret->SetValue(erfc(a->GetValue()));
2921 ret->SetExponent(1.0);
2922 ret->SetOpType(CONST);
2923 return ret;
2924 }
2925 else
2926 {
2927 Expression ret;
2928 ret->SetCoeff(1.0);
2929 ret->SetExponent(1.0);
2930 ret->SetOpType(ERFC);
2931 ret->AddCopyOfNode(a);
2932 return ret;
2933 }
2934 }
2935
Sqrt(Expression a)2936 Expression Sqrt(Expression a)
2937 {
2938 // make a preliminary check
2939 if (a->IsLessThan(0) && !a->HasValue(0))
2940 {
2941 // argument is < zero, can't do
2942 unsigned long mycode(0);
2943 std::string myif("Expression Building");
2944 std::string myscope("Sqrt");
2945 std::string myop("value < 0");
2946 std::string mydesc("sqrt(<0) is complex, can't do");
2947 std::string myinfo(HELPURL);
2948 throw ErrNotPermitted(mycode, myif, myscope, myop, mydesc, myinfo);
2949 }
2950 // go for it
2951 if (a->IsLeaf() && a->GetOpType() == CONST)
2952 {
2953 Expression ret;
2954 ret.SetToCopyOf(a);
2955 double t = a->GetValue();
2956 assert(t >= 0);
2957 ret->SetCoeff(1.0);
2958 ret->SetValue(sqrt(t));
2959 ret->SetExponent(1.0);
2960 ret->SetOpType(CONST);
2961 return ret;
2962 }
2963 else
2964 {
2965 Expression ret;
2966 ret->SetCoeff(1.0);
2967 ret->SetExponent(1.0);
2968 ret->SetOpType(SQRT);
2969 ret->AddCopyOfNode(a);
2970 return ret;
2971 }
2972 }
2973
Cbrt(Expression a)2974 Expression Cbrt(Expression a)
2975 {
2976 // go for it
2977 if (a->IsLeaf() && a->GetOpType() == CONST)
2978 {
2979 Expression ret;
2980 ret.SetToCopyOf(a);
2981 ret->SetCoeff(1.0);
2982 ret->SetValue(cbrt(a->GetValue()));
2983 ret->SetExponent(1.0);
2984 ret->SetOpType(CONST);
2985 return ret;
2986 }
2987 else
2988 {
2989 Expression ret;
2990 ret->SetCoeff(1.0);
2991 ret->SetExponent(1.0);
2992 ret->SetOpType(CBRT);
2993 ret->AddCopyOfNode(a);
2994 return ret;
2995 }
2996 }
2997
BesselJ0(Expression a)2998 Expression BesselJ0(Expression a)
2999 {
3000 // go for it
3001 if (a->IsLeaf() && a->GetOpType() == CONST)
3002 {
3003 Expression ret;
3004 ret.SetToCopyOf(a);
3005 ret->SetCoeff(1.0);
3006 ret->SetValue(j0(a->GetValue()));
3007 ret->SetExponent(1.0);
3008 ret->SetOpType(CONST);
3009 return ret;
3010 }
3011 else
3012 {
3013 Expression ret;
3014 ret->SetCoeff(1.0);
3015 ret->SetExponent(1.0);
3016 ret->SetOpType(BESSELJ0);
3017 ret->AddCopyOfNode(a);
3018 return ret;
3019 }
3020 }
3021
BesselJ1(Expression a)3022 Expression BesselJ1(Expression a)
3023 {
3024 // go for it
3025 if (a->IsLeaf() && a->GetOpType() == CONST)
3026 {
3027 Expression ret;
3028 ret.SetToCopyOf(a);
3029 ret->SetCoeff(1.0);
3030 ret->SetValue(j1(a->GetValue()));
3031 ret->SetExponent(1.0);
3032 ret->SetOpType(CONST);
3033 return ret;
3034 }
3035 else
3036 {
3037 Expression ret;
3038 ret->SetCoeff(1.0);
3039 ret->SetExponent(1.0);
3040 ret->SetOpType(BESSELJ1);
3041 ret->AddCopyOfNode(a);
3042 return ret;
3043 }
3044 }
3045
BesselY0(Expression a)3046 Expression BesselY0(Expression a)
3047 {
3048 // go for it
3049 if (a->IsLeaf() && a->GetOpType() == CONST)
3050 {
3051 Expression ret;
3052 ret.SetToCopyOf(a);
3053 ret->SetCoeff(1.0);
3054 ret->SetValue(y0(a->GetValue()));
3055 ret->SetExponent(1.0);
3056 ret->SetOpType(CONST);
3057 return ret;
3058 }
3059 else
3060 {
3061 Expression ret;
3062 ret->SetCoeff(1.0);
3063 ret->SetExponent(1.0);
3064 ret->SetOpType(BESSELY0);
3065 ret->AddCopyOfNode(a);
3066 return ret;
3067 }
3068 }
3069
BesselY1(Expression a)3070 Expression BesselY1(Expression a)
3071 {
3072 // go for it
3073 if (a->IsLeaf() && a->GetOpType() == CONST)
3074 {
3075 Expression ret;
3076 ret.SetToCopyOf(a);
3077 ret->SetCoeff(1.0);
3078 ret->SetValue(y1(a->GetValue()));
3079 ret->SetExponent(1.0);
3080 ret->SetOpType(CONST);
3081 return ret;
3082 }
3083 else
3084 {
3085 Expression ret;
3086 ret->SetCoeff(1.0);
3087 ret->SetExponent(1.0);
3088 ret->SetOpType(BESSELY1);
3089 ret->AddCopyOfNode(a);
3090 return ret;
3091 }
3092 }
3093
Sign(Expression a)3094 Expression Sign(Expression a)
3095 {
3096 // go for it
3097 if (a->IsLeaf() && a->GetOpType() == CONST)
3098 {
3099 Expression ret;
3100 ret.SetToCopyOf(a);
3101 ret->SetCoeff(1.0);
3102 double val = a->GetValue();
3103 ret->SetValue((val < 0.0) ? -1.0 : (val > 0.0) ? 1.0 : 0.0);
3104 ret->SetExponent(1.0);
3105 ret->SetOpType(CONST);
3106 return ret;
3107 }
3108 else
3109 {
3110 Expression ret;
3111 ret->SetCoeff(1.0);
3112 ret->SetExponent(1.0);
3113 ret->SetOpType(SIGN);
3114 ret->AddCopyOfNode(a);
3115 return ret;
3116 }
3117 }
3118
Rint(Expression a)3119 Expression Rint(Expression a)
3120 {
3121 // go for it
3122 if (a->IsLeaf() && a->GetOpType() == CONST)
3123 {
3124 Expression ret;
3125 ret.SetToCopyOf(a);
3126 ret->SetCoeff(1.0);
3127 ret->SetValue(floor(0.5 + a->GetValue()));
3128 ret->SetExponent(1.0);
3129 ret->SetOpType(CONST);
3130 return ret;
3131 }
3132 else
3133 {
3134 Expression ret;
3135 ret->SetCoeff(1.0);
3136 ret->SetExponent(1.0);
3137 ret->SetOpType(RINT);
3138 ret->AddCopyOfNode(a);
3139 return ret;
3140 }
3141 }
3142
Abs(Expression a)3143 Expression Abs(Expression a)
3144 {
3145 // go for it
3146 if (a->IsLeaf() && a->GetOpType() == CONST)
3147 {
3148 Expression ret;
3149 ret.SetToCopyOf(a);
3150 ret->SetCoeff(1.0);
3151 ret->SetValue(std::abs(a->GetValue()));
3152 ret->SetExponent(1.0);
3153 ret->SetOpType(CONST);
3154 return ret;
3155 }
3156 else
3157 {
3158 Expression ret;
3159 ret->SetCoeff(1.0);
3160 ret->SetExponent(1.0);
3161 ret->SetOpType(ABS);
3162 ret->AddCopyOfNode(a);
3163 return ret;
3164 }
3165 }
3166
Cot(Expression a)3167 Expression Cot(Expression a)
3168 {
3169 // make a preliminary check
3170 if (a->IsZero())
3171 {
3172 // *this is zero, can't do
3173 unsigned long mycode(0);
3174 std::string myif("Expression Building");
3175 std::string myscope("Cot");
3176 std::string myop("IsZero()");
3177 std::string mydesc("cot(0) is undefined");
3178 std::string myinfo(HELPURL);
3179 throw ErrNotPermitted(mycode, myif, myscope, myop, mydesc, myinfo);
3180 }
3181 // go for it
3182 if (a->IsLeaf() && a->GetOpType() == CONST)
3183 {
3184 Expression ret;
3185 ret.SetToCopyOf(a);
3186 double t = tan(a->GetValue());
3187 assert(t != 0);
3188 ret->SetCoeff(1.0);
3189 ret->SetValue(1 / t);
3190 ret->SetExponent(1.0);
3191 ret->SetOpType(CONST);
3192 return ret;
3193 }
3194 else
3195 {
3196 Expression ret;
3197 ret->SetCoeff(1.0);
3198 ret->SetExponent(1.0);
3199 ret->SetOpType(COT);
3200 ret->AddCopyOfNode(a);
3201 return ret;
3202 }
3203 }
3204
Coth(Expression a)3205 Expression Coth(Expression a)
3206 {
3207 // make a preliminary check
3208 if (a->IsZero())
3209 {
3210 // *this is zero, can't do
3211 unsigned long mycode(0);
3212 std::string myif("Expression Building");
3213 std::string myscope("Coth");
3214 std::string myop("IsZero()");
3215 std::string mydesc("coth(0) is undefined");
3216 std::string myinfo(HELPURL);
3217 throw ErrNotPermitted(mycode, myif, myscope, myop, mydesc, myinfo);
3218 }
3219 // go for it
3220 if (a->IsLeaf() && a->GetOpType() == CONST)
3221 {
3222 Expression ret;
3223 ret.SetToCopyOf(a);
3224 double t = tanh(a->GetValue());
3225 assert(t != 0);
3226 ret->SetCoeff(1.0);
3227 ret->SetValue(1 / t);
3228 ret->SetExponent(1.0);
3229 ret->SetOpType(CONST);
3230 return ret;
3231 }
3232 else
3233 {
3234 Expression ret;
3235 ret->SetCoeff(1.0);
3236 ret->SetExponent(1.0);
3237 ret->SetOpType(COTH);
3238 ret->AddCopyOfNode(a);
3239 return ret;
3240 }
3241 }
3242
3243 /***************** expression creation (affects arguments) ***********/
3244
3245 // sums:
SumLink(Expression a,Expression b)3246 Expression SumLink(Expression a,
3247 Expression b)
3248 {
3249 // make a preliminary check
3250 if (a->GetCoeff() == 0 || a->HasValue(0))
3251 return b;
3252 if (b->GetCoeff() == 0 || b->HasValue(0))
3253 return a;
3254 if (!(a->IsConstant() && b->IsConstant()) && a->IsEqualToNoCoeff(b))
3255 {
3256 a->SetCoeff(a->GetCoeff() + b->GetCoeff());
3257 if (std::abs(a->GetCoeff()) < Ev3NearZero())
3258 {
3259 // simplify to zero - for differences
3260 Expression zero(0.0);
3261 return zero;
3262 }
3263 else
3264 return a;
3265 }
3266 // go for it
3267 if (a->IsLeaf() && a->GetOpType() == CONST &&
3268 b->IsLeaf() && b->GetOpType() == CONST)
3269 {
3270 // a, b are numbers - add them
3271 a->SetValue(a->GetValue() + b->GetValue());
3272 a->SetCoeff(1.0);
3273 a->SetExponent(1.0);
3274 return a;
3275 }
3276 else if (a->IsLeaf() && a->GetOpType() == VAR &&
3277 b->IsLeaf() && b->GetOpType() == VAR &&
3278 a->GetVarIndex() == b->GetVarIndex() &&
3279 a->GetExponent() == b->GetExponent())
3280 {
3281 // a, b are the same variable - add coefficients
3282 a->SetCoeff(a->GetCoeff() + b->GetCoeff());
3283 return a;
3284 }
3285 else if (a->GetOpType() == SUM && b->GetOpType() != SUM)
3286 {
3287 // a is a sum and b isn't - just add the term b
3288 a->DistributeCoeffOverSum();
3289 Int i = 0;
3290 bool couldsimplify = false;
3291 Expression tmp;
3292 // if t is a leaf and there is a like leaf in this,
3293 // just add it to the value/coefficient
3294 if (b->IsLeaf() && b->GetOpType() == CONST)
3295 {
3296 // b is a constant
3297 for (i = 0; i < a->GetSize(); i++)
3298 {
3299 tmp = a->GetNode(i);
3300 if (tmp->IsLeaf() && tmp->GetOpType() == CONST)
3301 {
3302 tmp->SetValue(tmp->GetValue() + b->GetValue() / a->GetCoeff());
3303 tmp->SetCoeff(1.0);
3304 tmp->SetExponent(1.0); // NB: changing tmp should also change a
3305 couldsimplify = true;
3306 break;
3307 }
3308 }
3309 }
3310 else if (b->IsLeaf() && b->GetOpType() == VAR)
3311 {
3312 // b is a variable
3313 for (i = 0; i < a->GetSize(); i++)
3314 {
3315 if (a->GetNode(i)->IsLeaf() && a->GetNode(i)->GetOpType() == VAR &&
3316 b->GetVarIndex() == a->GetNode(i)->GetVarIndex() &&
3317 b->GetExponent() == a->GetNode(i)->GetExponent())
3318 {
3319 double tc = a->GetNode(i)->GetCoeff() + b->GetCoeff() / a->GetCoeff();
3320 // warning: tc could be zero, but it would be cumbersome
3321 // to simplify it here - do it in SimplifyConstant
3322 a->GetNode(i)->SetCoeff(tc);
3323 couldsimplify = true;
3324 break;
3325 }
3326 }
3327 }
3328 else if (!b->IsLeaf())
3329 {
3330 // a is a sum, b is a nonleaf, look for a subnode of a similar to b
3331 for (i = 0; i < a->GetSize(); i++)
3332 {
3333 if (a->GetNode(i)->IsEqualTo(b))
3334 {
3335 // found one, add coefficients - notice, as above, coeff could
3336 // be zero, but deal with that case in SimplifyConstant
3337 a->GetNode(i)->SetCoeff(a->GetNode(i)->GetCoeff() + b->GetCoeff());
3338 couldsimplify = true;
3339 break;
3340 }
3341 }
3342 }
3343 if (!couldsimplify)
3344 {
3345 // either could not simplify in steps above, or b is an operator
3346 a->AddNode(b);
3347 }
3348 return a;
3349 }
3350 else if (a->GetOpType() == SUM && b->GetOpType() == SUM)
3351 {
3352 // a, b are sums - add terms of b to a
3353 b->DistributeCoeffOverSum();
3354 Int i = 0;
3355 Int s = b->GetSize();
3356 for (i = 0; i < s; i++)
3357 {
3358 a = SumLink(a, b->GetNode(i));
3359 }
3360 return a;
3361 }
3362 else if (a->GetOpType() != SUM && b->GetOpType() == SUM)
3363 {
3364 // a is not a sum but b is - transform this into a sum
3365 b = SumLink(b, a);
3366 return b;
3367 }
3368 else
3369 {
3370 // all other cases - make new node on top of the addends
3371 Expression ret;
3372
3373
3374 ret->SetOpType(SUM);
3375 ret->SetCoeff(1.0);
3376 ret->SetExponent(1.0);
3377 ret->AddNode(a);
3378 ret->AddNode(b);
3379
3380 return ret;
3381 }
3382 }
3383
3384
3385 // product
ProductLink(Expression a,Expression t)3386 Expression ProductLink(Expression a,
3387 Expression t)
3388 {
3389 // make a preliminary check
3390 if (a->GetCoeff() == 0 || t->GetCoeff() == 0 ||
3391 a->HasValue(0) || t->HasValue(0))
3392 {
3393 Expression zero(0.0);
3394 return zero;
3395 }
3396 if (a->HasValue(1))
3397 return t;
3398 if (t->HasValue(1))
3399 return a;
3400 if (!(a->IsConstant() && t->IsConstant()) && a->IsEqualToNoCoeff(t))
3401 {
3402 Expression two(2.0);
3403 double c = a->GetCoeff();
3404 a->SetCoeff(1.);
3405 Expression power2(a ^ two);
3406 power2->SetCoeff(c * t->GetCoeff());
3407 return power2;
3408 }
3409 // go for it
3410 if (a->IsLeaf() && a->GetOpType() == CONST &&
3411 t->IsLeaf() && t->GetOpType() == CONST)
3412 {
3413 // a, t are numbers - multiply them
3414 a->SetValue(a->GetValue() * t->GetValue());
3415 a->SetCoeff(1.0);
3416 a->SetExponent(1.0);
3417 return a;
3418 }
3419 else if (a->IsLeaf() && a->GetOpType() == VAR &&
3420 t->IsLeaf() && t->GetOpType() == VAR &&
3421 a->GetVarIndex() == t->GetVarIndex())
3422 {
3423 // a, t are the same variable - multiply coefficients
3424 // and add exponents
3425 a->SetCoeff(a->GetCoeff() * t->GetCoeff());
3426 a->SetExponent(a->GetExponent() + t->GetExponent());
3427 return a;
3428 }
3429 else if (t->IsConstant())
3430 {
3431 // t is constant, set coeff of a
3432 a->SetCoeff(a->GetCoeff() * t->GetValue());
3433 a->DistributeCoeffOverSum();
3434 return a;
3435 }
3436 else if (a->IsConstant())
3437 {
3438 // a is constant, set coeff of t
3439 t->SetCoeff(t->GetCoeff() * a->GetValue());
3440 t->DistributeCoeffOverSum();
3441 return t;
3442 }
3443 else if (a->GetOpType() == PRODUCT && t->GetOpType() != PRODUCT)
3444 {
3445 // a is a product and t isn't - just multiply the term t
3446 Int i = 0;
3447 bool couldsimplify = false;
3448 if (t->IsLeaf() && t->GetOpType() == VAR)
3449 {
3450 // t is a variable
3451 Expression tmp;
3452 for (i = 0; i < a->GetSize(); i++)
3453 {
3454 tmp = a->GetNode(i);
3455 if (tmp->IsLeaf() && tmp->GetOpType() == VAR &&
3456 t->GetVarIndex() == tmp->GetVarIndex())
3457 {
3458 // found same variable in a, multiply coeffs and add exponents
3459 tmp->SetCoeff(tmp->GetCoeff() * t->GetCoeff());
3460 tmp->SetExponent(tmp->GetExponent() + t->GetExponent());
3461 couldsimplify = true;
3462 break;
3463 }
3464 }
3465 }
3466 // here we shan't try to simplify f*f <-- f^2 (f nonleaf)
3467 // because a product of nonleaves is easier to manipulate than
3468 // a power (as it adds a depth level)
3469 if (!couldsimplify)
3470 {
3471 // either could not simplify in steps above, or t is an operator
3472 a->AddNode(t);
3473 }
3474 return a;
3475 }
3476 else if (a->GetOpType() == PRODUCT && t->GetOpType() == PRODUCT)
3477 {
3478 // a, t are products - multiply terms of t to a
3479 t->DistributeCoeffOverProduct();
3480 Int i = 0;
3481 Int s = t->GetSize();
3482 for (i = 0; i < s; i++)
3483 {
3484 a = ProductLink(a, t->GetNode(i));
3485 }
3486 return a;
3487 }
3488 else if (a->GetOpType() != PRODUCT && t->GetOpType() == PRODUCT)
3489 {
3490 // a is not a products but t is - transform this into a product
3491 t = ProductLink(t, a);
3492 return t;
3493 }
3494 else
3495 {
3496 // all other cases - make new node on top of the addends
3497 Expression ret;
3498 ret->SetCoeff(1.0);
3499 ret->SetExponent(1.0);
3500 ret->SetOpType(PRODUCT);
3501 ret->AddNode(a);
3502 ret->AddNode(t);
3503 return ret;
3504 }
3505 }
3506
3507 // fractions:
FractionLink(Expression a,Expression t)3508 Expression FractionLink(Expression a,
3509 Expression t)
3510 {
3511 // make a preliminary check
3512 if (t->GetCoeff() == 0)
3513 {
3514 // divide by zero
3515 unsigned long mycode(0);
3516 std::string myif("Expression Building");
3517 std::string myscope("FractionLink");
3518 std::string myop("t.GetCoeff()==0");
3519 std::string mydesc("Divisor cannot be zero");
3520 std::string myinfo(HELPURL);
3521 std::string mydiv(NONE);
3522 throw ErrDivideByZero(mycode, myif, myscope, myop, mydesc, myinfo, mydiv);
3523 }
3524 if (a->GetCoeff() == 0 || a->HasValue(0))
3525 {
3526 // dividend has zero coeff, return zero
3527 Expression zero(0.0);
3528 return zero;
3529 }
3530 if (t->HasValue(1))
3531 return a;
3532 if (!(a->IsConstant() && t->IsConstant()) && a->IsEqualToNoCoeff(t))
3533 {
3534 // dividend = divisor, return ratio of coefficients
3535 Expression one(1.0);
3536 one->SetCoeff(a->GetCoeff() / t->GetCoeff());
3537 return one;
3538 }
3539 // go for it
3540 if (a->IsLeaf() && a->GetOpType() == CONST &&
3541 t->IsLeaf() && t->GetOpType() == CONST)
3542 {
3543 // a, t are numbers - divide them
3544 if (t->GetValue() == 0)
3545 {
3546 unsigned long mycode(0);
3547 std::string myif("Expression Building");
3548 std::string myscope("FractionLink");
3549 std::string myop("t.GetValue()==0");
3550 std::string mydesc("Divisor cannot be zero");
3551 std::string myinfo(HELPURL);
3552 std::string mydiv(NONE);
3553 throw ErrDivideByZero(mycode, myif, myscope, myop, mydesc, myinfo, mydiv);
3554 }
3555 else
3556 {
3557 a->SetValue(a->GetValue() / t->GetValue());
3558 a->SetCoeff(1.0);
3559 a->SetExponent(1.0);
3560 return a;
3561 }
3562 }
3563 else if (t->HasValue(1))
3564 {
3565 // divide by constant 1, don't do anything
3566 return a;
3567 }
3568 else if (t->IsConstant())
3569 {
3570 // t is constant, set coeff of a
3571 a->SetCoeff(a->GetCoeff() / t->GetValue());
3572 a->DistributeCoeffOverSum();
3573 return a;
3574 }
3575 else if (a->IsVariable() && t->IsVariable() &&
3576 a->GetVarIndex() == t->GetVarIndex())
3577 {
3578 // cx^e / dx^f = (c/d)x^(e-f)
3579 double te = a->GetExponent() - t->GetExponent();
3580 double tc = a->GetCoeff() / t->GetCoeff();
3581 if (std::abs(te) < Ev3NearZero())
3582 {
3583 Expression c(tc);
3584 return c;
3585 }
3586 a->SetCoeff(tc);
3587 a->SetExponent(te);
3588 return a;
3589 }
3590 else if (a->IsVariable() && t->GetOpType() == PRODUCT)
3591 {
3592 // a is a variable, t is a product - see if a appears in t
3593 // and cancel common term
3594 // first simplify coeffs of divisor
3595 t->ConsolidateProductCoeffs();
3596 // denominator
3597 if (std::abs(t->GetCoeff()) < Ev3NearZero())
3598 {
3599 // divide by zero
3600 unsigned long mycode(22);
3601 std::string myif("Expression Building");
3602 std::string myscope("FractionLink");
3603 std::string myop("t->GetCoeff()");
3604 std::string mydesc("Divisor cannot be zero");
3605 std::string myinfo(HELPURL);
3606 std::string mydiv(NONE);
3607 throw ErrDivideByZero(mycode, myif, myscope, myop, mydesc, myinfo, mydiv);
3608 }
3609 if (std::abs(a->GetCoeff()) < Ev3NearZero())
3610 {
3611 Expression zero(0.0);
3612 return zero;
3613 }
3614 double accumulatedcoeff = a->GetCoeff() / t->GetCoeff();
3615 a->SetCoeff(1.0);
3616 t->SetCoeff(1.0);
3617 // now try simplification
3618 Int i;
3619 for (i = 0; i < t->GetSize(); i++)
3620 {
3621 if (t->GetNode(i)->GetOpType() == VAR &&
3622 a->GetVarIndex() == t->GetNode(i)->GetVarIndex())
3623 {
3624 double te = a->GetExponent() - t->GetNode(i)->GetExponent();
3625 if (std::abs(te) < Ev3NearZero())
3626 {
3627 // exponents are the same, just cancel
3628 a->One();
3629 t->DeleteNode(i);
3630 }
3631 else if (te > 0)
3632 {
3633 // numerator remains, cancel denominator
3634 a->SetExponent(te);
3635 t->DeleteNode(i);
3636 }
3637 else if (te < 0)
3638 {
3639 // numerator goes to one, denominator remains
3640 a->One();
3641 t->GetNode(i)->SetExponent(-te);
3642 }
3643 // exit loop
3644 break;
3645 }
3646 }
3647 // check that denominator (t) has more than one operands;
3648 // if not, bring up a rank level
3649 if (t->GetSize() == 1)
3650 {
3651 t = t->GetNode(0);
3652 }
3653 // build ratio
3654 Expression ret;
3655 ret->SetOpType(FRACTION);
3656 ret->SetCoeff(accumulatedcoeff);
3657 ret->SetExponent(1.0);
3658 ret->AddNode(a);
3659 ret->AddNode(t);
3660 return ret;
3661 }
3662 else if (t->IsVariable() && a->GetOpType() == PRODUCT)
3663 {
3664 // t is a variable, a is a product - see if t appears in a
3665 // and cancel common term
3666 // first simplify coeffs of divisor
3667 a->ConsolidateProductCoeffs();
3668 // denominator - already checked
3669 if (std::abs(a->GetCoeff()) < Ev3NearZero())
3670 {
3671 Expression zero(0.0);
3672 return zero;
3673 }
3674 double accumulatedcoeff = a->GetCoeff() / t->GetCoeff();
3675 a->SetCoeff(1.0);
3676 t->SetCoeff(1.0);
3677 // now try simplification
3678 Int i;
3679 for (i = 0; i < a->GetSize(); i++)
3680 {
3681 if (a->GetNode(i)->GetOpType() == VAR &&
3682 t->GetVarIndex() == a->GetNode(i)->GetVarIndex())
3683 {
3684 double te = a->GetNode(i)->GetExponent() - t->GetExponent();
3685 if (std::abs(te) < Ev3NearZero())
3686 {
3687 // exponents are the same, just cancel
3688 t->One();
3689 a->DeleteNode(i);
3690 }
3691 else if (te > 0)
3692 {
3693 // numerator remains, cancel denominator
3694 t->One();
3695 a->GetNode(i)->SetExponent(te);
3696 }
3697 else if (te < 0)
3698 {
3699 // numerator goes to one, denominator remains
3700 t->SetExponent(-te);
3701 a->DeleteNode(i);
3702 }
3703 // exit loop
3704 break;
3705 }
3706 }
3707 // check that numerator (a) has more than one operands;
3708 // if not, bring up a rank level
3709 if (a->GetSize() == 1)
3710 {
3711 a = a->GetNode(0);
3712 }
3713 // build ratio
3714 Expression ret;
3715 ret->SetOpType(FRACTION);
3716 ret->SetCoeff(accumulatedcoeff);
3717 ret->SetExponent(1.0);
3718 ret->AddNode(a);
3719 ret->AddNode(t);
3720 return ret;
3721 }
3722 else if (a->GetOpType() == PRODUCT && t->GetOpType() == PRODUCT)
3723 {
3724 // a, t are products, try to cancel common terms
3725 Int i = 0, j = 0;
3726 double accumulatedcoeff;
3727 // first simplify coefficients of operands
3728 a->ConsolidateProductCoeffs();
3729 t->ConsolidateProductCoeffs();
3730 // denominator
3731 if (std::abs(t->GetCoeff()) < Ev3NearZero())
3732 throw ErrDivideByZero(21, "Expression Building", "FractionLink", "t->GetCoeff()", "Divisor cannot be zero", HELPURL, NONE);
3733
3734 if (std::abs(a->GetCoeff()) < Ev3NearZero())
3735 {
3736 Expression zero(0.0);
3737 return zero;
3738 }
3739 // save ratio of coeffs of products
3740 accumulatedcoeff = a->GetCoeff() / t->GetCoeff();
3741 a->SetCoeff(1.0);
3742 t->SetCoeff(1.0);
3743 // now try simplification
3744 i = 0;
3745 bool isnumeratorempty = false;
3746 bool isdenominatorempty = false;
3747 int szi = a->GetSize();
3748 int szj = t->GetSize();
3749 while(!isnumeratorempty && !isdenominatorempty && i < szi)
3750 {
3751 j = 0;
3752 while(!isnumeratorempty && !isdenominatorempty && j < szj)
3753 {
3754 if (a->GetNode(i)->IsEqualTo(t->GetNode(j)))
3755 {
3756 // found like terms i and j
3757 a->DeleteNode(i);
3758 szi--;
3759 if(szi == 0)
3760 {
3761 isnumeratorempty = true;
3762 a->One();
3763 }
3764 t->DeleteNode(j);
3765 szj--;
3766 if (szj == 0)
3767 {
3768 isdenominatorempty = true;
3769 t->One();
3770 }
3771 i--; // cancel the effect of the later i++
3772 break; // go to outer cycle
3773 }
3774 else
3775 {
3776 j++;
3777 }
3778 }
3779 i++;
3780 }
3781 if (t->HasValue(1))
3782 {
3783 // denominator is 1, return a
3784 a->SetCoeff(accumulatedcoeff);
3785 return a;
3786 }
3787 // now construct fraction
3788 // check that numerator, denominator have more than one operands;
3789 // if not, bring up a rank level
3790 if (a->GetSize() == 1)
3791 {
3792 a = a->GetNode(0);
3793 }
3794 if (t->GetSize() == 1)
3795 {
3796 t = t->GetNode(0);
3797 }
3798 Expression ret;
3799 ret->SetCoeff(accumulatedcoeff); // already contains coeffs of a, t
3800 ret->SetExponent(1.0);
3801 ret->SetOpType(FRACTION);
3802 ret->AddNode(a);
3803 ret->AddNode(t);
3804 return ret;
3805 }
3806 else
3807 {
3808 Expression ret;
3809 ret->SetCoeff(a->GetCoeff() / t->GetCoeff());
3810 a->SetCoeff(1.0);
3811 t->SetCoeff(1.0);
3812 ret->SetExponent(1.0);
3813 ret->SetOpType(FRACTION);
3814 ret->AddNode(a);
3815 ret->AddNode(t);
3816 return ret;
3817 }
3818 }
3819
3820 // unary minus:
MinusLink(Expression a)3821 Expression MinusLink(Expression a)
3822 {
3823 if (a->IsLeaf() && a->GetOpType() == CONST)
3824 {
3825 a->SetValue(- a->GetValue());
3826 a->SetCoeff(1.0);
3827 a->SetExponent(1.0);
3828 }
3829 else
3830 {
3831 a->SetCoeff(- a->GetCoeff());
3832 }
3833 return a;
3834 }
3835
3836 // binary minus:
DifferenceLink(Expression a,Expression b)3837 Expression DifferenceLink(Expression a,
3838 Expression b)
3839 {
3840 if (a->HasValue(0))
3841 return MinusLink(b);
3842 if (b->HasValue(0))
3843 return a;
3844 return SumLink(a, MinusLink(b));
3845 }
3846
3847 // power:
PowerLink(Expression a,Expression t)3848 Expression PowerLink(Expression a,
3849 Expression t)
3850 {
3851 // make a preliminary check
3852 if (a->GetCoeff() == 0)
3853 {
3854 // *this is zero, just return zero
3855 Expression zero(0.0);
3856 return zero;
3857 }
3858 if (t->HasValue(0.0))
3859 {
3860 // exponent is 0, just return 1
3861 Expression one(1.0);
3862 return one;
3863 }
3864 else if (t->HasValue(1.0))
3865 {
3866 // exponent is 1, just return a
3867 return a;
3868 }
3869 if (a->HasValue(0.0))
3870 {
3871 // base is zero, return 0
3872 Expression zero(0.0);
3873 return zero;
3874 }
3875 else if (a->HasValue(1.0))
3876 {
3877 // base is one, return 1
3878 Expression one(1.0);
3879 return one;
3880 }
3881 // go for it
3882 if (a->IsLeaf() && a->GetOpType() == CONST &&
3883 t->IsLeaf() && t->GetOpType() == CONST)
3884 {
3885 // constant to constant
3886 a->SetValue(pow(a->GetValue(), t->GetValue()));
3887 a->SetCoeff(1.0);
3888 a->SetExponent(1.0);
3889 return a;
3890 }
3891 else if ((std::abs(a->GetCoeff()) == 1.0) && a->IsLeaf() && (a->GetOpType() == VAR) &&
3892 t->IsLeaf() && (t->GetOpType() == CONST))
3893 {
3894 // variable to constant
3895 a->SetExponent(a->GetExponent() * t->GetValue());
3896 return a;
3897 }
3898 else
3899 {
3900 Expression ret;
3901 ret->SetCoeff(1.0);
3902 ret->SetExponent(1.0);
3903 ret->SetOpType(POWER);
3904 ret->AddNode(a);
3905 ret->AddNode(t);
3906 return ret;
3907 }
3908 }
3909
SinLink(Expression a)3910 Expression SinLink(Expression a)
3911 {
3912 // go for it
3913 if (a->IsLeaf() && a->GetOpType() == CONST)
3914 {
3915 a->SetValue(sin(a->GetValue()));
3916 a->SetCoeff(1.0);
3917 a->SetExponent(1.0);
3918 a->SetOpType(CONST);
3919 return a;
3920 }
3921 else
3922 {
3923 Expression ret;
3924 ret->SetCoeff(1.0);
3925 ret->SetExponent(1.0);
3926 ret->SetOpType(SIN);
3927 ret->AddNode(a);
3928 return ret;
3929 }
3930 }
3931
CosLink(Expression a)3932 Expression CosLink(Expression a)
3933 {
3934 // go for it
3935 if (a->IsLeaf() && a->GetOpType() == CONST)
3936 {
3937 a->SetValue(cos(a->GetValue()));
3938 a->SetCoeff(1.0);
3939 a->SetExponent(1.0);
3940 a->SetOpType(CONST);
3941 return a;
3942 }
3943 else
3944 {
3945 Expression ret;
3946 ret->SetCoeff(1.0);
3947 ret->SetExponent(1.0);
3948 ret->SetOpType(COS);
3949 ret->AddNode(a);
3950 return ret;
3951 }
3952 }
3953
TanLink(Expression a)3954 Expression TanLink(Expression a)
3955 {
3956 // go for it
3957 if (a->IsLeaf() && a->GetOpType() == CONST)
3958 {
3959 a->SetValue(tan(a->GetValue()));
3960 a->SetCoeff(1.0);
3961 a->SetExponent(1.0);
3962 a->SetOpType(CONST);
3963 return a;
3964 }
3965 else
3966 {
3967 Expression ret;
3968 ret->SetCoeff(1.0);
3969 ret->SetExponent(1.0);
3970 ret->SetOpType(TAN);
3971 ret->AddNode(a);
3972 return ret;
3973 }
3974 }
3975
AsinLink(Expression a)3976 Expression AsinLink(Expression a)
3977 {
3978 // go for it
3979 if (a->IsLeaf() && a->GetOpType() == CONST)
3980 {
3981 a->SetValue(asin(a->GetValue()));
3982 a->SetCoeff(1.0);
3983 a->SetExponent(1.0);
3984 a->SetOpType(CONST);
3985 return a;
3986 }
3987 else
3988 {
3989 Expression ret;
3990 ret->SetCoeff(1.0);
3991 ret->SetExponent(1.0);
3992 ret->SetOpType(ASIN);
3993 ret->AddNode(a);
3994 return ret;
3995 }
3996 }
3997
AcosLink(Expression a)3998 Expression AcosLink(Expression a)
3999 {
4000 if (a->IsLessThan(-1.0) || a->IsGreaterThan(1.0))
4001 throw ErrNotPermitted(0, "Expression Building", "AcosLink", "value <-1|>1", "acos(<-1|>1) is undefined", HELPURL);
4002
4003 // go for it
4004 if (a->IsLeaf() && a->GetOpType() == CONST)
4005 {
4006 a->SetValue(acos(a->GetValue()));
4007 a->SetCoeff(1.0);
4008 a->SetExponent(1.0);
4009 a->SetOpType(CONST);
4010 return a;
4011 }
4012 else
4013 {
4014 Expression ret;
4015 ret->SetCoeff(1.0);
4016 ret->SetExponent(1.0);
4017 ret->SetOpType(ACOS);
4018 ret->AddNode(a);
4019 return ret;
4020 }
4021 }
4022
AtanLink(Expression a)4023 Expression AtanLink(Expression a)
4024 {
4025 // go for it
4026 if (a->IsLeaf() && a->GetOpType() == CONST)
4027 {
4028 a->SetValue(atan(a->GetValue()));
4029 a->SetCoeff(1.0);
4030 a->SetExponent(1.0);
4031 a->SetOpType(CONST);
4032 return a;
4033 }
4034 else
4035 {
4036 Expression ret;
4037 ret->SetCoeff(1.0);
4038 ret->SetExponent(1.0);
4039 ret->SetOpType(ATAN);
4040 ret->AddNode(a);
4041 return ret;
4042 }
4043 }
4044
SinhLink(Expression a)4045 Expression SinhLink(Expression a)
4046 {
4047 // go for it
4048 if (a->IsLeaf() && a->GetOpType() == CONST)
4049 {
4050 a->SetValue(sinh(a->GetValue()));
4051 a->SetCoeff(1.0);
4052 a->SetExponent(1.0);
4053 a->SetOpType(CONST);
4054 return a;
4055 }
4056 else
4057 {
4058 Expression ret;
4059 ret->SetCoeff(1.0);
4060 ret->SetExponent(1.0);
4061 ret->SetOpType(SINH);
4062 ret->AddNode(a);
4063 return ret;
4064 }
4065 }
4066
CoshLink(Expression a)4067 Expression CoshLink(Expression a)
4068 {
4069 // go for it
4070 if (a->IsLeaf() && a->GetOpType() == CONST)
4071 {
4072 a->SetValue(cosh(a->GetValue()));
4073 a->SetCoeff(1.0);
4074 a->SetExponent(1.0);
4075 a->SetOpType(CONST);
4076 return a;
4077 }
4078 else
4079 {
4080 Expression ret;
4081 ret->SetCoeff(1.0);
4082 ret->SetExponent(1.0);
4083 ret->SetOpType(COSH);
4084 ret->AddNode(a);
4085 return ret;
4086 }
4087 }
4088
TanhLink(Expression a)4089 Expression TanhLink(Expression a)
4090 {
4091 // go for it
4092 if (a->IsLeaf() && a->GetOpType() == CONST)
4093 {
4094 a->SetValue(tanh(a->GetValue()));
4095 a->SetCoeff(1.0);
4096 a->SetExponent(1.0);
4097 a->SetOpType(CONST);
4098 return a;
4099 }
4100 else
4101 {
4102 Expression ret;
4103 ret->SetCoeff(1.0);
4104 ret->SetExponent(1.0);
4105 ret->SetOpType(TANH);
4106 ret->AddNode(a);
4107 return ret;
4108 }
4109 }
4110
AsinhLink(Expression a)4111 Expression AsinhLink(Expression a)
4112 {
4113 // go for it
4114 if (a->IsLeaf() && a->GetOpType() == CONST)
4115 {
4116 a->SetValue(asinh(a->GetValue()));
4117 a->SetCoeff(1.0);
4118 a->SetExponent(1.0);
4119 a->SetOpType(CONST);
4120 return a;
4121 }
4122 else
4123 {
4124 Expression ret;
4125 ret->SetCoeff(1.0);
4126 ret->SetExponent(1.0);
4127 ret->SetOpType(ASINH);
4128 ret->AddNode(a);
4129 return ret;
4130 }
4131 }
4132
AcoshLink(Expression a)4133 Expression AcoshLink(Expression a)
4134 {
4135 if (a->IsLessThan(1.0))
4136 throw ErrNotPermitted(0, "Expression Building", "AcoshLink", "value < 1", "acosh(<1) is undefined", HELPURL);
4137
4138 // go for it
4139 if (a->IsLeaf() && a->GetOpType() == CONST)
4140 {
4141 a->SetValue(acosh(a->GetValue()));
4142 a->SetCoeff(1.0);
4143 a->SetExponent(1.0);
4144 a->SetOpType(CONST);
4145 return a;
4146 }
4147 else
4148 {
4149 Expression ret;
4150 ret->SetCoeff(1.0);
4151 ret->SetExponent(1.0);
4152 ret->SetOpType(ACOSH);
4153 ret->AddNode(a);
4154 return ret;
4155 }
4156 }
4157
AtanhLink(Expression a)4158 Expression AtanhLink(Expression a)
4159 {
4160 if (a->IsLessThan(-1.0) || a->IsGreaterThan(1.0))
4161 throw ErrNotPermitted(0, "Expression Building", "AtanhLink", "value <-1|>1", "atanh(<-1|>1) is undefined", HELPURL);
4162
4163 // go for it
4164 if (a->IsLeaf() && a->GetOpType() == CONST)
4165 {
4166 a->SetValue(atanh(a->GetValue()));
4167 a->SetCoeff(1.0);
4168 a->SetExponent(1.0);
4169 a->SetOpType(CONST);
4170 return a;
4171 }
4172 else
4173 {
4174 Expression ret;
4175 ret->SetCoeff(1.0);
4176 ret->SetExponent(1.0);
4177 ret->SetOpType(ATANH);
4178 ret->AddNode(a);
4179 return ret;
4180 }
4181 }
4182
Log2Link(Expression a)4183 Expression Log2Link(Expression a)
4184 {
4185 // make a preliminary check
4186 if (a->IsZero())
4187 throw ErrNotPermitted(0, "Expression Building", "Log2Link", "IsZero()", "log2(0) is undefined", HELPURL);
4188
4189 if (a->IsLessThan(0))
4190 throw ErrNotPermitted(0, "Expression Building", "Log2Link", "value <= 0", "log2(<=0) is undefined", HELPURL);
4191
4192 // go for it
4193 if (a->IsLeaf() && a->GetOpType() == CONST)
4194 {
4195 double t = a->GetValue();
4196 assert(t >= 0);
4197 a->SetCoeff(1.0);
4198 a->SetValue(log2(t));
4199 a->SetExponent(1.0);
4200 a->SetOpType(CONST);
4201 return a;
4202 }
4203 else
4204 {
4205 Expression ret;
4206 ret->SetCoeff(1.0);
4207 ret->SetExponent(1.0);
4208 ret->SetOpType(LOG2);
4209 ret->AddNode(a);
4210 return ret;
4211 }
4212 }
4213
Log10Link(Expression a)4214 Expression Log10Link(Expression a)
4215 {
4216 // make a preliminary check
4217 if (a->IsZero())
4218 throw ErrNotPermitted(0, "Expression Building", "Log10Link", "IsZero()", "log10(0) is undefined", HELPURL);
4219
4220 if (a->IsLessThan(0))
4221 throw ErrNotPermitted(0, "Expression Building", "Log10Link", "value <= 0", "log10(<=0) is undefined", HELPURL);
4222
4223 // go for it
4224 if (a->IsLeaf() && a->GetOpType() == CONST)
4225 {
4226 double t = a->GetValue();
4227 assert(t >= 0);
4228 a->SetCoeff(1.0);
4229 a->SetValue(log10(t));
4230 a->SetExponent(1.0);
4231 a->SetOpType(CONST);
4232 return a;
4233 }
4234 else
4235 {
4236 Expression ret;
4237 ret->SetCoeff(1.0);
4238 ret->SetExponent(1.0);
4239 ret->SetOpType(LOG10);
4240 ret->AddNode(a);
4241 return ret;
4242 }
4243 }
4244
LogLink(Expression a)4245 Expression LogLink(Expression a)
4246 {
4247 // make a preliminary check
4248 if (a->IsZero())
4249 throw ErrNotPermitted(0, "Expression Building", "LogLink", "IsZero()", "log(0) is undefined", HELPURL);
4250
4251 if (a->IsLessThan(0))
4252 throw ErrNotPermitted(0, "Expression Building", "LogLink", "value <= 0", "log(<=0) is undefined", HELPURL);
4253
4254 // go for it
4255 if (a->IsLeaf() && a->GetOpType() == CONST)
4256 {
4257 double t = a->GetValue();
4258 assert(t >= 0);
4259 a->SetCoeff(1.0);
4260 a->SetValue(log(t));
4261 a->SetExponent(1.0);
4262 a->SetOpType(CONST);
4263 return a;
4264 }
4265 else
4266 {
4267 Expression ret;
4268 ret->SetCoeff(1.0);
4269 ret->SetExponent(1.0);
4270 ret->SetOpType(LOG);
4271 ret->AddNode(a);
4272 return ret;
4273 }
4274 }
4275
LnLink(Expression a)4276 Expression LnLink(Expression a)
4277 {
4278 // make a preliminary check
4279 if (a->IsZero())
4280 throw ErrNotPermitted(0, "Expression Building", "LnLink", "IsZero()", "ln(0) is undefined", HELPURL);
4281
4282 if (a->IsLessThan(0))
4283 throw ErrNotPermitted(0, "Expression Building", "LnLink", "value <= 0", "ln(<=0) is undefined", HELPURL);
4284
4285 // go for it
4286 if (a->IsLeaf() && a->GetOpType() == CONST)
4287 {
4288 double t = a->GetValue();
4289 assert(t >= 0);
4290 a->SetCoeff(1.0);
4291 a->SetValue(log(t));
4292 a->SetExponent(1.0);
4293 a->SetOpType(CONST);
4294 return a;
4295 }
4296 else
4297 {
4298 Expression ret;
4299 ret->SetCoeff(1.0);
4300 ret->SetExponent(1.0);
4301 ret->SetOpType(LN);
4302 ret->AddNode(a);
4303 return ret;
4304 }
4305 }
4306
LngammaLink(Expression a)4307 Expression LngammaLink(Expression a)
4308 {
4309 if (a->IsLessThan(0.0))
4310 throw ErrNotPermitted(0, "Expression Building", "LngammaLink", "value < 0", "lngamma(<0) is undefined", HELPURL);
4311
4312 // go for it
4313 if (a->IsLeaf() && a->GetOpType() == CONST)
4314 {
4315 a->SetValue(lgamma(a->GetValue()));
4316 a->SetCoeff(1.0);
4317 a->SetExponent(1.0);
4318 a->SetOpType(CONST);
4319 return a;
4320 }
4321 else
4322 {
4323 Expression ret;
4324 ret->SetCoeff(1.0);
4325 ret->SetExponent(1.0);
4326 ret->SetOpType(LNGAMMA);
4327 ret->AddNode(a);
4328 return ret;
4329 }
4330 }
4331
GammaLink(Expression a)4332 Expression GammaLink(Expression a)
4333 {
4334 // go for it
4335 if (a->IsLeaf() && a->GetOpType() == CONST)
4336 {
4337 a->SetValue(exp(lgamma(a->GetValue())));
4338 a->SetCoeff(1.0);
4339 a->SetExponent(1.0);
4340 a->SetOpType(CONST);
4341 return a;
4342 }
4343 else
4344 {
4345 Expression ret;
4346 ret->SetCoeff(1.0);
4347 ret->SetExponent(1.0);
4348 ret->SetOpType(GAMMA);
4349 ret->AddNode(a);
4350 return ret;
4351 }
4352 }
4353
ExpLink(Expression a)4354 Expression ExpLink(Expression a)
4355 {
4356 // go for it
4357 if (a->IsLeaf() && a->GetOpType() == CONST)
4358 {
4359 a->SetValue(exp(a->GetValue()));
4360 a->SetCoeff(1.0);
4361 a->SetExponent(1.0);
4362 a->SetOpType(CONST);
4363 return a;
4364 }
4365 else
4366 {
4367 Expression ret;
4368 ret->SetCoeff(1.0);
4369 ret->SetExponent(1.0);
4370 ret->SetOpType(EXP);
4371 ret->AddNode(a);
4372 return ret;
4373 }
4374 }
4375
ErfLink(Expression a)4376 Expression ErfLink(Expression a)
4377 {
4378 // go for it
4379 if (a->IsLeaf() && a->GetOpType() == CONST)
4380 {
4381 a->SetValue(erf(a->GetValue()));
4382 a->SetCoeff(1.0);
4383 a->SetExponent(1.0);
4384 a->SetOpType(CONST);
4385 return a;
4386 }
4387 else
4388 {
4389 Expression ret;
4390 ret->SetCoeff(1.0);
4391 ret->SetExponent(1.0);
4392 ret->SetOpType(ERF);
4393 ret->AddNode(a);
4394 return ret;
4395 }
4396 }
4397
ErfcLink(Expression a)4398 Expression ErfcLink(Expression a)
4399 {
4400 // go for it
4401 if (a->IsLeaf() && a->GetOpType() == CONST)
4402 {
4403 a->SetValue(erfc(a->GetValue()));
4404 a->SetCoeff(1.0);
4405 a->SetExponent(1.0);
4406 a->SetOpType(CONST);
4407 return a;
4408 }
4409 else
4410 {
4411 Expression ret;
4412 ret->SetCoeff(1.0);
4413 ret->SetExponent(1.0);
4414 ret->SetOpType(ERFC);
4415 ret->AddNode(a);
4416 return ret;
4417 }
4418 }
4419
SqrtLink(Expression a)4420 Expression SqrtLink(Expression a)
4421 {
4422 // make a preliminary check
4423 if (a->IsLessThan(0) && !a->HasValue(0))
4424 throw ErrNotPermitted(0, "Expression Building", "SqrtLink", "value < 0", "sqrt(<0) is complex, can't do", HELPURL);
4425
4426 // go for it
4427 if (a->IsLeaf() && a->GetOpType() == CONST)
4428 {
4429 double t = a->GetValue();
4430 assert(t >= 0.);
4431 a->SetCoeff(1.0);
4432 a->SetValue(sqrt(t));
4433 a->SetExponent(1.0);
4434 a->SetOpType(CONST);
4435 return a;
4436 }
4437 else
4438 {
4439 Expression ret;
4440 ret->SetCoeff(1.0);
4441 ret->SetExponent(1.0);
4442 ret->SetOpType(SQRT);
4443 ret->AddNode(a);
4444 return ret;
4445 }
4446 }
4447
CbrtLink(Expression a)4448 Expression CbrtLink(Expression a)
4449 {
4450 // go for it
4451 if (a->IsLeaf() && a->GetOpType() == CONST)
4452 {
4453 a->SetValue(cbrt(a->GetValue()));
4454 a->SetCoeff(1.0);
4455 a->SetExponent(1.0);
4456 a->SetOpType(CONST);
4457 return a;
4458 }
4459 else
4460 {
4461 Expression ret;
4462 ret->SetCoeff(1.0);
4463 ret->SetExponent(1.0);
4464 ret->SetOpType(CBRT);
4465 ret->AddNode(a);
4466 return ret;
4467 }
4468 }
4469
BesselJ0Link(Expression a)4470 Expression BesselJ0Link(Expression a)
4471 {
4472 // go for it
4473 if (a->IsLeaf() && a->GetOpType() == CONST)
4474 {
4475 a->SetValue(j0(a->GetValue()));
4476 a->SetCoeff(1.0);
4477 a->SetExponent(1.0);
4478 a->SetOpType(CONST);
4479 return a;
4480 }
4481 else
4482 {
4483 Expression ret;
4484 ret->SetCoeff(1.0);
4485 ret->SetExponent(1.0);
4486 ret->SetOpType(BESSELJ0);
4487 ret->AddNode(a);
4488 return ret;
4489 }
4490 }
4491
BesselJ1Link(Expression a)4492 Expression BesselJ1Link(Expression a)
4493 {
4494 // go for it
4495 if (a->IsLeaf() && a->GetOpType() == CONST)
4496 {
4497 a->SetValue(j1(a->GetValue()));
4498 a->SetCoeff(1.0);
4499 a->SetExponent(1.0);
4500 a->SetOpType(CONST);
4501 return a;
4502 }
4503 else
4504 {
4505 Expression ret;
4506 ret->SetCoeff(1.0);
4507 ret->SetExponent(1.0);
4508 ret->SetOpType(BESSELJ1);
4509 ret->AddNode(a);
4510 return ret;
4511 }
4512 }
4513
BesselY0Link(Expression a)4514 Expression BesselY0Link(Expression a)
4515 {
4516 // go for it
4517 if (a->IsLeaf() && a->GetOpType() == CONST)
4518 {
4519 a->SetValue(y0(a->GetValue()));
4520 a->SetCoeff(1.0);
4521 a->SetExponent(1.0);
4522 a->SetOpType(CONST);
4523 return a;
4524 }
4525 else
4526 {
4527 Expression ret;
4528 ret->SetCoeff(1.0);
4529 ret->SetExponent(1.0);
4530 ret->SetOpType(BESSELY0);
4531 ret->AddNode(a);
4532 return ret;
4533 }
4534 }
4535
BesselY1Link(Expression a)4536 Expression BesselY1Link(Expression a)
4537 {
4538 // go for it
4539 if (a->IsLeaf() && a->GetOpType() == CONST)
4540 {
4541 a->SetValue(y1(a->GetValue()));
4542 a->SetCoeff(1.0);
4543 a->SetExponent(1.0);
4544 a->SetOpType(CONST);
4545 return a;
4546 }
4547 else
4548 {
4549 Expression ret;
4550 ret->SetCoeff(1.0);
4551 ret->SetExponent(1.0);
4552 ret->SetOpType(BESSELY1);
4553 ret->AddNode(a);
4554 return ret;
4555 }
4556 }
4557
SignLink(Expression a)4558 Expression SignLink(Expression a)
4559 {
4560 // go for it
4561 if (a->IsLeaf() && a->GetOpType() == CONST)
4562 {
4563 double tmp(a->GetValue());
4564 a->SetValue((tmp < 0) ? -1.0 : (tmp > 0) ? 1.0 : 0.0);
4565 a->SetCoeff(1.0);
4566 a->SetExponent(1.0);
4567 a->SetOpType(CONST);
4568 return a;
4569 }
4570 else
4571 {
4572 Expression ret;
4573 ret->SetCoeff(1.0);
4574 ret->SetExponent(1.0);
4575 ret->SetOpType(SIGN);
4576 ret->AddNode(a);
4577 return ret;
4578 }
4579 }
4580
RintLink(Expression a)4581 Expression RintLink(Expression a)
4582 {
4583 // go for it
4584 if (a->IsLeaf() && a->GetOpType() == CONST)
4585 {
4586 a->SetValue(floor(0.5 + a->GetValue()));
4587 a->SetCoeff(1.0);
4588 a->SetExponent(1.0);
4589 a->SetOpType(CONST);
4590 return a;
4591 }
4592 else
4593 {
4594 Expression ret;
4595 ret->SetCoeff(1.0);
4596 ret->SetExponent(1.0);
4597 ret->SetOpType(RINT);
4598 ret->AddNode(a);
4599 return ret;
4600 }
4601 }
4602
AbsLink(Expression a)4603 Expression AbsLink(Expression a)
4604 {
4605 // go for it
4606 if (a->IsLeaf() && a->GetOpType() == CONST)
4607 {
4608 a->SetValue(std::abs(a->GetValue()));
4609 a->SetCoeff(1.0);
4610 a->SetExponent(1.0);
4611 a->SetOpType(CONST);
4612 return a;
4613 }
4614 else
4615 {
4616 Expression ret;
4617 ret->SetCoeff(1.0);
4618 ret->SetExponent(1.0);
4619 ret->SetOpType(ABS);
4620 ret->AddNode(a);
4621 return ret;
4622 }
4623 }
4624
CotLink(Expression a)4625 Expression CotLink(Expression a)
4626 {
4627 // make a preliminary check
4628 if (a->IsZero())
4629 throw ErrNotPermitted(0, "Expression Building", "CotLink", "IsZero()", "cot(0) is undefined", HELPURL);
4630
4631 // go for it
4632 if (a->IsLeaf() && a->GetOpType() == CONST)
4633 {
4634 double t = tan(a->GetValue());
4635 assert(t != 0);
4636 a->SetCoeff(1.0);
4637 a->SetValue(1 / t);
4638 a->SetExponent(1.0);
4639 a->SetOpType(CONST);
4640 return a;
4641 }
4642 else
4643 {
4644 Expression ret;
4645 ret->SetCoeff(1.0);
4646 ret->SetExponent(1.0);
4647 ret->SetOpType(COT);
4648 ret->AddNode(a);
4649 return ret;
4650 }
4651 }
4652
CothLink(Expression a)4653 Expression CothLink(Expression a)
4654 {
4655 // make a preliminary check
4656 if (a->IsZero())
4657 throw ErrNotPermitted(0, "Expression Building", "CothLink", "IsZero()", "coth(0) is undefined", HELPURL);
4658
4659 // go for it
4660 if (a->IsLeaf() && a->GetOpType() == CONST)
4661 {
4662 double t = tanh(a->GetValue());
4663 assert(t != 0);
4664 a->SetCoeff(1.0);
4665 a->SetValue(1 / t);
4666 a->SetExponent(1.0);
4667 a->SetOpType(CONST);
4668 return a;
4669 }
4670 else
4671 {
4672 Expression ret;
4673 ret->SetCoeff(1.0);
4674 ret->SetExponent(1.0);
4675 ret->SetOpType(COTH);
4676 ret->AddNode(a);
4677 return ret;
4678 }
4679 }
4680
4681
4682 /***************** differentiation ******************/
4683
4684 // differentiate w.r.t. variable varindex
Diff(const Expression & ac,Int vi)4685 Expression Diff(const Expression& ac, Int vi)
4686 {
4687 Expression ret(DiffNoSimplify(ac, vi));
4688 Simplify(&ret);
4689 return ret;
4690 }
4691
DiffNoSimplify(const Expression & ac,Int vi)4692 Expression DiffNoSimplify(const Expression& ac, Int vi)
4693 {
4694 Expression a;
4695 a.SetToCopyOf(ac);
4696 Expression zero(0.0);
4697 Expression c(1.0);
4698 if (a->DependsOnVariable(vi))
4699 {
4700 if (a->IsLeaf())
4701 {
4702 if (a->GetOpType() == CONST || a->GetVarIndex() != vi)
4703 {
4704 // safety check
4705 std::cerr << "Expression::Diff: warning: this node should "
4706 << "not diff to zero\n";
4707 return zero;
4708 }
4709 else
4710 {
4711 // variable vi, check exponent
4712 if (a->GetExponent() == 0)
4713 {
4714 // exponent is zero, node is actually constant
4715 return zero;
4716 }
4717 else if (a->GetExponent() == 1)
4718 {
4719 // exponent is one, node is variable
4720 c->SetValue(a->GetCoeff());
4721
4722 return c;
4723 }
4724 else
4725 {
4726 // for all other cases, apply rule x^c = c*x^(c-1)
4727 double expon = a->GetExponent();
4728 Expression ret(a.Copy());
4729 ret->SetExponent(expon - 1);
4730 ret->SetCoeff(ret->GetCoeff() * expon);
4731 return ret;
4732 }
4733 }
4734 }
4735 else
4736 {
4737
4738 // non-leaf node. build derivative.
4739 int op = a->GetOpType();
4740 Int sz = a->GetSize();
4741 double opcoeff = a->GetCoeff();
4742 if (sz == 0)
4743 {
4744 throw ErrNotPermitted(10, "Expression", "Diff", "GetSize() == 0",
4745 "non-leaf node can't have size 0", HELPURL);
4746 }
4747 Int i, j;
4748 Expression ret(0.0);
4749 Expression tmp(1.0);
4750 Expression tmp2(1.0);
4751 Expression two(2.0);
4752 switch(op)
4753 {
4754 case SUM:
4755 ret = Diff(a->GetNode(0), vi); // f_0'
4756 for(i = 1; i < sz; i++)
4757 {
4758 tmp = Diff(a->GetNode(i), vi);
4759 if (!tmp->IsZero())
4760 {
4761 ret = ret + tmp; // ... + g_i'
4762 }
4763 }
4764 break;
4765 case DIFFERENCE:
4766 ret = Diff(a->GetNode(0), vi); // f_0'
4767 for(i = 1; i < sz; i++)
4768 {
4769 tmp = Diff(a->GetNode(i), vi);
4770 if (!tmp->IsZero())
4771 {
4772 ret = ret - tmp; // ... - g_i'
4773 }
4774 }
4775 break;
4776 case PRODUCT:
4777 if (sz == 1)
4778 {
4779 // warn about product with one operand
4780 std::cerr << "Expression::Diff: warning: product with 1 operand "
4781 << "should not occur\n";
4782 }
4783 ret = Diff(a->GetNode(0), vi); // f_0'
4784 if (!ret->IsZero())
4785 {
4786 for(j = 1; j < sz; j++)
4787 {
4788 // get copies, not references
4789 ret = ret * a->GetCopyOfNode(j); // ... * f_i[i!=0]
4790 }
4791 }
4792 tmp->One(); // reset temporary to 1.0
4793 for(i = 1; i < sz; i++)
4794 {
4795 tmp = Diff(a->GetNode(i), vi); // tmp = f_i'
4796 if (!tmp->IsZero())
4797 {
4798 for(j = 0; j < sz; j++)
4799 {
4800 if (j != i)
4801 {
4802 // get references, and copy later (in sum)
4803 tmp = tmp * a->GetNode(j); // ... * f_j[i!=i]
4804 }
4805 }
4806 ret = ret + tmp.Copy(); // ... + tmp
4807 tmp->One(); // reset temporary to 1.0
4808 }
4809 }
4810 break;
4811 case FRACTION:
4812 if (sz != 2)
4813 {
4814 // check that there are exactly two operands
4815 throw ErrNotPermitted(11, "Expression", "Diff", "GetSize() != 2",
4816 "fraction must have exactly 2 operands",
4817 HELPURL);
4818 }
4819 if (a->GetNode(1)->IsZero())
4820 {
4821 // check denominator is not zero
4822 throw ErrDivideByZero(20, "Expression", "Diff",
4823 "GetNode(1)->IsZero()",
4824 "cannot divide by zero", HELPURL,
4825 a->GetNode(1)->ToString());
4826 }
4827 tmp->One();
4828 ret = Diff(a->GetNode(0), vi); // f'
4829 if (!ret->IsZero())
4830 {
4831 ret = ret / a->GetCopyOfNode(1); // f'/g
4832 }
4833 // can dispense from using GetCopyOf because tmp gets copied anyway
4834 tmp = a->GetNode(0); // tmp = f
4835 tmp2 = Diff(a->GetNode(1), vi);
4836 if (!tmp2->IsZero())
4837 {
4838 tmp = tmp * tmp2; // tmp = fg'
4839 ret = ret - tmp.Copy() / (a->GetCopyOfNode(1) ^ two); // f'/g - fg'/g^2
4840 }
4841 // can dispense from using copy here - tmp is not used thereafter
4842 // and when tmp is deleted, its subnodes are not automatically
4843 // deleted unless reference counter is zero - which won't be.
4844 break;
4845 case POWER:
4846 if (sz != 2)
4847 {
4848 // check that there are exactly two operands
4849 throw ErrNotPermitted(12, "Expression", "Diff", "GetSize() != 2",
4850 "power must have exactly 2 operands",
4851 HELPURL);
4852 }
4853 // check exponent
4854 if (a->GetNode(1)->IsZero())
4855 {
4856 // exponent is zero, whole node is one, diff is zero
4857 ret->Zero();
4858 }
4859 else if (a->GetNode(1)->HasValue(1.0))
4860 {
4861 // exponent is one, whole node is first operand, diff
4862 // is diff of first operand
4863 ret = Diff(a->GetNode(0), vi);
4864 }
4865 else if (a->GetNode(1)->HasValue(2.0))
4866 {
4867 // exponent is two, diff is 2 * first op * diff of first operand
4868 ret = Diff(a->GetNode(0), vi); // f'
4869 ret = ret * a->GetCopyOfNode(0); // f'f
4870 ret->SetCoeff(ret->GetCoeff() * 2.0); // 2f'f
4871 }
4872 else
4873 {
4874 // all other cases
4875 if (a->GetNode(1)->IsConstant())
4876 {
4877 // numeric exponent != 0,1,2
4878 ret = Diff(a->GetNode(0), vi); // f'
4879 tmp = a->GetCopyOfNode(0); // f
4880 const double coeff = tmp->GetCoeff();
4881 tmp = tmp ^ a->GetCopyOfNode(1); // f^c
4882 if (tmp->GetOpType() == VAR)
4883 {
4884 tmp->SetCoeff(tmp->GetExponent() * std::pow(coeff, tmp->GetExponent() - 1.0)); // cf^c
4885 tmp->SetExponent(tmp->GetExponent() - 1); // cf^(c-1)
4886 }
4887 else
4888 {
4889 tmp->GetNode(1)->ConsolidateValue();
4890 tmp->SetCoeff(tmp->GetCoeff() * tmp->GetNode(1)->GetValue());//cf^c
4891 tmp->GetNode(1)->SetValue(tmp->GetNode(1)->GetValue() - 1); //cf^(c-1)
4892 }
4893 // can dispense from using copy here - Diff returns copies anyway.
4894 // when temporary is deleted, its subnodes are not automatically
4895 // deleted unless their reference counter is zero - which won't be.
4896 ret = ret * tmp; // f'(cf^(c-1))
4897 }
4898 else
4899 {
4900 // symbolic exponent f^g
4901 ret = a->GetCopyOfNode(0); // f
4902 ret = Log(ret); // log(f)
4903 // can dispense from using copy here - Diff returns copies anyway.
4904 // when temporary is deleted, its subnodes are not automatically
4905 // deleted unless their reference counter is zero - which won't be.
4906 ret = ret * Diff(a->GetNode(1), vi); // g' log(f)
4907 tmp = Diff(a->GetNode(0), vi); // f'
4908 tmp = tmp * a->GetCopyOfNode(1); // gf'
4909 tmp = tmp / a->GetCopyOfNode(0); // gf'/f
4910 // can dispense from using copy here - tmp is not used thereafter
4911 // and when tmp is deleted, its subnodes are not automatically
4912 // deleted unless their reference counter is zero - which won't be.
4913 ret = ret + tmp; // g'log(f) + gf'/f
4914 tmp = a.Copy();
4915 tmp->SetCoeff(1.0);
4916 ret = ret * tmp; // (g'log(f) + gf'/f)(f^g)
4917 }
4918 }
4919 break;
4920 case MINUS:
4921 if (sz != 1)
4922 {
4923 // check that there is exactly one operand
4924 throw ErrNotPermitted(13, "Expression", "Diff", "GetSize() != 1",
4925 "unary minus must have exactly 1 operand",
4926 HELPURL);
4927 }
4928 ret = Diff(a->GetNode(0), vi);
4929 ret->SetCoeff(- ret->GetCoeff());
4930 break;
4931 case SIN:
4932 if (sz != 1)
4933 {
4934 // check that there is exactly one operand
4935 throw ErrNotPermitted(17, "Expression", "Diff", "GetSize() != 1",
4936 "sin must have exactly 1 operand",
4937 HELPURL);
4938 }
4939 ret = Diff(a->GetNode(0), vi) * Cos(a->GetCopyOfNode(0)); // f' cos(f)
4940 break;
4941 case COS:
4942 if (sz != 1)
4943 {
4944 // check that there is exactly one operand
4945 throw ErrNotPermitted(18, "Expression", "Diff", "GetSize() != 1",
4946 "cos must have exactly 1 operand",
4947 HELPURL);
4948 }
4949 ret = -Diff(a->GetNode(0), vi) * Sin(a->GetCopyOfNode(0)); // -f'sin(f)
4950 break;
4951 case TAN:
4952 if (sz != 1)
4953 {
4954 // check that there is exactly one operand
4955 throw ErrNotPermitted(19, "Expression", "Diff", "GetSize() != 1",
4956 "tan must have exactly 1 operand",
4957 HELPURL);
4958 }
4959 ret = a.Copy(); // tan(f)
4960 ret->SetCoeff(1.0);
4961 ret = ret ^ two; // tan(f)^2
4962 c->One();
4963 ret = ret + c; // tan(f)^2 + 1
4964 ret = ret * Diff(a->GetNode(0), vi); // f' * (tan(f)^2 + 1)
4965 break;
4966 case ASIN:
4967 if (sz != 1)
4968 {
4969 // check that there is exactly one operand
4970 throw ErrNotPermitted(17, "Expression", "Diff", "GetSize() != 1",
4971 "asin must have exactly 1 operand",
4972 HELPURL);
4973 }
4974 ret = a->GetCopyOfNode(0);
4975 ret = ret ^ two;
4976 c->One();
4977 ret = c - ret;
4978 ret = Diff(a->GetNode(0), vi) / Sqrt(ret); // f' / sqrt(1 - f^2)
4979 break;
4980 case ACOS:
4981 if (sz != 1)
4982 {
4983 // check that there is exactly one operand
4984 throw ErrNotPermitted(18, "Expression", "Diff", "GetSize() != 1",
4985 "acos must have exactly 1 operand",
4986 HELPURL);
4987 }
4988 ret = a->GetCopyOfNode(0);
4989 ret = ret ^ two;
4990 c->One();
4991 ret = c - ret;
4992 ret = -Diff(a->GetNode(0), vi) / Sqrt(ret); // -f' / sqrt(1 - f^2)
4993 break;
4994 case ATAN:
4995 if (sz != 1)
4996 {
4997 // check that there is exactly one operand
4998 throw ErrNotPermitted(19, "Expression", "Diff", "GetSize() != 1",
4999 "atan must have exactly 1 operand",
5000 HELPURL);
5001 }
5002 ret = a->GetCopyOfNode(0);
5003 ret = ret ^ two;
5004 c->One();
5005 ret = ret + c;
5006 ret = Diff(a->GetNode(0), vi) / ret; // f' / (f^2 + 1)
5007 break;
5008 case SINH:
5009 if (sz != 1)
5010 {
5011 // check that there is exactly one operand
5012 throw ErrNotPermitted(17, "Expression", "Diff", "GetSize() != 1",
5013 "sinh must have exactly 1 operand",
5014 HELPURL);
5015 }
5016 ret = Diff(a->GetNode(0), vi) * Cosh(a->GetCopyOfNode(0)); // f' cosh(f)
5017 break;
5018 case COSH:
5019 if (sz != 1)
5020 {
5021 // check that there is exactly one operand
5022 throw ErrNotPermitted(18, "Expression", "Diff", "GetSize() != 1",
5023 "cosh must have exactly 1 operand",
5024 HELPURL);
5025 }
5026 ret = Diff(a->GetNode(0), vi) * Sinh(a->GetCopyOfNode(0)); // f'sinh(f)
5027 break;
5028 case TANH:
5029 if (sz != 1)
5030 {
5031 // check that there is exactly one operand
5032 throw ErrNotPermitted(19, "Expression", "Diff", "GetSize() != 1",
5033 "tanh must have exactly 1 operand",
5034 HELPURL);
5035 }
5036 ret = a.Copy();
5037 ret->SetCoeff(1.0);
5038 ret = ret ^ two;
5039 c->One();
5040 ret = c - ret;
5041 ret = ret * Diff(a->GetNode(0), vi); // f' * (1 - tan(f)^2)
5042 break;
5043 case ASINH:
5044 if (sz != 1)
5045 {
5046 // check that there is exactly one operand
5047 throw ErrNotPermitted(17, "Expression", "Diff", "GetSize() != 1",
5048 "asinh must have exactly 1 operand",
5049 HELPURL);
5050 }
5051 ret = a->GetCopyOfNode(0);
5052 ret = ret ^ two;
5053 c->One();
5054 ret = c + ret;
5055 ret = Diff(a->GetNode(0), vi) / Sqrt(ret); // f' / sqrt(1 + f^2)
5056 break;
5057 case ACOSH:
5058 if (sz != 1)
5059 {
5060 // check that there is exactly one operand
5061 throw ErrNotPermitted(18, "Expression", "Diff", "GetSize() != 1",
5062 "acosh must have exactly 1 operand",
5063 HELPURL);
5064 }
5065 ret = a->GetCopyOfNode(0);
5066 ret = ret ^ two;
5067 c->One();
5068 ret = ret - c;
5069 ret = Diff(a->GetNode(0), vi) / Sqrt(ret); // f' / sqrt(f^2 - 1)
5070 break;
5071 case ATANH:
5072 if (sz != 1)
5073 {
5074 // check that there is exactly one operand
5075 throw ErrNotPermitted(19, "Expression", "Diff", "GetSize() != 1",
5076 "atanh must have exactly 1 operand",
5077 HELPURL);
5078 }
5079 ret = a->GetCopyOfNode(0);
5080 ret = ret ^ two;
5081 c->One();
5082 ret = c - ret;
5083 ret = Diff(a->GetNode(0), vi) / ret; // f' / (1 - tan(f)^2)
5084 break;
5085 case LOG2:
5086 if (sz != 1)
5087 {
5088 // check that there is exactly one operand
5089 throw ErrNotPermitted(14, "Expression", "Diff", "GetSize() != 1",
5090 "log2 must have exactly 1 operand",
5091 HELPURL);
5092 }
5093 if (a->GetNode(0)->IsLessThan(0))
5094 {
5095 throw ErrNotPermitted(15, "Expression", "Diff", "arg <= 0",
5096 "log2 argument must be symbolic or positive",
5097 HELPURL);
5098 }
5099 ret = Diff(a->GetNode(0), vi);
5100 ret = ret / (Expression(M_LN2) * a->GetCopyOfNode(0)); // f'/(log(2)f)
5101 break;
5102 case LOG10:
5103 if (sz != 1)
5104 {
5105 // check that there is exactly one operand
5106 throw ErrNotPermitted(14, "Expression", "Diff", "GetSize() != 1",
5107 "log10 must have exactly 1 operand",
5108 HELPURL);
5109 }
5110 if (a->GetNode(0)->IsLessThan(0))
5111 {
5112 throw ErrNotPermitted(15, "Expression", "Diff", "arg <= 0",
5113 "log10 argument must be symbolic or positive",
5114 HELPURL);
5115 }
5116 ret = Diff(a->GetNode(0), vi);
5117 ret = ret / (Expression(M_LN10) * a->GetCopyOfNode(0)); // f'/(log(10)f)
5118 break;
5119 case LOG:
5120 case LN:
5121 if (sz != 1)
5122 {
5123 // check that there is exactly one operand
5124 throw ErrNotPermitted(14, "Expression", "Diff", "GetSize() != 1",
5125 "log (ln) must have exactly 1 operand",
5126 HELPURL);
5127 }
5128 if (a->GetNode(0)->IsLessThan(0))
5129 {
5130 throw ErrNotPermitted(15, "Expression", "Diff", "arg <= 0",
5131 "log (ln) argument must be symbolic or positive",
5132 HELPURL);
5133 }
5134 ret = Diff(a->GetNode(0), vi);
5135 ret = ret / a->GetCopyOfNode(0); // f'/f
5136 break;
5137 case EXP:
5138 if (sz != 1)
5139 {
5140 // check that there is exactly one operand
5141 throw ErrNotPermitted(16, "Expression", "Diff", "GetSize() != 1",
5142 "exp must have exactly 1 operand",
5143 HELPURL);
5144 }
5145 ret = Diff(a->GetNode(0), vi) * Exp(a->GetCopyOfNode(0)); // f'exp(f)
5146 break;
5147 case ERF:
5148 if (sz != 1)
5149 {
5150 // check that there is exactly one operand
5151 throw ErrNotPermitted(16, "Expression", "Diff", "GetSize() != 1",
5152 "erf must have exactly 1 operand",
5153 HELPURL);
5154 }
5155 ret = Expression(M_2_SQRTPI) * Diff(a->GetCopyOfNode(0), vi) * Exp(-(a->GetCopyOfNode(0) ^ two)); // (2/sqrt(pi)) f'e^(-f^2)
5156 break;
5157 case ERFC:
5158 if (sz != 1)
5159 {
5160 // check that there is exactly one operand
5161 throw ErrNotPermitted(16, "Expression", "Diff", "GetSize() != 1",
5162 "erfc must have exactly 1 operand",
5163 HELPURL);
5164 }
5165 ret = Expression(-M_2_SQRTPI) * Diff(a->GetCopyOfNode(0), vi) * Exp(-(a->GetCopyOfNode(0) ^ two)); // (2/sqrt(pi)) f'e^(-f^2)
5166 break;
5167 case SQRT:
5168 if (sz != 1)
5169 {
5170 // check that there is exactly one operand
5171 throw ErrNotPermitted(19, "Expression", "Diff", "GetSize() != 1",
5172 "sqrt must have exactly 1 operand",
5173 HELPURL);
5174 }
5175 if (a->GetNode(0)->IsLessThan(0))
5176 {
5177 throw ErrNotPermitted(15, "Expression", "Diff", "arg < 0",
5178 "sqrt argument must be symbolic or positive",
5179 HELPURL);
5180 }
5181 ret = Expression(0.5) * Diff(a->GetNode(0), vi) / Sqrt(a->GetCopyOfNode(0)); // 1/2 * f' / sqrt(f)
5182 break;
5183 case CBRT:
5184 if (sz != 1)
5185 {
5186 // check that there is exactly one operand
5187 throw ErrNotPermitted(16, "Expression", "Diff", "GetSize() != 1",
5188 "cbrt must have exactly 1 operand",
5189 HELPURL);
5190 }
5191 ret = Expression(1.0 / 3.0) * Diff(a->GetNode(0), vi) / (a->GetCopyOfNode(0) ^ Expression(2.0 / 3.0)); // (1/3) f' / f^(2/3)
5192 break;
5193 case BESSELJ0:
5194 if (sz != 1)
5195 {
5196 // check that there is exactly one operand
5197 throw ErrNotPermitted(16, "Expression", "Diff", "GetSize() != 1",
5198 "besselJ0 must have exactly 1 operand",
5199 HELPURL);
5200 }
5201 ret = -Diff(a->GetNode(0), vi) * BesselJ1(a->GetCopyOfNode(0)); // -f'besselJ1(f)
5202 break;
5203 case BESSELJ1:
5204 if (sz != 1)
5205 {
5206 // check that there is exactly one operand
5207 throw ErrNotPermitted(16, "Expression", "Diff", "GetSize() != 1",
5208 "besselJ1 must have exactly 1 operand",
5209 HELPURL);
5210 }
5211 ret = a->GetCopyOfNode(0);
5212 ret = BesselJ0(ret) - BesselJ1(ret) / ret;
5213 ret = Diff(a->GetNode(0), vi) * ret; // f'(besselJ0(f) - besselJ1(f) / f)
5214 break;
5215 case BESSELY0:
5216 if (sz != 1)
5217 {
5218 // check that there is exactly one operand
5219 throw ErrNotPermitted(16, "Expression", "Diff", "GetSize() != 1",
5220 "besselY0 must have exactly 1 operand",
5221 HELPURL);
5222 }
5223 ret = -Diff(a->GetNode(0), vi) * BesselY1(a->GetCopyOfNode(0)); // -f'besselY1(f)
5224 break;
5225 case BESSELY1:
5226 if (sz != 1)
5227 {
5228 // check that there is exactly one operand
5229 throw ErrNotPermitted(16, "Expression", "Diff", "GetSize() != 1",
5230 "besselY1 must have exactly 1 operand",
5231 HELPURL);
5232 }
5233 ret = a->GetCopyOfNode(0);
5234 ret = BesselY0(ret) - BesselY1(ret) / ret;
5235 ret = Diff(a->GetNode(0), vi) * ret; // f'(besselY0(f) - besselY1(f) / f)
5236 break;
5237 case SIGN:
5238 case RINT:
5239 if (sz != 1)
5240 {
5241 // check that there is exactly one operand
5242 throw ErrNotPermitted(16, "Expression", "Diff", "GetSize() != 1",
5243 "sign (rint) must have exactly 1 operand",
5244 HELPURL);
5245 }
5246 ret = zero; // 0
5247 break;
5248 case ABS:
5249 if (sz != 1)
5250 {
5251 // check that there is exactly one operand
5252 throw ErrNotPermitted(16, "Expression", "Diff", "GetSize() != 1",
5253 "abs must have exactly 1 operand",
5254 HELPURL);
5255 }
5256 ret = Diff(a->GetNode(0), vi) * Sign(a->GetCopyOfNode(0)); // f'sign(f)
5257 break;
5258 default:
5259 if (sz != 1)
5260 {
5261 // check that there is exactly one operand
5262 throw ErrNotPermitted(14, "Expression", "Diff", "GetSize() != 1",
5263 "log must have exactly 1 operand",
5264 HELPURL);
5265 }
5266 throw ErrNotPermitted(16, "Expression", "Diff", "not implemented",
5267 "The derivative of the function is not implemented.",
5268 HELPURL);
5269 break;
5270 }
5271 ret->SetCoeff(ret->GetCoeff() * opcoeff);
5272 return ret;
5273 }
5274 }
5275 else
5276 {
5277 return zero;
5278 }
5279 return zero;
5280 }
5281
5282 /************************ simplifications **********************/
5283
TrigSimp(Expression a)5284 bool TrigSimp(Expression a)
5285 {
5286 Int i = 0;
5287 Int ret = 0;
5288 bool bret = false;
5289 bool ischanged = false;
5290 // first, recurse over all subnodes of a
5291 for(i = 0; i < a->GetSize(); i++)
5292 {
5293 ischanged = TrigSimp(a->GetNode(i));
5294 if (!bret && ischanged)
5295 {
5296 bret = true;
5297 }
5298 }
5299 // now try simplification on a
5300 if (a->GetOpType() == SUM && a->GetSize() > 1)
5301 {
5302 // try to look for a sin^2 and a cos^2
5303 Int sinpos = -1;
5304 Int cospos = -1;
5305 Int sinpossimple = -1;
5306 Int cospossimple = -1;
5307 for (i = 0; i < a->GetSize(); i++)
5308 {
5309 // cycle over subnodes
5310 if (a->GetNode(i)->GetOpType() == POWER)
5311 {
5312 if (a->GetNode(i)->GetNode(0)->GetOpType() == SIN &&
5313 a->GetNode(i)->GetNode(1)->HasValue(2))
5314 sinpos = i;
5315 }
5316 if (a->GetNode(i)->GetOpType() == POWER)
5317 {
5318 if (a->GetNode(i)->GetNode(0)->GetOpType() == COS &&
5319 a->GetNode(i)->GetNode(1)->HasValue(2))
5320 cospos = i;
5321 }
5322 if (a->GetNode(i)->GetOpType() == SIN &&
5323 a->GetNode(i)->GetExponent() == 2)
5324 {
5325 sinpossimple = i;
5326 }
5327 if (a->GetNode(i)->GetOpType() == COS &&
5328 a->GetNode(i)->GetExponent() == 2)
5329 {
5330 cospossimple = i;
5331 }
5332 }
5333
5334 if (sinpos != -1 && cospos != -1)
5335 {
5336 double coscoeff = a->GetNode(sinpos)->GetCoeff();
5337 double sincoeff = a->GetNode(cospos)->GetCoeff();
5338
5339 // found both, check their arguments
5340 if ((coscoeff == sincoeff) &&
5341 a->GetNode(sinpos)->GetNode(0)->GetNode(0)->IsEqualTo
5342 (a->GetNode(cospos)->GetNode(0)->GetNode(0)))
5343 {
5344 ret++; // augment simplification counter
5345 bret = true;
5346 // arguments are equal, can simplify
5347 Int f = sinpos < cospos ? sinpos : cospos; // last to delete
5348 Int l = sinpos > cospos ? sinpos : cospos; // first to delete
5349 a->DeleteNode(l);
5350 a->DeleteNode(f);
5351 // verify that there are still some nodes left
5352 if (a->GetSize() == 0)
5353 {
5354 // there aren't any, set a to one
5355 a->One();
5356 a->SetCoeff(coscoeff);
5357 }
5358 else
5359 {
5360 // there are some, check whether there is a constant part
5361 // we can add the 1 to
5362 bool addflag = false;
5363 for (i = 0; i < a->GetSize(); i++)
5364 {
5365 if (a->GetNode(i)->IsConstant())
5366 {
5367 // yes there is
5368 a->GetNode(i)->SetValue(a->GetNode(i)->GetSimpleValue() + 1);
5369 addflag = true;
5370 break;
5371 }
5372 }
5373 if (!addflag)
5374 {
5375 // no there wasn't, add it as a symbolic node
5376 Expression coeffexpr(coscoeff);
5377 a->AddNode(coeffexpr);
5378 }
5379 // check that there is more than just one node
5380 if (a->GetSize() == 1)
5381 {
5382 // only one node, shift everything one rank level up
5383 a = a->GetNode(0);
5384 }
5385 }
5386 }
5387 }
5388 if (sinpossimple != -1 && cospossimple != -1)
5389 {
5390 double coscoeff = a->GetNode(sinpossimple)->GetCoeff();
5391 double sincoeff = a->GetNode(cospossimple)->GetCoeff();
5392
5393 if ((coscoeff == sincoeff) &&
5394 a->GetNode(sinpossimple)->GetNode(0)->IsEqualTo
5395 (a->GetNode(cospossimple)->GetNode(0)))
5396 {
5397 ret++;
5398 bret = true;
5399 // arguments are equal, can simplify
5400 Int f = sinpossimple < cospossimple ? sinpossimple : cospossimple;
5401 Int l = sinpossimple > cospossimple ? sinpossimple : cospossimple;
5402 a->DeleteNode(l);
5403 a->DeleteNode(f);
5404 // verify that there are still some nodes left
5405 if (a->GetSize() == 0)
5406 {
5407 // there aren't any, set a to one
5408 a->One();
5409 a->SetCoeff(coscoeff);
5410 }
5411 else
5412 {
5413 // there are some, check whether there is a constant part
5414 // we can add the 1 to
5415 bool addflag = false;
5416 for (i = 0; i < a->GetSize(); i++)
5417 {
5418 if (a->GetNode(i)->IsConstant())
5419 {
5420 // yes there is
5421 a->GetNode(i)->SetValue(a->GetNode(i)->GetSimpleValue() + 1);
5422 addflag = true;
5423 break;
5424 }
5425 }
5426 if (!addflag)
5427 {
5428 // no there wasn't, add it as a symbolic node
5429 Expression coeffexpr(coscoeff);
5430 a->AddNode(coeffexpr);
5431 }
5432 // check that there is more than just one node
5433 if (a->GetSize() == 1)
5434 {
5435 // only one node, shift everything one rank level up
5436 a = a->GetNode(0);
5437 }
5438 }
5439 }
5440 }
5441 }
5442 if (ret > 0)
5443 bret = true;
5444 return bret;
5445 }
5446
5447 // generic simplification with modification of the expression
Simplify(Expression * a)5448 bool Simplify(Expression* a)
5449 {
5450 bool changedflag = false;
5451 bool ret = false;
5452 bool goonflag = true;
5453 while(goonflag)
5454 {
5455 goonflag = false;
5456 (*a)->ConsolidateProductCoeffs();
5457 (*a)->DistributeCoeffOverSum();
5458 ret = DifferenceToSum(a);
5459 if (ret)
5460 {
5461 changedflag = true;
5462 goonflag = true;
5463 }
5464 ret = SimplifyConstant(a);
5465 if (ret)
5466 {
5467 changedflag = true;
5468 goonflag = true;
5469 }
5470 ret = CompactProducts(a);
5471 if (ret)
5472 {
5473 changedflag = true;
5474 goonflag = true;
5475 }
5476 ret = CompactLinearPart(a);
5477 if (ret)
5478 {
5479 changedflag = true;
5480 goonflag = true;
5481 }
5482 ret = SimplifyRecursive(a);
5483 if (ret)
5484 {
5485 changedflag = true;
5486 goonflag = true;
5487 }
5488 ret = TrigSimp(*a);
5489 if (ret)
5490 {
5491 changedflag = true;
5492 goonflag = true;
5493 }
5494 }
5495 return changedflag;
5496 }
5497
5498 // call after DifferenceToSum
SimplifyConstant(Expression * a)5499 bool SimplifyConstant(Expression* a)
5500 {
5501 bool ret = false;
5502 Expression one(1.0);
5503 Expression zero(0.0);
5504 if ((*a)->GetExponent() == 0)
5505 {
5506 double c = (*a)->GetCoeff();
5507 RecursiveDestroy(a);
5508 a->SetTo(one);
5509 (*a)->SetCoeff(c);
5510 ret = true;
5511 }
5512 else if ((*a)->GetCoeff() == 0)
5513 {
5514 RecursiveDestroy(a);
5515 a->SetTo(zero);
5516 ret = true;
5517 }
5518 else
5519 {
5520 int i = 0;
5521 int op, ops;
5522 op = (*a)->GetOpType();
5523 bool ischanged = false;
5524 int sz = (*a)->GetSize();
5525 while (i < sz)
5526 {
5527 // simplify each of the terms
5528 ischanged = SimplifyConstant((*a)->GetNodePtr(i));
5529 if (!ret && ischanged)
5530 {
5531 ret = true;
5532 }
5533 i++;
5534 }
5535 i = 0;
5536 while (i < sz)
5537 {
5538 // simplify this operand as a whole
5539 ops = (*a)->GetNode(i)->GetOpType();
5540 switch(op)
5541 {
5542 case SUM:
5543 if (ops == CONST)
5544 {
5545 if ((*a)->GetNode(i)->GetValue() == 0)
5546 {
5547 (*a)->DeleteNode(i);
5548 ret = true;
5549 sz--;
5550 if (sz == 1)
5551 {
5552 a->SetTo((*a)->GetNode(1 - i));
5553 i = 0;
5554 sz = (*a)->GetSize();
5555 }
5556 }
5557 else
5558 {
5559 i++;
5560 }
5561 }
5562 else
5563 {
5564 i++;
5565 }
5566 break;
5567 case PRODUCT:
5568 if (ops == CONST)
5569 {
5570 if ((*a)->GetNode(i)->GetValue() == 1)
5571 {
5572 (*a)->DeleteNode(i);
5573 ret = true;
5574 sz--;
5575 if (sz == 1)
5576 {
5577 a->SetTo((*a)->GetNode(1 - i));
5578 i = 0;
5579 sz = (*a)->GetSize();
5580 }
5581 }
5582 else if ((*a)->GetNode(i)->GetValue() == 0)
5583 {
5584 RecursiveDestroy(a);
5585 ret = true;
5586 a->SetTo(zero);
5587 sz = 0;
5588 }
5589 else
5590 {
5591 i++;
5592 }
5593 }
5594 else
5595 {
5596 i++;
5597 }
5598 break;
5599 case FRACTION:
5600 if (ops == CONST && i == 1)
5601 {
5602 double c = (*a)->GetCoeff();
5603 a->SetTo((*a)->GetNode(0));
5604 (*a)->SetCoeff((*a)->GetCoeff() * c);
5605 ret = true;
5606 sz--;
5607 }
5608 else
5609 {
5610 i++;
5611 }
5612 if (sz >= 2 && (*a)->GetNode(0)->IsConstant() &&
5613 (*a)->GetNode(1)->IsConstant())
5614 {
5615 double d = (*a)->GetNode(1)->GetValue();
5616 if (d == 0)
5617 {
5618 throw ErrDivideByZero(23, "Expression", "SimplifyConstant",
5619 "d==0",
5620 "cannot divide by zero", HELPURL,
5621 (*a)->ToString());
5622 }
5623 ret = true;
5624 a->SetTo((*a)->GetNode(0));
5625 (*a)->SetValue((*a)->GetValue() / d);
5626 (*a)->SetCoeff(1.0);
5627 (*a)->SetExponent(1.0);
5628 sz = 0;
5629 }
5630 break;
5631 case POWER:
5632 if (sz >= 2 && (*a)->GetNode(0)->IsConstant() &&
5633 (*a)->GetNode(1)->IsConstant())
5634 {
5635 double d = (*a)->GetNode(1)->GetValue();
5636 ret = true;
5637 a->SetTo((*a)->GetNode(0));
5638 (*a)->SetValue(pow((*a)->GetValue(), d));
5639 (*a)->SetCoeff(1.0);
5640 (*a)->SetExponent(1.0);
5641 sz = 0;
5642 }
5643 else
5644 {
5645 i++;
5646 }
5647 break;
5648 case LOG:
5649 if ((*a)->GetNode(0)->IsConstant())
5650 {
5651 double d = (*a)->GetNode(0)->GetValue();
5652 if (d <= 0)
5653 {
5654 throw ErrNotPermitted(24, "Expression", "SimplifyConstant",
5655 "d<=0",
5656 "log of nonpositive not allowed", HELPURL);
5657 }
5658 ret = true;
5659 a->SetTo((*a)->GetNode(0));
5660 (*a)->SetValue(log(d));
5661 (*a)->SetCoeff(1.0);
5662 (*a)->SetExponent(1.0);
5663 sz = 0;
5664 }
5665 else
5666 {
5667 i++;
5668 }
5669 break;
5670 case EXP:
5671 if ((*a)->GetNode(0)->IsConstant())
5672 {
5673 double d = (*a)->GetNode(0)->GetValue();
5674 ret = true;
5675 a->SetTo((*a)->GetNode(0));
5676 (*a)->SetValue(exp(d));
5677 (*a)->SetCoeff(1.0);
5678 (*a)->SetExponent(1.0);
5679 sz = 0;
5680 }
5681 else
5682 {
5683 i++;
5684 }
5685 break;
5686 case SIN:
5687 if ((*a)->GetNode(0)->IsConstant())
5688 {
5689 double d = (*a)->GetNode(0)->GetValue();
5690 ret = true;
5691 a->SetTo((*a)->GetNode(0));
5692 (*a)->SetValue(sin(d));
5693 (*a)->SetCoeff(1.0);
5694 (*a)->SetExponent(1.0);
5695 sz = 0;
5696 }
5697 else
5698 {
5699 i++;
5700 }
5701 break;
5702 case COS:
5703 if ((*a)->GetNode(0)->IsConstant())
5704 {
5705 double d = (*a)->GetNode(0)->GetValue();
5706 ret = true;
5707 a->SetTo((*a)->GetNode(0));
5708 (*a)->SetValue(cos(d));
5709 (*a)->SetCoeff(1.0);
5710 (*a)->SetExponent(1.0);
5711 sz = 0;
5712 }
5713 else
5714 {
5715 i++;
5716 }
5717 break;
5718 case TAN:
5719 if ((*a)->GetNode(0)->IsConstant())
5720 {
5721 double d = (*a)->GetNode(0)->GetValue();
5722 ret = true;
5723 a->SetTo((*a)->GetNode(0));
5724 (*a)->SetValue(tan(d));
5725 (*a)->SetCoeff(1.0);
5726 (*a)->SetExponent(1.0);
5727 sz = 0;
5728 }
5729 else
5730 {
5731 i++;
5732 }
5733 break;
5734 case COT:
5735 if ((*a)->GetNode(0)->IsConstant())
5736 {
5737 double d = (*a)->GetNode(0)->GetValue();
5738 ret = true;
5739 a->SetTo((*a)->GetNode(0));
5740 (*a)->SetValue(1 / tan(d));
5741 (*a)->SetCoeff(1.0);
5742 (*a)->SetExponent(1.0);
5743 sz = 0;
5744 }
5745 else
5746 {
5747 i++;
5748 }
5749 break;
5750 case SINH:
5751 if ((*a)->GetNode(0)->IsConstant())
5752 {
5753 double d = (*a)->GetNode(0)->GetValue();
5754 ret = true;
5755 a->SetTo((*a)->GetNode(0));
5756 (*a)->SetValue(sinh(d));
5757 (*a)->SetCoeff(1.0);
5758 (*a)->SetExponent(1.0);
5759 sz = 0;
5760 }
5761 else
5762 {
5763 i++;
5764 }
5765 break;
5766 case COSH:
5767 if ((*a)->GetNode(0)->IsConstant())
5768 {
5769 double d = (*a)->GetNode(0)->GetValue();
5770 ret = true;
5771 a->SetTo((*a)->GetNode(0));
5772 (*a)->SetValue(cosh(d));
5773 (*a)->SetCoeff(1.0);
5774 (*a)->SetExponent(1.0);
5775 sz = 0;
5776 }
5777 else
5778 {
5779 i++;
5780 }
5781 break;
5782 case TANH:
5783 if ((*a)->GetNode(0)->IsConstant())
5784 {
5785 double d = (*a)->GetNode(0)->GetValue();
5786 ret = true;
5787 a->SetTo((*a)->GetNode(0));
5788 (*a)->SetValue(tanh(d));
5789 (*a)->SetCoeff(1.0);
5790 (*a)->SetExponent(1.0);
5791 sz = 0;
5792 }
5793 else
5794 {
5795 i++;
5796 }
5797 break;
5798 case COTH:
5799 if ((*a)->GetNode(0)->IsConstant())
5800 {
5801 double d = (*a)->GetNode(0)->GetValue();
5802 ret = true;
5803 a->SetTo((*a)->GetNode(0));
5804 (*a)->SetValue(1 / tanh(d));
5805 (*a)->SetCoeff(1.0);
5806 (*a)->SetExponent(1.0);
5807 sz = 0;
5808 }
5809 else
5810 {
5811 i++;
5812 }
5813 break;
5814 case SQRT:
5815 if ((*a)->GetNode(0)->IsConstant())
5816 {
5817 double d = (*a)->GetNode(0)->GetValue();
5818 if (d <= 0)
5819 {
5820 throw ErrNotPermitted(25, "Expression", "SimplifyConstant",
5821 "d<=0",
5822 "sqrt of nonpositive not allowed", HELPURL);
5823 }
5824 ret = true;
5825 a->SetTo((*a)->GetNode(0));
5826 (*a)->SetValue(sqrt(d));
5827 (*a)->SetCoeff(1.0);
5828 (*a)->SetExponent(1.0);
5829 sz = 0;
5830 }
5831 else
5832 {
5833 i++;
5834 }
5835 break;
5836 default:
5837 i++;
5838 break;
5839 }
5840 }
5841 }
5842 return ret;
5843 }
5844
SimplifyRecursive(Expression * a)5845 bool SimplifyRecursive(Expression* a)
5846 {
5847 bool ret = false;
5848 bool ischanged = false;
5849 // signals whether we're dealing with
5850 // -1 : nothing
5851 // 0 : constants
5852 // 1 : linear variables
5853 // 2 : a variable raised to an exponent different from 1
5854 // 3 : any other more complex node
5855 if (!(*a)->IsLeaf())
5856 {
5857 int op = (*a)->GetOpType();
5858 Expression t1, t2;
5859 int i, j;
5860 for(i = 0; i < (*a)->GetSize(); i++)
5861 {
5862 ischanged = SimplifyRecursive((*a)->GetNodePtr(i));
5863 if (!ret && ischanged)
5864 ret = true;
5865 }
5866 int status = -1;
5867 int prestatus = -1;
5868 double consolidated[4] = {0, 0, 0, 0};
5869 double expon = 0;
5870 double preexpon = 0;
5871 double c = 0;
5872 int prevarindex = -1;
5873 int prevarpowindex = -1;
5874 int varindex = -1;
5875 int varpowindex = -1;
5876 int firstvarindex = -1;
5877 int firstvarpowindex = -1;
5878 int firstconstindex = -1;
5879 int sz = (*a)->GetSize();
5880 Expression one(1.0);
5881
5882 switch(op)
5883 {
5884 case SUM:
5885 i = 0;
5886 while(i < sz)
5887 {
5888 // work out which status we're in
5889 if ((*a)->GetNode(i)->IsConstant())
5890 {
5891 if (status == -1 || firstconstindex == -1)
5892 {
5893 firstconstindex = i;
5894 }
5895 // constant
5896 status = 0;
5897 }
5898 else if ((*a)->GetNode(i)->IsVariable() &&
5899 (*a)->GetNode(i)->GetExponent() == 1)
5900 {
5901 // variable
5902 status = 1;
5903 }
5904 else if ((*a)->GetNode(i)->IsVariable() &&
5905 (*a)->GetNode(i)->GetExponent() != 1)
5906 {
5907 // variable raised to power
5908 status = 2;
5909 }
5910 else
5911 {
5912 // other term
5913 status = 3;
5914 }
5915 if (status == 0)
5916 {
5917 // constant
5918 consolidated[status] += (*a)->GetNode(i)->GetValue();
5919 (*a)->GetNode(firstconstindex)->SetValue(consolidated[status]);
5920 (*a)->GetNode(firstconstindex)->SetCoeff(1.0);
5921 (*a)->GetNode(firstconstindex)->SetExponent(1.0);
5922 if (prestatus == 0)
5923 {
5924 (*a)->DeleteNode(i);
5925 ret = true;
5926 sz--;
5927 if (sz == 1)
5928 {
5929 a->SetTo((*a)->GetNode(0));
5930 i = 0;
5931 sz = (*a)->GetSize();
5932 }
5933 }
5934 else
5935 {
5936 i++;
5937 }
5938 }
5939 else if (status == 1)
5940 {
5941 // variable
5942 varindex = (*a)->GetNode(i)->GetVarIndex();
5943 c = (*a)->GetNode(i)->GetCoeff();
5944 if (varindex != prevarindex)
5945 {
5946 firstvarindex = i;
5947 consolidated[status] = c;
5948 i++;
5949 }
5950 else
5951 {
5952 consolidated[status] += c;
5953 (*a)->GetNode(firstvarindex)->SetCoeff(consolidated[status]);
5954 ret = true;
5955 (*a)->DeleteNode(i);
5956 sz--;
5957 if (sz == 1)
5958 {
5959 a->SetTo((*a)->GetNode(0));
5960 i = 0;
5961 sz = (*a)->GetSize();
5962 }
5963 }
5964 prevarindex = varindex;
5965 }
5966 else if (status == 2)
5967 {
5968 // variable raised to power
5969 varpowindex = (*a)->GetNode(i)->GetVarIndex();
5970 expon = (*a)->GetNode(i)->GetExponent();
5971 c = (*a)->GetNode(i)->GetCoeff();
5972 if (expon != preexpon || varpowindex != prevarpowindex)
5973 {
5974 firstvarpowindex = i;
5975 consolidated[status] = c;
5976 i++;
5977 }
5978 else
5979 {
5980 consolidated[status] += c;
5981 (*a)->GetNode(firstvarpowindex)->SetCoeff(consolidated[status]);
5982 ret = true;
5983 (*a)->DeleteNode(i);
5984 sz--;
5985 if (sz == 1)
5986 {
5987 a->SetTo((*a)->GetNode(0));
5988 i = 0;
5989 sz = (*a)->GetSize();
5990 }
5991 }
5992 preexpon = expon;
5993 prevarpowindex = varpowindex;
5994 }
5995 else if (status == 3)
5996 {
5997 // other term
5998 c = (*a)->GetNode(i)->GetCoeff();
5999 firstvarindex = i;
6000 consolidated[status] = c;
6001 j = i + 1;
6002 while(j < sz)
6003 {
6004 if ((*a)->GetNode(i)->IsEqualToNoCoeff((*a)->GetNode(j)))
6005 {
6006 c = (*a)->GetNode(j)->GetCoeff();
6007 consolidated[status] += c;
6008 ret = true;
6009 (*a)->GetNode(firstvarindex)->SetCoeff(consolidated[status]);
6010 RecursiveDestroy((*a)->GetNodePtr(j));
6011 (*a)->DeleteNode(j);
6012 sz--;
6013 if (sz == 1)
6014 {
6015 a->SetTo((*a)->GetNode(0));
6016 j = i + 1;
6017 sz = (*a)->GetSize();
6018 }
6019 }
6020 else
6021 {
6022 j++;
6023 }
6024 }
6025 i++;
6026 }
6027 else
6028 {
6029 // should never happen, but anyway...
6030 i++;
6031 }
6032 // update status of last iteration
6033 prestatus = status;
6034 }
6035 break;
6036 case PRODUCT:
6037 i = 0;
6038 prevarindex = -1;
6039 consolidated[0] = 1;
6040 expon = 0;
6041 while(i < sz)
6042 {
6043 if ((*a)->GetNode(i)->IsVariable())
6044 {
6045 varindex = (*a)->GetNode(i)->GetVarIndex();
6046 if (varindex != prevarindex)
6047 {
6048 firstvarindex = i;
6049 consolidated[0] = (*a)->GetNode(i)->GetCoeff();
6050 expon = (*a)->GetNode(i)->GetExponent();
6051 i++;
6052 }
6053 else
6054 {
6055 consolidated[0] *= (*a)->GetNode(i)->GetCoeff();
6056 expon += (*a)->GetNode(i)->GetExponent();
6057 (*a)->GetNode(firstvarindex)->SetCoeff(consolidated[0]);
6058 (*a)->GetNode(firstvarindex)->SetExponent(expon);
6059 (*a)->DeleteNode(i);
6060 ret = true;
6061 sz--;
6062 if (sz == 1)
6063 {
6064 a->SetTo((*a)->GetNode(0));
6065 i = 0;
6066 sz = (*a)->GetSize();
6067 }
6068 }
6069 }
6070 else if (!(*a)->GetNode(i)->IsLeaf())
6071 {
6072 // WARNING: work to be done
6073 // not going to do the same as in sum just yet, maybe future
6074 // work - transform expr * expr in expr^2 when expr not a variable
6075 i++;
6076 }
6077 }
6078 break;
6079 case FRACTION:
6080 if ((*a)->GetNode(0)->IsEqualTo((*a)->GetNode(1)))
6081 {
6082 // f(x)/f(x)
6083 c = (*a)->GetCoeff();
6084 RecursiveDestroy(a);
6085 a->SetTo(Expression(c));
6086 ret = true;
6087 sz = 0;
6088 }
6089 else
6090 {
6091 // try to simplify denominator by one of numerator factors
6092 if ((*a)->GetNode(0)->GetOpType() == PRODUCT)
6093 {
6094 for(j = 0; j < (*a)->GetNode(0)->GetSize(); j++)
6095 {
6096 if ((*a)->GetNode(1)->IsEqualTo((*a)->GetNode(0)->GetNode(j)))
6097 {
6098 c = (*a)->GetCoeff();
6099 a->SetTo((*a)->GetNode(0));
6100 (*a)->SetCoeff((*a)->GetCoeff() * c);
6101 (*a)->DeleteNode(j);
6102 ret = true;
6103 sz = 0;
6104 break;
6105 }
6106 }
6107 }
6108 // do the opposite
6109 if (sz > 0 && (*a)->GetNode(1)->GetOpType() == PRODUCT)
6110 {
6111 for(j = 0; j < (*a)->GetNode(1)->GetSize(); j++)
6112 {
6113 if ((*a)->GetNode(0)->IsEqualTo((*a)->GetNode(1)->GetNode(j)))
6114 {
6115 *((*a)->GetNodePtr(0)) = Pointer<BasicExpression>(one);
6116 (*a)->GetNode(1)->DeleteNode(j);
6117 ret = true;
6118 sz = 0;
6119 break;
6120 }
6121 }
6122 }
6123 if (sz > 0 && (*a)->GetNode(0)->GetOpType() == PRODUCT &&
6124 (*a)->GetNode(1)->GetOpType() == PRODUCT)
6125 {
6126 // both num and denom. are products, try and find common factors
6127 int k = 0;
6128 int sz1, sz2;
6129 j = 0;
6130 sz1 = (*a)->GetNode(0)->GetSize();
6131 sz2 = (*a)->GetNode(1)->GetSize();
6132 while (j < sz1)
6133 {
6134 k = 0;
6135 while (k < sz2)
6136 {
6137 if ((*a)->GetNode(0)->GetNode(j)->IsEqualTo
6138 ((*a)->GetNode(1)->GetNode(k)))
6139 {
6140 (*a)->GetNode(0)->DeleteNode(j);
6141 (*a)->GetNode(1)->DeleteNode(k);
6142 ret = true;
6143 sz1--;
6144 if (sz1 == 0)
6145 {
6146 // numerator empty, replace with 1
6147 (*a)->GetNode(0)->One();
6148 }
6149 sz2--;
6150 if (sz2 == 0)
6151 {
6152 // denominator empty, node becomes num.
6153 a->SetTo((*a)->GetNode(0));
6154 }
6155 if (sz1 == 0 && sz2 == 0)
6156 {
6157 // 1/1, simplify
6158 (*a)->One();
6159 }
6160 if (sz1 == 0 || sz2 == 0)
6161 {
6162 // either num. or den. 1, exit loop
6163 sz1 = 0;
6164 sz2 = 0;
6165 break;
6166 }
6167 j--;
6168 }
6169 else
6170 {
6171 k++;
6172 }
6173 }
6174 j++;
6175 }
6176 }
6177 }
6178 sz = 0;
6179 break;
6180 case POWER:
6181 if (sz == 2 &&
6182 (*a)->GetNode(0)->IsVariable() &&
6183 (*a)->GetNode(1)->IsConstant())
6184 {
6185 // case var^const, transform in variable with an exponent
6186 expon = (*a)->GetNode(1)->GetValue();
6187 c = (*a)->GetCoeff();
6188 double c0 = (*a)->GetNode(0)->GetCoeff();
6189 (*a)->GetNode(0)->SetExponent(expon);
6190 (*a)->DeleteNode(1);
6191 a->SetTo((*a)->GetNode(0));
6192 (*a)->SetCoeff(c * pow(c0, expon));
6193 }
6194 break;
6195 default:
6196 break;
6197 }
6198 }
6199 return ret;
6200 }
6201
DifferenceToSum(Expression * a)6202 bool DifferenceToSum(Expression* a)
6203 {
6204 bool ret = false;
6205 double d = 0., e = 0.;
6206 if (!(*a)->IsLeaf())
6207 {
6208 if (((*a)->GetOpType() == SUM || (*a)->GetOpType() == DIFFERENCE) &&
6209 (*a)->GetSize() == 1)
6210 {
6211 DifferenceToSum((*a)->GetNodePtr(0));
6212 // replace a with its child
6213 a->SetTo((*a)->GetNode(0));
6214 ret = true;
6215 }
6216 if ((*a)->GetOpType() == DIFFERENCE)
6217 {
6218 int i;
6219 (*a)->SetOpType(SUM);
6220 for(i = 1; i < (*a)->GetSize(); i++)
6221 {
6222 // start from node 1 not 0 because a difference is +op0 -op1 -op2 ...
6223 (*a)->GetNode(i)->SetCoeff(- (*a)->GetNode(i)->GetCoeff());
6224 }
6225 }
6226 else if ((*a)->GetOpType() == MINUS)
6227 {
6228 d = (*a)->GetCoeff();
6229 e = (*a)->GetExponent();
6230 if (is_even(e))
6231 {
6232 // replace a with its child and adjust coeff
6233 a->SetTo((*a)->GetNode(0));
6234 (*a)->SetCoeff((*a)->GetCoeff() * d); // since exponent is even, +
6235 (*a)->SetExponent((*a)->GetExponent() * e);
6236 ret = true;
6237 }
6238 else if (is_odd(e))
6239 {
6240 // replace a with its child and adjust coeff
6241 a->SetTo((*a)->GetNode(0));
6242 (*a)->SetCoeff(- (*a)->GetCoeff() * d); // since exponent is odd, -
6243 (*a)->SetExponent((*a)->GetExponent() * e);
6244 ret = true;
6245 }
6246 }
6247 else if ((*a)->GetOpType() == PLUS)
6248 {
6249 // replace a with its child
6250 a->SetTo((*a)->GetNode(0));
6251 (*a)->SetCoeff((*a)->GetCoeff() * d); // since exponent is even, +
6252 (*a)->SetExponent((*a)->GetExponent() * e);
6253 ret = true;
6254 }
6255 }
6256 return ret;
6257 }
6258
6259 // standard order for a set of subnodes of a sum is:
6260 // constants + linear variables + vars^{rising powers} + complex operands
6261 class NodeOrderSum
6262 {
6263 public:
operator ()(const Expression & a,const Expression & b)6264 int operator() (const Expression& a,
6265 const Expression& b)
6266 {
6267 if (a->IsConstant() && !b->IsConstant())
6268 {
6269 return true;
6270 }
6271 else if (a->IsVariable() && b->IsVariable())
6272 {
6273 if (a->GetExponent() == 1 && b->GetExponent() != 1)
6274 {
6275 return true;
6276 }
6277 else if (a->GetExponent() < b->GetExponent())
6278 {
6279 return true;
6280 }
6281 else if (a->GetExponent() > b->GetExponent())
6282 {
6283 return false;
6284 }
6285 else
6286 {
6287 if (a->GetVarIndex() < b->GetVarIndex())
6288 {
6289 return true;
6290 }
6291 else
6292 {
6293 return false;
6294 }
6295 }
6296 }
6297 else if (a->IsLeaf() && !b->IsLeaf())
6298 {
6299 return true;
6300 }
6301 else
6302 {
6303 return false;
6304 }
6305 }
6306 };
6307
6308 // standard order for a set of subnodes is:
6309 // constants + vars^{rising powers} + complex operands
6310 class NodeOrder
6311 {
6312 public:
operator ()(const Expression & a,const Expression & b)6313 int operator() (const Expression& a,
6314 const Expression& b)
6315 {
6316 if (a->IsConstant() && !b->IsConstant())
6317 {
6318 return true;
6319 }
6320 else if (a->IsVariable() && b->IsVariable())
6321 {
6322 if (a->GetExponent() < b->GetExponent())
6323 {
6324 return true;
6325 }
6326 else if (a->GetExponent() > b->GetExponent())
6327 {
6328 return false;
6329 }
6330 else
6331 {
6332 if (a->GetVarIndex() < b->GetVarIndex())
6333 {
6334 return true;
6335 }
6336 else
6337 {
6338 return false;
6339 }
6340 }
6341 }
6342 else if (a->IsLeaf() && !b->IsLeaf())
6343 {
6344 return true;
6345 }
6346 else
6347 {
6348 return false;
6349 }
6350 }
6351 };
6352
ReorderNodes(Expression * a)6353 bool ReorderNodes(Expression* a)
6354 {
6355 bool ret = false;
6356 if (!(*a)->IsLeaf() && (*a)->GetSize() > 1 &&
6357 ((*a)->GetOpType() == SUM || (*a)->GetOpType() == PRODUCT))
6358 {
6359 int i;
6360 for(i = 0; i < (*a)->GetSize(); i++)
6361 {
6362 ReorderNodes((*a)->GetNodePtr(i));
6363 }
6364 // how do I get this sort to tell me whether it did anything or not?
6365 // at the moment this function returns false by definition, incorrect
6366 if ((*a)->GetOpType() == SUM)
6367 {
6368 sort(((*a)->GetNodeVectorPtr())->begin(),
6369 ((*a)->GetNodeVectorPtr())->end(), NodeOrderSum());
6370 }
6371 else
6372 {
6373 sort(((*a)->GetNodeVectorPtr())->begin(),
6374 ((*a)->GetNodeVectorPtr())->end(), NodeOrder());
6375 }
6376 }
6377 return ret;
6378 }
6379
CompactLinearPart(Expression * a)6380 bool CompactLinearPart(Expression* a)
6381 {
6382 bool ret = false;
6383 bool ischanged = false;
6384 ischanged = SimplifyConstant(a);
6385 if (!ret && ischanged)
6386 ret = true;
6387 ischanged = DifferenceToSum(a);
6388 if (!ret && ischanged)
6389 ret = true;
6390 ischanged = CompactLinearPartRecursive(a);
6391 if (!ret && ischanged)
6392 ret = true;
6393 ischanged = ReorderNodes(a);
6394 return ret;
6395 }
6396
CompactLinearPartRecursive(Expression * a)6397 bool CompactLinearPartRecursive(Expression* a)
6398 {
6399 bool ret = false;
6400 bool ischanged = false;
6401 int i, j;
6402 i = 0;
6403 int sz = (*a)->GetSize();
6404 if ((*a)->GetOpType() == SUM)
6405 {
6406 while(i < sz)
6407 {
6408 ischanged = CompactLinearPartRecursive((*a)->GetNodePtr(i));
6409 if (!ret && ischanged)
6410 ret = true;
6411 if ((*a)->GetNode(i)->GetOpType() == SUM)
6412 {
6413 ret = true;
6414 double ci = (*a)->GetNode(i)->GetCoeff();
6415 for(j = 0; j < (*a)->GetNode(i)->GetSize(); j++)
6416 {
6417 Expression nodej((*a)->GetNode(i)->GetNode(j));
6418 nodej->SetCoeff(nodej->GetCoeff() * ci);
6419 (*a)->AddNode(nodej);
6420 ++ sz;// we added a node
6421 }
6422 (*a)->DeleteNode(i);
6423 -- sz; // we have deleted a node
6424 // we don't need to increase i, since we have deleted the i-th node
6425 // the next node is still the i-th node
6426 if (sz == 1)
6427 {
6428 a->SetTo((*a)->GetNode(0));
6429 i = 0;
6430 sz = (*a)->GetSize();
6431 }
6432 }
6433 else
6434 {
6435 i++;
6436 }
6437 }
6438 }
6439 return ret;
6440 }
6441
6442
6443 // deals with cases like *(*(x,y), z) --> *(x,y,z)
CompactProducts(Expression * a)6444 bool CompactProducts(Expression* a)
6445 {
6446 bool ret = false;
6447 bool ischanged = false;
6448 int i, j;
6449 if ((*a)->GetOpType() == PRODUCT)
6450 {
6451 for(i = 0; i < (*a)->GetSize(); i++)
6452 {
6453 ischanged = CompactProducts((*a)->GetNodePtr(i));
6454 if (!ret && ischanged)
6455 ret = true;
6456 if ((*a)->GetNode(i)->GetOpType() == PRODUCT)
6457 {
6458 ret = true;
6459 for(j = 0; j < (*a)->GetNode(i)->GetSize(); j++)
6460 {
6461 (*a)->AddNode((*a)->GetNode(i)->GetNode(j));
6462 }
6463 (*a)->DeleteNode(i);
6464 }
6465 }
6466 if ((*a)->GetSize() == 1)
6467 {
6468 // product with just one operand, up a level
6469 double c = (*a)->GetCoeff();
6470 a->SetTo((*a)->GetNode(0));
6471 (*a)->SetCoeff((*a)->GetCoeff() * c);
6472 ret = true;
6473 }
6474 }
6475 else
6476 {
6477 // not a product, recurse
6478 for(i = 0; i < (*a)->GetSize(); i++)
6479 {
6480 ischanged = CompactProducts((*a)->GetNodePtr(i));
6481 if (!ret && ischanged)
6482 {
6483 ret = true;
6484 }
6485 }
6486 }
6487 (*a)->ConsolidateProductCoeffs();
6488 return ret;
6489 }
6490
6491 // generic simplification on a copy of the expression
SimplifyCopy(Expression * a,bool & ischanged)6492 Expression SimplifyCopy(Expression* a,
6493 bool & ischanged)
6494 {
6495 Expression b;
6496 b = (*a).Copy();
6497 ischanged = Simplify(&b);
6498 return b;
6499 }
6500
6501 // recursive destroy - deleted all the tree and nodes in a tree - use
6502 // with caution
RecursiveDestroy(Expression * a)6503 void RecursiveDestroy(Expression* a)
6504 {
6505 int i;
6506 for(i = 0; i < (*a)->GetSize(); i++)
6507 {
6508 RecursiveDestroy((*a)->GetNodePtr(i));
6509 }
6510 a->Destroy();
6511 }
6512
6513
6514 } /* namespace Ev3 */
6515