Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2929_PrioritizedGrammarEnumeration/HeuristicLab.Algorithms.DataAnalysis.PGE/3.3/go-code/go-symexpr/simp.go @ 16080

Last change on this file since 16080 was 16080, checked in by hmaislin, 6 years ago

#2929 initial commit of working PGE version

File size: 35.2 KB
Line 
1package symexpr
2
3import (
4  "math"
5
6  // "fmt"
7)
8
9type SimpRules struct {
10  GroupAddTerms bool
11  ConvertConsts bool
12  MulToPow      bool
13  MaxPowPow     int
14
15  MulInCoeff int // add must be >= to size, 0 == No
16
17  // state tracking
18  InTrig bool
19}
20
21func DefaultRules() SimpRules {
22  return SimpRules{true, true, true, 12, 0, false}
23}
24
25func (l *Leaf) Simplify(rules SimpRules) Expr  { return nil }
26func (u *Unary) Simplify(rules SimpRules) Expr { return nil }
27func (n *N_ary) Simplify(rules SimpRules) Expr { return nil }
28
29func (n *Time) Simplify(rules SimpRules) Expr { return n }
30
31func (v *Var) Simplify(rules SimpRules) Expr { return v }
32
33func (c *Constant) Simplify(rules SimpRules) Expr { return c }
34
35func (c *ConstantF) Simplify(rules SimpRules) Expr {
36  if math.IsNaN(c.F) || math.IsInf(c.F, 0) {
37    return nil
38  }
39  // "close" to system value ??? TODO
40
41  return c
42}
43
44func (s *System) Simplify(rules SimpRules) Expr { return s }
45
46func (u *Neg) Simplify(rules SimpRules) (ret Expr) {
47  if u.C == nil {
48    return nil
49  }
50  u.C = u.C.Simplify(rules)
51  if u.C == nil {
52    return nil
53  }
54  switch u.C.ExprType() {
55  case NULL:
56    ret = nil
57    u.C = nil
58  case NEG:
59    ret = u.C
60    u.C = nil
61  case CONSTANT:
62    ret = u.C
63    u.C = nil
64  case CONSTANTF:
65    c := u.C.(*ConstantF)
66    c.F *= -1.0
67    ret = u.C
68    u.C = nil
69  case MUL:
70    m := u.C.(*Mul)
71    if m.CS[0].ExprType() == CONSTANT { // Constants should always be first operand in Mul
72      ret = u.C
73      u.C = nil
74    } else if m.CS[0].ExprType() == CONSTANTF { // Constants should always be first operand in Mul
75      c := m.CS[0].(*ConstantF)
76      c.F *= -1.0
77      ret = u.C
78      u.C = nil
79    }
80  default: // no simplification
81    ret = u
82  }
83  return ret
84}
85
86func (u *Abs) Simplify(rules SimpRules) (ret Expr) {
87  if u.C == nil {
88    return nil
89  }
90  u.C = u.C.Simplify(rules)
91  if u.C == nil {
92    return nil
93  }
94  switch u.C.ExprType() {
95  case NULL:
96    ret = nil
97    u.C = nil
98  case ABS:
99    ret = u.C
100    u.C = nil
101  default: // no simplification
102    ret = u
103  }
104  return ret
105}
106
107func (u *Sqrt) Simplify(rules SimpRules) (ret Expr) {
108  if u.C == nil {
109    return nil
110  }
111  u.C = u.C.Simplify(rules)
112  if u.C == nil {
113    return nil
114  }
115  switch u.C.ExprType() {
116  case NULL:
117    ret = nil
118    u.C = nil
119  case SQRT:
120    s := u.C.(*Sqrt)
121    ret = NewPowF(s.C, 0.25)
122    u.C = nil
123  case CONSTANT:
124    ret = u.C
125    u.C = nil
126  case CONSTANTF:
127    ret = u.C
128    u.C = nil
129    ret.(*ConstantF).F = math.Sqrt(ret.(*ConstantF).F)
130  case POWF:
131    p := u.C.(*PowF)
132    p.Power *= 0.5
133    ret = p
134    u.C = nil
135  case POWI:
136    p := u.C.(*PowI)
137    if p.Power == 2 {
138      ret = p.Base
139      p.Base = nil
140    } else if p.Power%2 == 0 {
141      p.Power /= 2
142      ret = p
143      u.C = nil
144    } else {
145      f := NewPowF(p.Base, float64(p.Power)*0.5)
146      ret = f
147      p.Base = nil
148    }
149
150  default: // no simplification
151    ret = u
152  }
153  return ret
154}
155
156func (u *Sin) Simplify(rules SimpRules) (ret Expr) {
157  // fmt.Printf("Simp Sin:  %v\n", u.C)
158  if !rules.InTrig {
159    rules.InTrig = true
160  } else {
161    tmp := u.C
162    u.C = nil
163    return tmp
164  }
165  if u.C == nil {
166    return nil
167  }
168  u.C = u.C.Simplify(rules)
169  if u.C == nil {
170    return nil
171  }
172  // fmt.Printf("      %v\n", u.C)
173  switch u.C.ExprType() {
174  case NULL, SIN, COS, TAN, CONSTANT:
175    ret = u.C
176    u.C = nil
177  case CONSTANTF:
178    ret = u.C
179    u.C = nil
180    ret.(*ConstantF).F = math.Sin(ret.(*ConstantF).F)
181  default: // no simplification
182    ret = u
183  }
184  return ret
185}
186
187func (u *Cos) Simplify(rules SimpRules) (ret Expr) {
188  if !rules.InTrig {
189    rules.InTrig = true
190  } else {
191    tmp := u.C
192    u.C = nil
193    return tmp
194  }
195  if u.C == nil {
196    return nil
197  }
198  u.C = u.C.Simplify(rules)
199  if u.C == nil {
200    return nil
201  }
202  switch u.C.ExprType() {
203  case NULL, SIN, COS, TAN, CONSTANT:
204    ret = u.C
205    u.C = nil
206  case CONSTANTF:
207    ret = u.C
208    u.C = nil
209    ret.(*ConstantF).F = math.Cos(ret.(*ConstantF).F)
210  default: // no simplification
211    ret = u
212  }
213  return ret
214}
215
216func (u *Tan) Simplify(rules SimpRules) (ret Expr) {
217  if !rules.InTrig {
218    rules.InTrig = true
219  } else {
220    tmp := u.C
221    u.C = nil
222    return tmp
223  }
224  if u.C == nil {
225    return nil
226  }
227  u.C = u.C.Simplify(rules)
228  if u.C == nil {
229    return nil
230  }
231  switch u.C.ExprType() {
232  case NULL, SIN, COS, TAN, CONSTANT:
233    ret = u.C
234    u.C = nil
235  case CONSTANTF:
236    ret = u.C
237    u.C = nil
238    ret.(*ConstantF).F = math.Tan(ret.(*ConstantF).F)
239  default: // no simplification
240    ret = u
241  }
242  return ret
243}
244
245func (u *Exp) Simplify(rules SimpRules) (ret Expr) {
246  if u.C == nil {
247    return nil
248  }
249  u.C = u.C.Simplify(rules)
250  if u.C == nil {
251    return nil
252  }
253  switch u.C.ExprType() {
254  case NULL, CONSTANT:
255    ret = u.C
256    u.C = nil
257  case CONSTANTF:
258    ret = u.C
259    u.C = nil
260    ret.(*ConstantF).F = math.Exp(ret.(*ConstantF).F)
261  default: // no simplification
262    ret = u
263  }
264  return ret
265}
266
267func (u *Log) Simplify(rules SimpRules) (ret Expr) {
268  if u.C == nil {
269    return nil
270  }
271  u.C = u.C.Simplify(rules)
272  if u.C == nil {
273    return nil
274  }
275  switch u.C.ExprType() {
276  case NULL, CONSTANT:
277    ret = u.C
278    u.C = nil
279  case CONSTANTF:
280    ret = u.C
281    u.C = nil
282    ret.(*ConstantF).F = math.Log(ret.(*ConstantF).F)
283  default: // no simplification
284    ret = u
285  }
286  return ret
287}
288
289func (u *PowI) Simplify(rules SimpRules) Expr {
290  var (
291    ret Expr     = u
292    t   ExprType = NULL
293  )
294  if u.Base != nil {
295    // serial := make([]int, 0, 64)
296    // serial = u.Base.Serial(serial)
297    // fmt.Printf("PowI-presort:  %v   %v\n", u.Base, serial)
298
299    u.Base = u.Base.Simplify(rules)
300    if u.Base == nil {
301      return nil
302    }
303
304    // serial2 := make([]int, 0, 64)
305    // serial2 = u.Base.Serial(serial2)
306    // fmt.Printf("PowI-postsort:  %v   %v\n", u.Base, serial2)
307    t = u.Base.ExprType()
308  }
309
310  if u.Power > rules.MaxPowPow {
311    u.Power = rules.MaxPowPow
312  } else if u.Power < -rules.MaxPowPow {
313    u.Power = -rules.MaxPowPow
314  }
315
316  if u.Power == 0 {
317    ret = &ConstantF{F: 1}
318  } else if u.Power == 1 {
319    ret = u.Base
320    u.Base = nil
321  } else {
322    switch t {
323    case NULL, CONSTANT:
324      ret = u.Base
325      u.Base = nil
326    case CONSTANTF:
327      ret = u.Base
328      u.Base = nil
329      ret.(*ConstantF).F = math.Pow(ret.(*ConstantF).F, float64(u.Power))
330    case MUL:
331      if u.Base.HasConst() {
332        m := u.Base.(*Mul)
333        mret := NewMul()
334        mret.Insert(m.CS[0])
335        m.CS[0] = nil
336        u.Base = m.Simplify(rules)
337        tmp := NewPowF(u.Base, float64(u.Power))
338        mret.Insert(tmp)
339        ret = mret
340      }
341    case POWI:
342      p := u.Base.(*PowI)
343      u.Base = p.Base
344      u.Power = u.Power * p.Power
345      if u.Power > rules.MaxPowPow {
346        u.Power = rules.MaxPowPow
347      } else if u.Power < -rules.MaxPowPow {
348        u.Power = -rules.MaxPowPow
349      }
350      // ret = NewPowF(u.Base, float64(u.Power))
351      ret = u
352    default: // no simplification
353      // ret = NewPowF(u.Base, float64(u.Power))
354      ret = u
355    }
356  }
357  // serial := make([]int, 0, 64)
358  // serial = ret.Serial(serial)
359  // fmt.Printf("PowI-ret:  %v  %v\n", ret, serial)
360  return ret
361}
362
363func (u *PowF) Simplify(rules SimpRules) Expr {
364  var (
365    ret Expr     = u
366    t   ExprType = NULL
367  )
368  if u.Base != nil {
369    u.Base = u.Base.Simplify(rules)
370    if u.Base == nil {
371      return nil
372    }
373    t = u.Base.ExprType()
374  }
375
376  if u.Power == 0 {
377    ret = &ConstantF{F: 1}
378  } else if u.Power == 1 {
379    ret = u.Base
380    u.Base = nil
381  } else {
382    switch t {
383    case NULL, CONSTANT:
384      ret = u.Base
385      u.Base = nil
386    case CONSTANTF:
387      ret = u.Base
388      u.Base = nil
389      ret.(*ConstantF).F = math.Pow(ret.(*ConstantF).F, float64(u.Power))
390    default: // no simplification
391      ret = NewPowI(u.Base, int(u.Power))
392    }
393  }
394  return ret
395}
396
397func (n *PowE) Simplify(rules SimpRules) Expr {
398  var (
399    ret    Expr     = n
400    t1, t2 ExprType = NULL, NULL
401  )
402  if n.Base != nil {
403    n.Base = n.Base.Simplify(rules)
404    t1 = n.Base.ExprType()
405  }
406  if n.Power != nil {
407    n.Power = n.Power.Simplify(rules)
408    t2 = n.Power.ExprType()
409  }
410  if t1 == NULL && t2 == NULL {
411    return &Null{}
412  } else if t1 == NULL {
413    ret = n.Power
414    n.Base = nil
415    n.Power = nil
416  } else if t2 == NULL {
417    ret = n.Base
418    n.Base = nil
419    n.Power = nil
420  } else if n.Base.ExprType() == n.Power.ExprType() &&
421    n.Base.ExprType() == CONSTANTF {
422    ret = n.Base
423    ret.(*ConstantF).F = math.Pow(ret.(*ConstantF).F, n.Power.(*ConstantF).F)
424    n.Base = nil
425    n.Power = nil
426  }
427  return ret
428}
429
430func (n *Div) Simplify(rules SimpRules) Expr {
431  var (
432    ret    Expr     = n
433    t1, t2 ExprType = NULL, NULL
434  )
435  if n.Numer != nil {
436    n.Numer = n.Numer.Simplify(rules)
437    if n.Numer != nil {
438      t1 = n.Numer.ExprType()
439    }
440  }
441  if n.Denom != nil {
442    n.Denom = n.Denom.Simplify(rules)
443    if n.Denom != nil {
444      t2 = n.Denom.ExprType()
445    }
446  }
447
448  // check to see if nulls/nils
449  if t1 == NULL && t2 == NULL {
450    ret = nil
451  } else if t1 == NULL {
452    ret = n.Denom
453    n.Numer = nil
454    n.Denom = nil
455    return ret
456  } else if t2 == NULL {
457    ret = n.Numer
458    n.Numer = nil
459    n.Denom = nil
460    return ret
461  }
462
463  // check to see if divs
464  if t1 == DIV && t2 == DIV {
465    //  a/b // c/d => ad/bc
466    ndiv := n.Numer.(*Div)
467    ddiv := n.Denom.(*Div)
468    nmul := NewMul()
469    nmul.Insert(ndiv.Numer)
470    nmul.Insert(ddiv.Denom)
471    dmul := NewMul()
472    dmul.Insert(ndiv.Denom)
473    dmul.Insert(ddiv.Numer)
474    ndiv.Numer = nil
475    ndiv.Denom = nil
476    ddiv.Numer = nil
477    ddiv.Denom = nil
478    n.Numer = nmul.Simplify(rules)
479    n.Denom = dmul.Simplify(rules)
480    t1 = n.Numer.ExprType()
481    t2 = n.Denom.ExprType()
482
483  } else if t1 == DIV {
484    //  a/b // c   => a/bc
485    div := n.Numer.(*Div)
486    n.Numer = div.Numer
487    mul := NewMul()
488    mul.Insert(div.Denom)
489    mul.Insert(n.Denom)
490    div.Numer = nil
491    div.Denom = nil
492    n.Denom = mul.Simplify(rules)
493    t1 = n.Numer.ExprType()
494    t2 = n.Denom.ExprType()
495
496  } else if t2 == DIV {
497    //  a // c/d   => ad/c
498    div := n.Denom.(*Div)
499    n.Denom = div.Numer
500    mul := NewMul()
501    mul.Insert(n.Numer)
502    mul.Insert(div.Denom)
503    div.Numer = nil
504    div.Denom = nil
505    n.Numer = mul.Simplify(rules)
506    t1 = n.Numer.ExprType()
507    t2 = n.Denom.ExprType()
508  }
509
510  // cancel / simp like terms
511  if t1 == t2 && t1 == CONSTANT {
512    ret = n.Numer
513    n.Numer = nil
514    n.Denom = nil
515    return ret
516  } else if t1 == CONSTANT && t2 == MUL {
517    d := n.Denom.(*Mul)
518    if d.CS[0].ExprType() == CONSTANT {
519      d.CS[0] = nil
520      n.Denom = d.Simplify(rules)
521    }
522    return ret
523  } else if t2 == CONSTANT && t1 == MUL {
524    d := n.Numer.(*Mul)
525    if d.CS[0].ExprType() != CONSTANT {
526      d.Insert(NewConstant(-1))
527    }
528    ret = n.Numer
529    n.Numer = nil
530    n.Denom = nil
531    return ret
532  } else if t1 == t2 && t1 == CONSTANTF {
533    c := n.Numer.(*ConstantF)
534    c.F /= n.Denom.(*ConstantF).F
535    ret = n.Numer
536    n.Numer = nil
537    n.Denom = nil
538    return ret
539  } else if t1 == CONSTANTF && t2 == MUL {
540    d := n.Denom.(*Mul)
541    if d.CS[0].ExprType() == CONSTANTF {
542      c := n.Numer.(*ConstantF)
543      c.F /= d.CS[0].(*ConstantF).F
544      d.CS[0] = nil
545      n.Denom = d.Simplify(rules)
546    }
547    return ret
548  } else if t2 == CONSTANTF && t1 == MUL {
549    d := n.Numer.(*Mul)
550    if d.CS[0].ExprType() != CONSTANTF {
551      c := NewConstantF(1.0)
552      c.F /= n.Denom.(*ConstantF).F
553      d.Insert(c)
554    } else {
555      c := d.CS[0].(*ConstantF)
556      c.F /= n.Denom.(*ConstantF).F
557    }
558    ret = n.Numer
559    n.Numer = nil
560    n.Denom = nil
561    return ret
562  } else {
563    ret = n.cancelLikeTerms(rules)
564  }
565
566  return ret
567}
568
569func (D *Div) cancelLikeTerms(rules SimpRules) Expr {
570
571  t1 := D.Numer.ExprType()
572  t2 := D.Denom.ExprType()
573  var ret Expr = D
574
575  // fmt.Println("cancel", t1, t2)
576
577  if D.Numer.AmISame(D.Denom) {
578    return NewConstantF(1.0)
579  }
580
581  changed := false
582  if t1 == t2 && t1 == MUL {
583    mn := D.Numer.(*Mul)
584    md := D.Denom.(*Mul)
585    for i, n := range mn.CS {
586      if n == nil {
587        continue
588      }
589      for j, d := range md.CS {
590        if d == nil {
591          continue
592        }
593        // fmt.Println("cancel", i, n.ExprType(), j, d.ExprType())
594
595        if n.AmISame(d) {
596          mn.CS[i] = nil
597          md.CS[j] = nil
598          changed = true
599          break
600        }
601        if n.ExprType() == POWI && d.ExprType() == POWI {
602          np, dp := n.(*PowI), d.(*PowI)
603          if np.Base.AmISame(dp.Base) {
604            if np.Power > dp.Power {
605              np.Power -= dp.Power
606              md.CS[j] = nil
607              changed = true
608              continue
609            } else if np.Power < dp.Power {
610              dp.Power -= np.Power
611              mn.CS[i] = nil
612              changed = true
613              break
614            } else { // same and should cancel
615              mn.CS[i] = nil
616              md.CS[j] = nil
617              changed = true
618              break
619            }
620          }
621        } else if n.ExprType() == POWI {
622          np := n.(*PowI)
623          if np.Base.AmISame(d) {
624            np.Power -= 1
625            md.CS[j] = nil
626            changed = true
627            continue
628          }
629        } else if d.ExprType() == POWI {
630          nd := d.(*PowI)
631          if nd.Base.AmISame(n) {
632            nd.Power -= 1
633            mn.CS[i] = nil
634            changed = true
635            break
636          }
637        }
638
639      }
640
641    }
642  } else if t1 == MUL {
643    if D.Numer.AmIAlmostSame(D.Denom) {
644      return NewConstantF(1.0)
645    }
646    mn := D.Numer.(*Mul)
647    d := D.Denom
648    for i, n := range mn.CS {
649      if n.AmISame(d) {
650        mn.CS[i] = nil
651        D.Denom = nil
652        changed = true
653        break
654      }
655      if n.ExprType() == POWI && d.ExprType() == POWI {
656        np, dp := n.(*PowI), d.(*PowI)
657        if np.Base.AmISame(dp.Base) {
658          if np.Power > dp.Power {
659            np.Power -= dp.Power
660            D.Denom = nil
661            changed = true
662            break
663          } else if np.Power < dp.Power {
664            dp.Power -= np.Power
665            mn.CS[i] = nil
666            changed = true
667            break
668          } else { // same and should cancel
669            // will we even get here?
670            mn.CS[i] = nil
671            D.Denom = nil
672            changed = true
673            break
674          }
675        }
676      } else if n.ExprType() == POWI {
677        np := n.(*PowI)
678        if np.Base.AmISame(d) {
679          np.Power -= 1
680          D.Denom = nil
681          changed = true
682          break
683        }
684      } else if d.ExprType() == POWI {
685        nd := d.(*PowI)
686        if nd.Base.AmISame(n) {
687          nd.Power -= 1
688          mn.CS[i] = nil
689          changed = true
690          break
691        }
692      }
693    }
694  } else if t2 == MUL {
695    if D.Denom.AmIAlmostSame(D.Numer) {
696      return NewConstantF(1.0)
697    }
698    n := D.Numer
699    md := D.Denom.(*Mul)
700    for i, d := range md.CS {
701      if n.AmISame(d) {
702        D.Numer = NewConstantF(1.0)
703        md.CS[i] = nil
704        changed = true
705        break
706      }
707      if n.ExprType() == POWI && d.ExprType() == POWI {
708        np, dp := n.(*PowI), d.(*PowI)
709        if np.Base.AmISame(dp.Base) {
710          if np.Power > dp.Power {
711            np.Power -= dp.Power
712            md.CS[i] = nil
713            changed = true
714            break
715          } else if np.Power < dp.Power {
716            dp.Power -= np.Power
717            D.Numer = NewConstantF(1.0)
718            changed = true
719            break
720          } else { // same and should cancel
721            // will we even get here?
722            D.Numer = nil
723            md.CS[i] = nil
724            changed = true
725            break
726          }
727        }
728      } else if n.ExprType() == POWI {
729        np := n.(*PowI)
730        if np.Base.AmISame(d) {
731          np.Power -= 1
732          md.CS[i] = nil
733          changed = true
734          break
735        }
736      } else if d.ExprType() == POWI {
737        nd := d.(*PowI)
738        if nd.Base.AmISame(n) {
739          nd.Power -= 1
740          D.Numer = NewConstantF(1.0)
741          changed = true
742          break
743        }
744      }
745    }
746  } else {
747    n, d := D.Numer, D.Denom
748    if n.AmISame(d) {
749      D.Numer = NewConstantF(1.0)
750      D.Denom = nil
751      changed = true
752    } else if n.ExprType() == POWI && d.ExprType() == POWI {
753      // fmt.Println("Got Here 1")
754      np, dp := n.(*PowI), d.(*PowI)
755      if np.Base.AmISame(dp.Base) {
756        if np.Power > dp.Power {
757          np.Power -= dp.Power
758          D.Denom = nil
759          changed = true
760        } else if np.Power < dp.Power {
761          dp.Power -= np.Power
762          D.Numer = NewConstantF(1.0)
763          changed = true
764        } else { // same and should cancel
765          // will we even get here?
766          D.Numer = NewConstantF(1.0)
767          D.Denom = nil
768          changed = true
769        }
770      }
771    } else if n.ExprType() == POWI {
772      // fmt.Println("Got Here 2")
773      np := n.(*PowI)
774      if np.Base.AmISame(d) {
775        np.Power -= 1
776        D.Denom = nil
777        changed = true
778      }
779    } else if d.ExprType() == POWI {
780      // fmt.Println("Got Here 3")
781      nd := d.(*PowI)
782      if nd.Base.AmISame(n) {
783        nd.Power -= 1
784        D.Numer = NewConstantF(1.0)
785        changed = true
786      }
787    }
788  }
789
790  if changed {
791    t1, t2 = NULL, NULL
792    if D.Numer != nil {
793      D.Numer = D.Numer.Simplify(rules)
794      if D.Numer != nil {
795        t1 = D.Numer.ExprType()
796      }
797    }
798    if D.Denom != nil {
799      D.Denom = D.Denom.Simplify(rules)
800      if D.Denom != nil {
801        t2 = D.Denom.ExprType()
802      }
803    }
804
805    // check to see if nulls/nils
806    if t1 == NULL && t2 == NULL {
807      ret = nil
808    } else if t1 == NULL {
809      D.Numer = NewConstantF(1.0)
810      ret = D
811      return ret
812    } else if t2 == NULL {
813      ret = D.Numer
814      D.Numer = nil
815      D.Denom = nil
816      return ret
817    }
818  }
819
820  return ret
821}
822
823func (n *Add) Simplify(rules SimpRules) Expr {
824  var ret Expr = n
825  hasSome := false
826  // fmt.Printf("n.CS = %v\n",n.CS)
827  for i, C := range n.CS {
828    if C != nil {
829      n.CS[i] = C.Simplify(rules)
830      if n.CS[i] == nil {
831        continue
832      }
833      if n.CS[i].ExprType() == NULL {
834        n.CS[i] = nil
835      } else {
836        hasSome = true
837      }
838    }
839  }
840
841  if !hasSome {
842    return nil
843  }
844
845  changed := true
846  for changed {
847    // fmt.Printf("iter = %v\n",n.CS)
848    // fmt.Printf("ADD:  %v\n", n)
849    changed = false
850    if rules.ConvertConsts {
851      changed = changed || gatherAddTerms(n)
852      // fmt.Printf("GTH:  %v\n", n)
853      changed = changed || groupAddTerms(n)
854      // fmt.Printf("GRP:  %v\n", n)
855    } else {
856      changed = changed || gatherAddTerms(n)
857      // fmt.Printf("GTH:  %v\n", n)
858      changed = changed || groupAddTermsF(n)
859      // fmt.Printf("GRP:  %v\n", n)
860    }
861    n.Sort()
862    // fmt.Printf("SRT:  %v\n", n)
863  }
864  // fmt.Printf("POST:  %v\n\n\n", n)
865
866  cnt := countTerms(n.CS)
867  if cnt == 0 {
868    ret = nil
869  }
870  if cnt == 1 {
871    ret = n.CS[0]
872    n.CS[0] = nil
873  }
874  // fmt.Printf("exit = %v\n",n.CS)
875
876  return ret
877}
878
879func (n *Mul) Simplify(rules SimpRules) Expr {
880
881  var ret Expr = n
882
883  changed := true
884  for changed {
885    for i, C := range n.CS {
886      if C != nil {
887        n.CS[i] = C.Simplify(rules)
888        if n.CS[i] == nil {
889          continue
890        }
891        if n.CS[i].ExprType() == NULL {
892          n.CS[i] = nil
893        }
894      }
895    }
896
897    // fmt.Printf("MUL:  %v\n", n)
898    changed = false
899    if rules.ConvertConsts {
900      changed = changed || gatherMulTerms(n)
901      // fmt.Printf("GTH:  %v\n", n)
902      changed = changed || groupMulTerms(n)
903      // fmt.Printf("GRP:  %v\n", n)
904    } else {
905      changed = changed || gatherMulTermsF(n)
906      // fmt.Printf("GTH:  %v\n", n)
907      changed = changed || groupMulTermsF(n)
908      // fmt.Printf("GRP:  %v\n", n)
909    }
910    n.Sort()
911    // fmt.Printf("SRT:  %v\n", n)
912  }
913  // fmt.Printf("POST:  %v\n\n\n", n)
914
915  cnt := countTerms(n.CS)
916  if cnt == 0 {
917    ret = nil
918  }
919  if cnt == 1 {
920    // fmt.Printf("ARRRRGGGGG   %v\n", n.CS)
921    ret = n.CS[0]
922    n.CS[0] = nil
923  }
924  return ret
925}
926
927func countTerms(terms []Expr) int {
928  cnt := 0
929  for _, e := range terms {
930    if e != nil {
931      cnt++
932    }
933  }
934  return cnt
935}
936
937// this function left aligns children terms ( ie move nils to end of terms[] )
938// and returns the number of children
939func leftAlignTerms(terms []Expr) int {
940  cnt, nilp := 0, -1
941  for i, e := range terms {
942    if e != nil {
943      // fmt.Printf( "TERMS(%d/%d): %v\n", i,nilp, terms )
944      cnt++
945      if nilp >= 0 {
946        terms[nilp], terms[i] = terms[i], nil
947        nilp++
948        // find next nil spot
949        for nilp < len(terms) {
950          if terms[nilp] == nil {
951            break
952          } else {
953            nilp++
954          }
955        }
956        if nilp >= len(terms) {
957          break
958        } // the outer loop
959      }
960    } else if nilp < 0 {
961      nilp = i
962    }
963  }
964  return cnt
965}
966
967// pulls recursive adds into the current add
968func gatherAddTerms(n *Add) (changed bool) {
969  terms := make([]Expr, 0)
970  // terms := n.CS
971  // fmt.Printf("n.CS: %v\n", n.CS[:])
972  for i, e := range n.CS {
973    if e == nil {
974      continue
975    }
976    if e.ExprType() == ADD {
977      // fmt.Printf("got here\n")
978      changed = true
979      a := e.(*Add)
980      for j, E := range a.CS {
981        if E == nil {
982          continue
983        }
984        terms = append(terms, E)
985        a.CS[j] = nil
986      }
987      // rem := leftAlignTerms(a.CS[:])
988      // if rem == 0 {
989      n.CS[i] = nil
990      // }
991      // leftAlignTerms(terms)
992    } else {
993      terms = append(terms, e)
994    }
995  }
996  // fmt.Printf("terms: %v\n", terms)
997  n.CS = terms
998  return changed
999}
1000
1001// pulls recursive muls into the current mul
1002func gatherMulTerms(n *Mul) (changed bool) {
1003  terms := make([]Expr, 0)
1004  hasCoeff := false
1005  var coeff *ConstantF = nil
1006  hasDiv := -1
1007  for i, e := range n.CS {
1008    if e == nil {
1009      continue
1010    }
1011    switch e.ExprType() {
1012
1013    case CONSTANT:
1014      if !hasCoeff {
1015        terms = append(terms, e)
1016        hasCoeff = true
1017      } else {
1018        changed = true
1019      }
1020
1021    case CONSTANTF:
1022      // changed = true
1023      if coeff == nil {
1024        // hasCoeff = true
1025        coeff = e.(*ConstantF)
1026        terms = append(terms, e)
1027        // terms = append(terms, NewConstant(-1))
1028      } else {
1029        coeff.F *= e.(*ConstantF).F
1030      }
1031      n.CS[i] = nil
1032
1033    case NEG:
1034      changed = true
1035      neg := e.(*Neg)
1036      if !hasCoeff {
1037        mul := NewMul()
1038        mul.Insert(NewConstantF(-1))
1039        mul.Insert(neg.C)
1040        neg.C = nil
1041        terms = append(terms, mul)
1042        hasCoeff = true
1043      } else {
1044        terms = append(terms, neg.C)
1045        neg.C = nil
1046      }
1047
1048    case DIV:
1049      if hasDiv == -1 {
1050        hasDiv = i // store the first div occurance
1051      }
1052      terms = append(terms, e)
1053    case MUL:
1054      changed = true
1055      a := e.(*Mul)
1056      leftAlignTerms(a.CS[:])
1057      for j, E := range a.CS {
1058        if E == nil {
1059          continue
1060        }
1061        if e.ExprType() == CONSTANT {
1062          if !hasCoeff {
1063            hasCoeff = true
1064            terms = append(terms, E)
1065          }
1066          a.CS[i] = nil
1067        } else {
1068          terms = append(terms, E)
1069          a.CS[j] = nil
1070        }
1071      }
1072      rem := leftAlignTerms(a.CS[:])
1073      if rem == 0 {
1074        n.CS[i] = nil
1075      }
1076      leftAlignTerms(terms)
1077
1078    default:
1079      terms = append(terms, e)
1080    }
1081  }
1082  n.CS = terms
1083
1084  if hasDiv > -1 && len(n.CS) > 1 {
1085    changed = true
1086    numer := NewMul()
1087    denom := NewMul()
1088    for i, e := range n.CS {
1089      if e == nil {
1090        continue
1091      }
1092      switch e.ExprType() {
1093      case DIV:
1094        d := e.(*Div)
1095        numer.Insert(d.Numer)
1096        denom.Insert(d.Denom)
1097      // case POWI:
1098      // case POWF:
1099      default:
1100        numer.Insert(e)
1101      }
1102      n.CS[i] = nil
1103    }
1104    n.Insert(NewDiv(numer, denom))
1105  }
1106  return changed
1107}
1108
1109// group like terms in an addition
1110func groupAddTerms(n *Add) (changed bool) {
1111  terms := n.CS
1112  for i, x := range terms {
1113    // fmt.Printf("TERMS:  %v\n", terms)
1114    if x == nil {
1115      continue
1116    }
1117    xT := x.ExprType()
1118    same := false
1119    for j := i + 1; j < len(terms); j++ {
1120      y := terms[j]
1121      // fmt.Printf("%d-%d  %v  %v\n", i, j, x, y)
1122      if y == nil {
1123        continue
1124      }
1125
1126      //  F(x) +  F(x)
1127      // cF(x) + dF(x)
1128      // cF(x) +  F(x)
1129      //  F(x) + cF(x)
1130      if x.AmIAlmostSame(y) || y.AmIAlmostSame(x) { // both directions ensures Mul.AmIAlmostSame()... with only one FAIL on F(x) + cF(x)
1131        same = true
1132        terms[j] = nil
1133      }
1134
1135      //  F(x) -  F(x)
1136      // cF(x) - dF(x)
1137      // cF(x) -  F(x)
1138      //  F(x) - cF(x)
1139      if xT == NEG {
1140        c := x.(*Neg).C
1141        if y.AmIAlmostSame(c) {
1142          same = true
1143          terms[j] = nil
1144        }
1145      }
1146      yT := y.ExprType()
1147      if yT == NEG {
1148        c := y.(*Neg).C
1149        if x.AmIAlmostSame(c) {
1150          same = true
1151          terms[j] = nil
1152        }
1153      }
1154
1155    }
1156    if same {
1157      changed = true
1158      // fmt.Printf("groupAddTerms: %v\n", terms)
1159      // extract x.C if neg
1160      if xT == NEG {
1161        x = x.(*Neg).C
1162        xT = x.ExprType()
1163      }
1164      if xT == MUL {
1165        mul := x.(*Mul)
1166        if !(mul.CS[0].ExprType() == CONSTANT) {
1167          mul.Insert(NewConstantF(1.0))
1168        }
1169      } else {
1170        mul := NewMul()
1171        mul.Insert(NewConstantF(1.0))
1172        mul.Insert(x)
1173        terms[i] = mul
1174      }
1175    }
1176
1177  }
1178  return
1179}
1180
1181// group like terms in a multiplication
1182func groupMulTerms(m *Mul) (changed bool) {
1183  terms := m.CS
1184  L := len(terms)
1185  hasConst := false
1186  var coeff *ConstantF = nil
1187
1188  for i, x := range terms {
1189    if x == nil {
1190      continue
1191    }
1192
1193    // setting up current term
1194    powSum := 1.0
1195
1196    xT := x.ExprType()
1197    if xT == CONSTANT && !hasConst {
1198      hasConst = true
1199    }
1200
1201    if xT == CONSTANTF {
1202      if coeff == nil {
1203        coeff = x.(*ConstantF)
1204      } else {
1205        coeff.F *= x.(*ConstantF).F
1206        terms[i] = nil
1207        continue
1208      }
1209    }
1210
1211    var xC Expr
1212    xTb := NULL
1213    switch xT {
1214    case NEG:
1215      xC = x.(*Neg).C
1216      xTb = xC.ExprType()
1217    case POWI:
1218      p := x.(*PowI)
1219      xC = p.Base
1220      xTb = p.Base.ExprType()
1221      powSum = float64(p.Power)
1222    case POWF:
1223      p := x.(*PowF)
1224      xC = p.Base
1225      xTb = p.Base.ExprType()
1226      powSum = p.Power
1227    case POWE:
1228      p := x.(*PowE)
1229      if p.Power.ExprType() == CONSTANTF {
1230        xC = p.Base
1231        xTb = p.Base.ExprType()
1232        powSum = p.Power.(*ConstantF).F
1233      }
1234    }
1235
1236    for j := i + 1; j < L; j++ {
1237      y := terms[j]
1238      if y == nil {
1239        continue
1240      }
1241
1242      // setting up following term(s)
1243      powY := 1.0
1244      yT := y.ExprType()
1245      if yT == CONSTANT && !hasConst {
1246        hasConst = true
1247      }
1248
1249      if yT == CONSTANTF {
1250        if coeff == nil {
1251          coeff = y.(*ConstantF)
1252        } else {
1253          coeff.F *= y.(*ConstantF).F
1254          terms[j] = nil
1255          continue
1256        }
1257      }
1258
1259      var yC Expr
1260      yTb := NULL
1261      switch yT {
1262      case NEG:
1263        yC = y.(*Neg).C
1264        yTb = yC.ExprType()
1265      case POWI:
1266        p := y.(*PowI)
1267        yC = p.Base
1268        yTb = p.Base.ExprType()
1269        powY = float64(p.Power)
1270      case POWF:
1271        p := y.(*PowF)
1272        yC = p.Base
1273        yTb = p.Base.ExprType()
1274        powY = p.Power
1275      case POWE:
1276        p := y.(*PowE)
1277        if p.Power.ExprType() == CONSTANTF {
1278          yC = p.Base
1279          yTb = p.Base.ExprType()
1280          powY = p.Power.(*ConstantF).F
1281        }
1282      }
1283
1284      // fmt.Println("Types: ", xT, xTb, yT, yTb)
1285
1286      // This is the actual comparison Code
1287      same := false
1288      if xT == yT {
1289        if x.AmISame(y) {
1290          same = true
1291          powSum += powY
1292        }
1293        if xTb == yTb && xTb != NULL {
1294          if xC.AmISame(yC) {
1295            same = true
1296            powSum += powY
1297          }
1298        }
1299      } else if xTb == yT {
1300        if xC.AmISame(y) {
1301          same = true
1302          powSum += powY
1303        }
1304      } else if xT == yTb {
1305        if x.AmISame(yC) {
1306          same = true
1307          powSum += powY
1308        }
1309      } else if xTb == yTb && xTb != NULL {
1310        if xC.AmISame(yC) {
1311          same = true
1312          powSum += powY
1313        }
1314      }
1315
1316      // Check the results of camparison update the terms
1317      if same {
1318        // fmt.Printf("GotHERE\n")
1319        terms[j] = nil
1320        changed = true
1321        if powSum == 0 {
1322          terms[i] = nil // remove the lhs term
1323        } else if powSum == 1 {
1324          // what is lhs?
1325          // if PowI || Neg || ? :: then extract Base
1326          if xTb != NULL {
1327            switch xT {
1328            case NEG:
1329              terms[i] = x.(*Neg).C
1330            case POWI:
1331              terms[i] = x.(*PowI).Base
1332            case POWF:
1333              terms[i] = x.(*PowF).Base
1334            }
1335          }
1336        } else {
1337          // whole or fractional power?
1338          flr := math.Floor(powSum)
1339          dim := math.Dim(powSum, flr)
1340          if dim == 0 {
1341            // whole power
1342            base := x
1343            if xT != POWI {
1344              if xTb != NULL {
1345                switch xT {
1346                case NEG:
1347                  base = x.(*Neg).C
1348                case POWF:
1349                  base = x.(*PowF).Base
1350                }
1351              }
1352              base = NewPowI(base, int(powSum))
1353            } else {
1354              base.(*PowI).Power = int(powSum)
1355            }
1356            terms[i] = base
1357          } else {
1358            // fractional power
1359            base := x
1360            if xT != POWF {
1361              if xTb != NULL {
1362                switch xT {
1363                case NEG:
1364                  base = x.(*Neg).C
1365                case POWI:
1366                  base = x.(*PowI).Base
1367                }
1368              }
1369              base = NewPowF(base, powSum)
1370            } else {
1371              base.(*PowF).Power = powSum
1372            }
1373          }
1374        }
1375      }
1376    }
1377
1378  }
1379  return
1380}
1381
1382// pulls recursive muls into the current mul
1383func gatherMulTermsF(n *Mul) (changed bool) {
1384  terms := make([]Expr, 0)
1385  hasCoeff := false
1386  var coeff *ConstantF = nil
1387  hasDiv := -1
1388  for i, e := range n.CS {
1389    if e == nil {
1390      continue
1391    }
1392    switch e.ExprType() {
1393
1394    case CONSTANT:
1395      if !hasCoeff {
1396        terms = append(terms, e)
1397        hasCoeff = true
1398      } else {
1399        changed = true
1400      }
1401
1402    case CONSTANTF:
1403      // changed = true
1404      if coeff == nil {
1405        // hasCoeff = true
1406        coeff = e.(*ConstantF)
1407        terms = append(terms, e)
1408        // terms = append(terms, NewConstant(-1))
1409      } else {
1410        coeff.F *= e.(*ConstantF).F
1411      }
1412      n.CS[i] = nil
1413
1414    case NEG:
1415      changed = true
1416      neg := e.(*Neg)
1417      if !hasCoeff {
1418        mul := NewMul()
1419        mul.Insert(NewConstantF(-1))
1420        mul.Insert(neg.C)
1421        neg.C = nil
1422        terms = append(terms, mul)
1423        hasCoeff = true
1424      } else {
1425        terms = append(terms, neg.C)
1426        neg.C = nil
1427      }
1428
1429    case DIV:
1430      if hasDiv == -1 {
1431        hasDiv = i // store the first div occurance
1432      }
1433      terms = append(terms, e)
1434    case MUL:
1435      changed = true
1436      a := e.(*Mul)
1437      leftAlignTerms(a.CS[:])
1438      for j, E := range a.CS {
1439        if E == nil {
1440          continue
1441        }
1442        if e.ExprType() == CONSTANT || e.ExprType() == CONSTANTF {
1443          if !hasCoeff {
1444            hasCoeff = true
1445            terms = append(terms, E)
1446          }
1447          a.CS[i] = nil
1448        } else {
1449          terms = append(terms, E)
1450          a.CS[j] = nil
1451        }
1452      }
1453      rem := leftAlignTerms(a.CS[:])
1454      if rem == 0 {
1455        n.CS[i] = nil
1456      }
1457      leftAlignTerms(terms)
1458
1459    default:
1460      terms = append(terms, e)
1461    }
1462  }
1463  n.CS = terms
1464
1465  if hasDiv > -1 && len(n.CS) > 1 {
1466    changed = true
1467    numer := NewMul()
1468    denom := NewMul()
1469    for i, e := range n.CS {
1470      if e == nil {
1471        continue
1472      }
1473      switch e.ExprType() {
1474      case DIV:
1475        d := e.(*Div)
1476        numer.Insert(d.Numer)
1477        denom.Insert(d.Denom)
1478      // case POWI:
1479      // case POWF:
1480      default:
1481        numer.Insert(e)
1482      }
1483      n.CS[i] = nil
1484    }
1485    n.Insert(NewDiv(numer, denom))
1486  }
1487  return changed
1488}
1489
1490// group like terms in an addition
1491func groupAddTermsF(n *Add) (changed bool) {
1492  terms := n.CS
1493  for i, x := range terms {
1494    // fmt.Printf("TERMS:  %v\n", terms)
1495    if x == nil {
1496      continue
1497    }
1498    xT := x.ExprType()
1499    same := false
1500    sum := 1.0
1501    if xT == MUL && x.(*Mul).CS[0].ExprType() == CONSTANTF {
1502      sum = x.(*Mul).CS[0].(*ConstantF).F
1503    } else if xT == NEG {
1504      sum = -1.0
1505    }
1506    for j := i + 1; j < len(terms); j++ {
1507      y := terms[j]
1508      // fmt.Printf("%d-%d  %v  %v\n", i, j, x, y)
1509      if y == nil {
1510        continue
1511      }
1512      yT := y.ExprType()
1513
1514      //  F(x) +  F(x)
1515      // cF(x) + dF(x)
1516      // cF(x) +  F(x)
1517      //  F(x) + cF(x)
1518      if x.AmIAlmostSame(y) || y.AmIAlmostSame(x) { // both directions ensures Mul.AmIAlmostSame()... with only one FAIL on F(x) + cF(x)
1519        if yT == MUL && y.(*Mul).CS[0].ExprType() == CONSTANTF {
1520          sum += y.(*Mul).CS[0].(*ConstantF).F
1521        } else {
1522          sum += 1.0
1523        }
1524        same = true
1525        terms[j] = nil
1526      }
1527
1528      //  F(x) -  F(x)
1529      // cF(x) - dF(x)
1530      // cF(x) -  F(x)
1531      //  F(x) - cF(x)
1532      if xT == NEG {
1533        // fmt.Printf("GOT HERE xT NEG\n")
1534        c := x.(*Neg).C
1535        if y.AmIAlmostSame(c) {
1536          // fmt.Printf("GOT HERE xT NEG y almostSame\n")
1537          if yT == MUL && y.(*Mul).CS[0].ExprType() == CONSTANTF {
1538            sum += y.(*Mul).CS[0].(*ConstantF).F
1539          } else {
1540            sum += 1.0
1541          }
1542          same = true
1543          terms[j] = nil
1544        }
1545      }
1546      if yT == NEG {
1547        c := y.(*Neg).C
1548        if x.AmIAlmostSame(c) {
1549          if c.ExprType() == MUL && c.(*Mul).CS[0].ExprType() == CONSTANTF {
1550            sum -= c.(*Mul).CS[0].(*ConstantF).F
1551          } else {
1552            sum -= 1.0
1553          }
1554          same = true
1555          terms[j] = nil
1556        }
1557      }
1558
1559    }
1560    if same {
1561      changed = true
1562      // fmt.Printf("sum = %v\n", sum)
1563      // fmt.Printf("groupAddTerms: %v\n", terms)
1564      if sum == 0.0 {
1565        terms[i] = NewConstantF(sum)
1566        continue
1567      } else if sum == 1.0 {
1568        if xT == NEG {
1569          terms[i] = x.(*Neg).C
1570        }
1571        continue
1572      } else if sum == -1.0 {
1573        if xT != NEG {
1574          terms[i] = NewNeg(x)
1575        }
1576        continue
1577      } else {
1578
1579        // extract x.C if neg
1580        if xT == NEG {
1581          // fmt.Printf("xT is NEG\n")
1582          x = x.(*Neg).C
1583          xT = x.ExprType()
1584        }
1585        if xT == MUL {
1586          // fmt.Printf("xT is MUL\n")
1587          mul := x.(*Mul)
1588          if !(mul.CS[0].ExprType() == CONSTANTF) {
1589            mul.Insert(NewConstantF(sum))
1590          } else {
1591            mul.CS[0].(*ConstantF).F = sum
1592          }
1593        } else {
1594          mul := NewMul()
1595          mul.Insert(NewConstantF(sum))
1596          mul.Insert(x)
1597          terms[i] = mul
1598        }
1599      }
1600    }
1601
1602  }
1603  return
1604}
1605
1606// group like terms in a multiplication
1607func groupMulTermsF(m *Mul) (changed bool) {
1608  terms := m.CS
1609  L := len(terms)
1610  hasConst := false
1611  var coeff *ConstantF = nil
1612
1613  for i, x := range terms {
1614    if x == nil {
1615      continue
1616    }
1617
1618    // setting up current term
1619    powSum := 1.0
1620
1621    xT := x.ExprType()
1622    if xT == CONSTANT && !hasConst {
1623      hasConst = true
1624    }
1625
1626    if xT == CONSTANTF {
1627      if coeff == nil {
1628        coeff = x.(*ConstantF)
1629      } else {
1630        coeff.F *= x.(*ConstantF).F
1631        terms[i] = nil
1632        continue
1633      }
1634    }
1635
1636    var xC Expr
1637    xTb := NULL
1638    switch xT {
1639    case NEG:
1640      xC = x.(*Neg).C
1641      xTb = xC.ExprType()
1642    case POWI:
1643      p := x.(*PowI)
1644      xC = p.Base
1645      xTb = p.Base.ExprType()
1646      powSum = float64(p.Power)
1647    case POWF:
1648      p := x.(*PowF)
1649      xC = p.Base
1650      xTb = p.Base.ExprType()
1651      powSum = p.Power
1652    }
1653
1654    for j := i + 1; j < L; j++ {
1655      y := terms[j]
1656      if y == nil {
1657        continue
1658      }
1659
1660      // setting up following term(s)
1661      powY := 1.0
1662      yT := y.ExprType()
1663      if yT == CONSTANT && !hasConst {
1664        hasConst = true
1665      }
1666
1667      if yT == CONSTANTF {
1668        if coeff == nil {
1669          coeff = y.(*ConstantF)
1670        } else {
1671          coeff.F *= y.(*ConstantF).F
1672          terms[j] = nil
1673          continue
1674        }
1675      }
1676
1677      var yC Expr
1678      yTb := NULL
1679      switch yT {
1680      case NEG:
1681        yC = y.(*Neg).C
1682        yTb = yC.ExprType()
1683      case POWI:
1684        p := y.(*PowI)
1685        yC = p.Base
1686        yTb = p.Base.ExprType()
1687        powY = float64(p.Power)
1688      case POWF:
1689        p := y.(*PowF)
1690        yC = p.Base
1691        yTb = p.Base.ExprType()
1692        powY = p.Power
1693      }
1694
1695      // This is the actual comparison Code
1696      same := false
1697      if xT == yT {
1698        if x.AmISame(y) {
1699          same = true
1700          powSum += powY
1701        }
1702      } else if xTb == yT {
1703        if xC.AmISame(y) {
1704          same = true
1705          powSum += powY
1706        }
1707      } else if xT == yTb {
1708        if x.AmISame(yC) {
1709          same = true
1710          powSum += powY
1711        }
1712      } else if xTb == yTb && xTb != NULL {
1713        if xC.AmISame(yC) {
1714          same = true
1715          powSum += powY
1716        }
1717      }
1718
1719      // Check the results of camparison update the terms
1720      if same {
1721        terms[j] = nil
1722        changed = true
1723        if powSum == 0 {
1724          terms[i] = nil // remove the lhs term
1725        } else if powSum == 1 {
1726          // what is lhs?
1727          // if PowI || Neg || ? :: then extract Base
1728          if xTb != NULL {
1729            switch xT {
1730            case NEG:
1731              terms[i] = x.(*Neg).C
1732            case POWI:
1733              terms[i] = x.(*PowI).Base
1734            case POWF:
1735              terms[i] = x.(*PowF).Base
1736            }
1737          }
1738        } else {
1739          // // whole or fractional power?
1740          // flr := math.Floor(powSum)
1741          // dim := math.Dim(powSum, flr)
1742          // if dim == 0 {
1743          //  // whole power
1744          //  base := x
1745          //  if xT != POWI {
1746          //    if xTb != NULL {
1747          //      switch xT {
1748          //      case NEG:
1749          //        base = x.(*Neg).C
1750          //      case POWF:
1751          //        base = x.(*PowF).Base
1752          //      }
1753          //    }
1754          //    base = NewPowI(base, int(powSum))
1755          //  } else {
1756          //    base.(*PowI).Power = int(powSum)
1757          //  }
1758          //  terms[i] = base
1759          // } else {
1760          // fractional power
1761          base := x
1762          if xT != POWF {
1763            if xTb != NULL {
1764              switch xT {
1765              case NEG:
1766                base = x.(*Neg).C
1767              case POWI:
1768                base = x.(*PowI).Base
1769              }
1770            }
1771            base = NewPowF(base, powSum)
1772          } else {
1773            base.(*PowF).Power = powSum
1774          }
1775          // }
1776        }
1777      }
1778    }
1779
1780  }
1781  return
1782}
Note: See TracBrowser for help on using the repository browser.