remove bogus debugging output
[PyX/mjg.git] / pyx / mathtree.py
blob7421664b1ae89858bb03a9440a9bcfb3402cdb09
1 #!/usr/bin/env python
2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2002 André Wobst <wobsta@users.sourceforge.net>
8 # This file is part of PyX (http://pyx.sourceforge.net/).
10 # PyX is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # PyX is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with PyX; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 import string, re, math
28 class ParseStr:
30 def __init__(self, StrToParse, Pos = 0):
31 self.StrToParse = StrToParse
32 self.Pos = Pos
34 def __repr__(self):
35 return "ParseStr('" + self.StrToParse + "', " + str(self.Pos) + ")"
37 def __str__(self, Indent = ""):
38 WhiteSpaces = ""
39 for i in range(self.Pos):
40 WhiteSpaces = WhiteSpaces + " "
41 return Indent + self.StrToParse + "\n" + Indent + WhiteSpaces + "^"
43 def NextNonWhiteSpace(self, i = None):
44 if i == None:
45 i = self.Pos
46 while self.StrToParse[i] in string.whitespace:
47 i = i + 1
48 return i
50 def MatchStr(self, Str):
51 try:
52 i = self.NextNonWhiteSpace()
53 if self.StrToParse[i: i + len(Str)] == Str:
54 self.Pos = i + len(Str)
55 return Str
56 except IndexError:
57 pass
59 def MatchStrParenthesis(self, Str):
60 try:
61 i = self.NextNonWhiteSpace()
62 if self.StrToParse[i: i + len(Str)] == Str:
63 i = i + len(Str)
64 i = self.NextNonWhiteSpace(i)
65 if self.StrToParse[i: i + 1] == "(":
66 self.Pos = i + 1
67 return Str
68 except IndexError:
69 pass
71 def MatchPattern(self, Pat):
72 try:
73 i = self.NextNonWhiteSpace()
74 Match = Pat.match(self.StrToParse[i:])
75 if Match:
76 self.Pos = i + Match.end()
77 return Match.group()
78 except IndexError:
79 pass
81 def AllDone(self):
82 try:
83 self.NextNonWhiteSpace()
84 except IndexError:
85 return 1
86 return 0
89 class ArgCountError(Exception): pass
90 class DerivativeError(Exception): pass
92 class MathTree:
94 def __init__(self, ArgCount, *Args):
95 self.ArgCount = ArgCount
96 self.Args = []
97 for arg in Args:
98 self.AddArg(arg)
100 def __repr__(self, depth = 0):
101 indent = ""
102 SingleIndent = " "
103 for i in range(depth):
104 indent = indent + SingleIndent
105 result = indent + self.__class__.__name__ + "(\n"
106 for SubTree in self.Args:
107 if isinstance(SubTree, MathTree):
108 result = result + SubTree.__repr__(depth + 1)
109 else:
110 result = result + indent + SingleIndent + repr(SubTree)
112 if SubTree != self.Args[-1]:
113 result = result + ",\n"
114 else:
115 result = result + ")"
116 return result
118 def AddArg(self, Arg, Last=0, NotLast=0):
119 if len(self.Args) == self.ArgCount:
120 raise ArgCountError
121 self.Args.append(Arg)
122 if NotLast and len(self.Args) == self.ArgCount:
123 raise ArgCountError
124 if Last and len(self.Args) != self.ArgCount:
125 raise ArgCountError
127 def DependOn(self, arg):
128 for Arg in self.Args:
129 if Arg.DependOn(arg):
130 return 1
131 return 0
133 def Derivative(self, arg):
134 if not self.DependOn(arg):
135 return MathTreeValConst(0.0)
136 return self.CalcDerivative(arg)
138 def VarList(self):
139 list = [ ]
140 for Arg in self.Args:
141 newlist = Arg.VarList()
142 for x in newlist:
143 if x not in list:
144 list.append(x)
145 return list
148 class MathTreeVal(MathTree):
150 def __init__(self, *args):
151 MathTree.__init__(self, 1, *args)
153 def __str__(self):
154 return str(self.Args[0])
157 ConstPattern = re.compile(r"-?\d*((\d\.?)|(\.?\d))\d*(E[+-]?\d+)?",
158 re.IGNORECASE)
160 class MathTreeValConst(MathTreeVal):
162 def InitByParser(self, arg):
163 Match = arg.MatchPattern(ConstPattern)
164 if Match:
165 self.AddArg(string.atof(Match))
166 return 1
168 def CalcDerivative(self, arg):
169 raise DerivativeError("expression doesn't depend on \"%s\"" % arg)
171 def Derivative(self, arg):
172 return MathTreeValConst(0.0)
174 def DependOn(self, arg):
175 return 0
177 def VarList(self):
178 return [ ]
180 def Calc(HIDDEN_self, **args):
181 return HIDDEN_self.Args[0]
184 VarPattern = re.compile(r"[a-z_][a-z0-9_]*", re.IGNORECASE)
185 MathConst = {"pi": math.pi, "e": math.e}
187 class MathTreeValVar(MathTreeVal):
189 def InitByParser(self, arg):
190 Match = arg.MatchPattern(VarPattern)
191 if Match:
192 self.AddArg(Match)
193 return 1
195 def CalcDerivative(self, arg):
196 if arg != self.Args[0]:
197 raise DerivativeError("expression doesn't depend on \"%s\"" % arg)
198 return MathTreeValConst(1.0)
200 def DependOn(self, arg):
201 if arg == self.Args[0]:
202 return 1
203 return 0
205 def VarList(self):
206 if self.Args[0] in MathConst.keys():
207 return []
208 return [self.Args[0]]
210 def Calc(HIDDEN_self, **args):
211 if HIDDEN_self.Args[0] in args.keys():
212 return float(args[HIDDEN_self.Args[0]])
213 return MathConst[HIDDEN_self.Args[0]]
216 class MathTreeFunc(MathTree):
218 def __init__(self, name, ArgCount, *args):
219 self.name = name
220 MathTree.__init__(self, ArgCount, *args)
222 def InitByParser(self, arg):
223 return arg.MatchStrParenthesis(self.name)
225 def __str__(self):
226 args = ""
227 for SubTree in self.Args:
228 args = args + str(SubTree)
229 if SubTree != self.Args[-1]:
230 args = args + ","
231 return self.name + "(" + args + ")"
234 class MathTreeFunc1(MathTreeFunc):
236 def __init__(self, name, *args):
237 MathTreeFunc.__init__(self, name, 1, *args)
240 class MathTreeFunc1Neg(MathTreeFunc1):
242 def __init__(self, *args):
243 MathTreeFunc1.__init__(self, "neg", *args)
245 def CalcDerivative(self, arg):
246 return MathTreeFunc1Neg(self.Args[0].CalcDerivative(arg))
248 def Calc(HIDDEN_self, **args):
249 return -HIDDEN_self.Args[0].Calc(**args)
252 class MathTreeFunc1Abs(MathTreeFunc1):
254 def __init__(self, *args):
255 MathTreeFunc1.__init__(self, "abs", *args)
257 def CalcDerivative(self, arg):
258 return MathTreeOpMul(
259 MathTreeFunc1Sgn(self.Args[0]),
260 self.Args[0].CalcDerivative(arg))
262 def Calc(HIDDEN_self, **args):
263 return abs(HIDDEN_self.Args[0].Calc(**args))
266 class MathTreeFunc1Sgn(MathTreeFunc1):
268 def __init__(self, *args):
269 MathTreeFunc1.__init__(self, "sgn", *args)
271 def CalcDerivative(self, arg):
272 return MathTreeValConst(0.0)
274 def Calc(HIDDEN_self, **args):
275 if HIDDEN_self.Args[0].Calc(**args) < 0:
276 return -1.0
277 return 1.0
280 class MathTreeFunc1Sqrt(MathTreeFunc1):
282 def __init__(self, *args):
283 MathTreeFunc1.__init__(self, "sqrt", *args)
285 def CalcDerivative(self, arg):
286 return MathTreeOpMul(
287 MathTreeOpDiv(
288 MathTreeValConst(0.5),
289 self),
290 self.Args[0].CalcDerivative(arg))
292 def Calc(HIDDEN_self, **args):
293 return math.sqrt(HIDDEN_self.Args[0].Calc(**args))
296 class MathTreeFunc1Exp(MathTreeFunc1):
298 def __init__(self, *args):
299 MathTreeFunc1.__init__(self, "exp", *args)
301 def CalcDerivative(self, arg):
302 return MathTreeOpMul(self, self.Args[0].CalcDerivative(arg))
304 def Calc(HIDDEN_self, **args):
305 return math.exp(HIDDEN_self.Args[0].Calc(**args))
308 class MathTreeFunc1Log(MathTreeFunc1):
310 def __init__(self, *args):
311 MathTreeFunc1.__init__(self, "log", *args)
313 def CalcDerivative(self, arg):
314 return MathTreeOpDiv(self.Args[0].CalcDerivative(arg), self.Args[0])
316 def Calc(HIDDEN_self, **args):
317 return math.log(HIDDEN_self.Args[0].Calc(**args))
320 class MathTreeFunc1Sin(MathTreeFunc1):
322 def __init__(self, *args):
323 MathTreeFunc1.__init__(self, "sin", *args)
325 def CalcDerivative(self, arg):
326 return MathTreeOpMul(
327 MathTreeFunc1Cos(self.Args[0]),
328 self.Args[0].CalcDerivative(arg))
330 def Calc(HIDDEN_self, **args):
331 return math.sin(HIDDEN_self.Args[0].Calc(**args))
334 class MathTreeFunc1Cos(MathTreeFunc1):
336 def __init__(self, *args):
337 MathTreeFunc1.__init__(self, "cos", *args)
339 def CalcDerivative(self, arg):
340 return MathTreeOpMul(
341 MathTreeFunc1Neg(MathTreeFunc1Sin(self.Args[0])),
342 self.Args[0].CalcDerivative(arg))
344 def Calc(HIDDEN_self, **args):
345 return math.cos(HIDDEN_self.Args[0].Calc(**args))
348 class MathTreeFunc1Tan(MathTreeFunc1):
350 def __init__(self, *args):
351 MathTreeFunc1.__init__(self, "tan", *args)
353 def CalcDerivative(self, arg):
354 return MathTreeOpDiv(
355 self.Args[0].CalcDerivative(arg),
356 MathTreeOpPow(
357 MathTreeFunc1Cos(self.Args[0]),
358 MathTreeValConst(2.0)))
360 def Calc(HIDDEN_self, **args):
361 return math.tan(HIDDEN_self.Args[0].Calc(**args))
364 class MathTreeFunc1ASin(MathTreeFunc1):
366 def __init__(self, *args):
367 MathTreeFunc1.__init__(self, "asin", *args)
369 def CalcDerivative(self, arg):
370 return MathTreeOpDiv(
371 self.Args[0].CalcDerivative(arg),
372 MathTreeFunc1Sqrt(
373 MathTreeOpSub(
374 MathTreeValConst(1.0),
375 MathTreeOpPow(
376 self.Args[0],
377 MathTreeValConst(2.0)))))
379 def Calc(HIDDEN_self, **args):
380 return math.asin(HIDDEN_self.Args[0].Calc(**args))
383 class MathTreeFunc1ACos(MathTreeFunc1):
385 def __init__(self, *args):
386 MathTreeFunc1.__init__(self, "acos", *args)
388 def CalcDerivate(self, arg):
389 return MathTreeOpDiv(
390 MathTreeFunc1Neg(self.Args[0].CalcDerivative(arg)),
391 MathTreeFunc1Sqrt(
392 MathTreeOpSub(
393 MathTreeValConst(1.0),
394 MathTreeOpPow(
395 self.Args[0],
396 MathTreeValConst(2.0)))))
398 def Calc(HIDDEN_self, **args):
399 return math.acos(HIDDEN_self.Args[0].Calc(**args))
402 class MathTreeFunc1ATan(MathTreeFunc1):
404 def __init__(self, *args):
405 MathTreeFunc1.__init__(self, "atan", *args)
407 def CalcDerivate(self, arg):
408 return MathTreeOpDiv(
409 self.Args[0].CalcDerivative(arg),
410 MathTreeOpAdd(
411 MathTreeValConst(1.0),
412 MathTreeOpPow(
413 self.Args[0],
414 MathTreeValConst(2.0))))
416 def Calc(HIDDEN_self, **args):
417 return math.atan(HIDDEN_self.Args[0].Calc(**args))
420 class MathTreeFunc1SinD(MathTreeFunc1):
422 def __init__(self, *args):
423 MathTreeFunc1.__init__(self, "sind", *args)
425 def CalcDerivative(self, arg):
426 return MathTreeOpMul(
427 MathTreeFunc1CosD(self.Args[0]),
428 MathTreeOpMul(
429 MathTreeValConst(math.pi/180.0),
430 self.Args[0].CalcDerivative(arg)))
432 def Calc(HIDDEN_self, **args):
433 return math.sin(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
436 class MathTreeFunc1CosD(MathTreeFunc1):
438 def __init__(self, *args):
439 MathTreeFunc1.__init__(self, "cosd", *args)
441 def CalcDerivative(self, arg):
442 return MathTreeOpMul(
443 MathTreeFunc1Neg(MathTreeFunc1Sin(self.Args[0])),
444 MathTreeOpMul(
445 MathTreeValConst(math.pi/180.0),
446 self.Args[0].CalcDerivative(arg)))
448 def Calc(HIDDEN_self, **args):
449 return math.cos(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
452 class MathTreeFunc1TanD(MathTreeFunc1):
454 def __init__(self, *args):
455 MathTreeFunc1.__init__(self, "tand", *args)
457 def CalcDerivative(self, arg):
458 return MathTreeOpDiv(
459 MathTreeOpMul(
460 MathTreeValConst(math.pi/180.0),
461 self.Args[0].CalcDerivative(arg)),
462 MathTreeOpPow(
463 MathTreeFunc1Cos(self.Args[0]),
464 MathTreeValConst(2.0)))
466 def Calc(HIDDEN_self, **args):
467 return math.tan(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
470 class MathTreeFunc1ASinD(MathTreeFunc1):
472 def __init__(self, *args):
473 MathTreeFunc1.__init__(self, "asind", *args)
475 def CalcDerivative(self, arg):
476 return MathTreeOpDiv(
477 MathTreeOpMul(
478 MathTreeValConst(180.0/math.pi),
479 self.Args[0].CalcDerivative(arg)),
480 MathTreeFunc1Sqrt(
481 MathTreeOpSub(
482 MathTreeValConst(1.0),
483 MathTreeOpPow(
484 self.Args[0],
485 MathTreeValConst(2.0)))))
487 def Calc(HIDDEN_self, **args):
488 return 180.0/math.pi*math.asin(HIDDEN_self.Args[0].Calc(**args))
491 class MathTreeFunc1ACosD(MathTreeFunc1):
493 def __init__(self, *args):
494 MathTreeFunc1.__init__(self, "acosd", *args)
496 def CalcDerivate(self, arg):
497 return MathTreeOpDiv(
498 MathTreeFunc1Neg(
499 MathTreeOpMul(
500 MathTreeValConst(180.0/math.pi),
501 self.Args[0].CalcDerivative(arg))),
502 MathTreeFunc1Sqrt(
503 MathTreeOpSub(
504 MathTreeValConst(1.0),
505 MathTreeOpPow(
506 self.Args[0],
507 MathTreeValConst(2.0)))))
509 def Calc(HIDDEN_self, **args):
510 return 180.0/math.pi*math.acos(HIDDEN_self.Args[0].Calc(**args))
513 class MathTreeFunc1ATanD(MathTreeFunc1):
515 def __init__(self, *args):
516 MathTreeFunc1.__init__(self, "atand", *args)
518 def CalcDerivate(self, arg):
519 return MathTreeOpDiv(
520 MathTreeOpMul(
521 MathTreeValConst(180.0/math.pi),
522 self.Args[0].CalcDerivative(arg)),
523 MathTreeOpAdd(
524 MathTreeValConst(1.0),
525 MathTreeOpPow(
526 self.Args[0],
527 MathTreeValConst(2.0))))
529 def Calc(HIDDEN_self, **args):
530 return 180.0/math.pi*math.atan(HIDDEN_self.Args[0].Calc(**args))
533 class MathTreeFunc2(MathTreeFunc):
535 def __init__(self, name, *args):
536 MathTreeFunc.__init__(self, name, 2, *args)
539 class MathTreeFunc2Norm(MathTreeFunc2):
541 def __init__(self, *args):
542 MathTreeFunc2.__init__(self, "norm", *args)
544 def CalcDerivative(self, arg):
545 if self.Args[0].DependOn(arg):
546 if self.Args[1].DependOn(arg):
547 return MathTreeOpDiv(
548 MathTreeOpAdd(
549 MathTreeOpMul(
550 self.Args[0],
551 self.Args[0].CalcDerivative(arg)),
552 MathTreeOpMul(
553 self.Args[1],
554 self.Args[1].CalcDerivative(arg))),
555 self)
556 else:
557 return MathTreeOpDiv(
558 MathTreeOpMul(
559 self.Args[0],
560 self.Args[0].CalcDerivative(arg)),
561 self)
562 else:
563 if self.Args[1].DependOn(arg):
564 return MathTreeOpDiv(
565 MathTreeOpMul(
566 self.Args[1],
567 self.Args[1].CalcDerivative(arg)),
568 self)
570 def Calc(HIDDEN_self, **args):
571 return math.sqrt(HIDDEN_self.Args[0].Calc(**args) ** 2 +
572 HIDDEN_self.Args[1].Calc(**args) ** 2)
575 FuncExternPattern = re.compile(r"([a-z_][a-z0-9_]*)\s*\(", re.IGNORECASE)
577 class MathTreeFuncExtern(MathTreeFunc):
579 def __init__(self, *args):
580 MathTreeFunc.__init__(self, None, -1, *args)
582 def InitByParser(self, arg):
583 Match = arg.MatchPattern(FuncExternPattern)
584 if Match:
585 self.name = Match[:-1].strip()
586 return self.name
588 def Calc(HIDDEN_self, **args):
589 return args[HIDDEN_self.name](*[arg.Calc(**args) for arg in HIDDEN_self.Args])
592 class MathTreeOp(MathTree):
594 def __init__(self, level, symbol, *args):
595 self.ParenthesisBarrier = 0
596 self.level = level
597 self.symbol = symbol
598 MathTree.__init__(self, 2, *args)
600 def __str__(self):
601 result = ""
602 if isinstance(self.Args[0], MathTreeOp) and\
603 self.level > self.Args[0].level:
604 result = result + "(" + str(self.Args[0]) + ")"
605 else:
606 result = result + str(self.Args[0])
607 result = result + self.symbol
608 if isinstance(self.Args[1], MathTreeOp) and\
609 self.level >= self.Args[1].level:
610 result = result + "(" + str(self.Args[1]) + ")"
611 else:
612 result = result + str(self.Args[1])
613 return result
615 def InitByParser(self, arg):
616 return arg.MatchStr(self.symbol)
619 class MathTreeOpAdd(MathTreeOp):
621 def __init__(self, *args):
622 MathTreeOp.__init__(self, 1, "+", *args)
624 def CalcDerivative(self, arg):
625 if self.Args[0].DependOn(arg):
626 if self.Args[1].DependOn(arg):
627 return MathTreeOpAdd(
628 self.Args[0].CalcDerivative(arg),
629 self.Args[1].CalcDerivative(arg))
630 else:
631 return self.Args[0].CalcDerivative(arg)
632 else:
633 if self.Args[1].DependOn(arg):
634 return self.Args[1].CalcDerivative(arg)
636 def Calc(HIDDEN_self, **args):
637 return HIDDEN_self.Args[0].Calc(**args) + HIDDEN_self.Args[1].Calc(**args)
640 class MathTreeOpSub(MathTreeOp):
642 def __init__(self, *args):
643 MathTreeOp.__init__(self, 1, "-", *args)
645 def CalcDerivative(self, arg):
646 if self.Args[0].DependOn(arg):
647 if self.Args[1].DependOn(arg):
648 return MathTreeOpSub(
649 self.Args[0].CalcDerivative(arg),
650 self.Args[1].CalcDerivative(arg))
651 else:
652 return self.Args[0].CalcDerivative(arg)
653 else:
654 if self.Args[1].DependOn(arg):
655 return MathTreeFunc1Neg(self.Args[1].CalcDerivative(arg))
657 def Calc(HIDDEN_self, **args):
658 return HIDDEN_self.Args[0].Calc(**args) - HIDDEN_self.Args[1].Calc(**args)
661 class MathTreeOpMul(MathTreeOp):
663 def __init__(self, *args):
664 MathTreeOp.__init__(self, 2, "*", *args)
666 def CalcDerivative(self, arg):
667 if self.Args[0].DependOn(arg):
668 if self.Args[1].DependOn(arg):
669 return MathTreeOpAdd(
670 MathTreeOpMul(
671 self.Args[0],
672 self.Args[1].CalcDerivative(arg)),
673 MathTreeOpMul(
674 self.Args[0].CalcDerivative(arg),
675 self.Args[1]))
676 else:
677 return MathTreeOpMul(
678 self.Args[0].CalcDerivative(arg),
679 self.Args[1])
680 else:
681 if self.Args[1].DependOn(arg):
682 return MathTreeOpMul(
683 self.Args[0],
684 self.Args[1].CalcDerivative(arg))
686 def Calc(HIDDEN_self, **args):
687 return HIDDEN_self.Args[0].Calc(**args) * HIDDEN_self.Args[1].Calc(**args)
690 class MathTreeOpDiv(MathTreeOp):
692 def __init__(self, *args):
693 MathTreeOp.__init__(self, 2, "/", *args)
695 def CalcDerivative(self, arg):
696 if self.Args[0].DependOn(arg):
697 if self.Args[1].DependOn(arg):
698 return MathTreeOpMul(
699 MathTreeOpSub(
700 MathTreeOpMul(
701 self.Args[0].CalcDerivative(arg),
702 self.Args[1]),
703 MathTreeOpMul(
704 self.Args[0],
705 self.Args[1].CalcDerivative(arg))),
706 MathTreeOpPow(
707 self.Args[1],
708 MathTreeValConst(-2.0)))
709 else:
710 return MathTreeOpDiv(
711 self.Args[0].CalcDerivative(arg),
712 self.Args[1])
713 else:
714 if self.Args[1].DependOn(arg):
715 return MathTreeOpMul(
716 MathTreeOpMul(
717 MathTreeFunc1Neg(self.Args[0]),
718 MathTreeOpPow(
719 self.Args[1],
720 MathTreeValConst(-2.0))),
721 self.Args[1].CalcDerivative(arg))
723 def Calc(HIDDEN_self, **args):
724 return HIDDEN_self.Args[0].Calc(**args) / HIDDEN_self.Args[1].Calc(**args)
727 class MathTreeOpPow(MathTreeOp):
729 def __init__(self, *args):
730 MathTreeOp.__init__(self, 3, "^", *args)
732 def InitByParser(self, arg):
733 pos = arg.MatchStr("^")
734 if pos:
735 return 1
736 else:
737 return arg.MatchStr("**")
739 def CalcDerivative(self, arg):
740 if self.Args[0].DependOn(arg):
741 if self.Args[1].DependOn(arg):
742 return MathTreeOpMul(
743 MathTreeOpPow(
744 self.Args[0],
745 self.Args[1]),
746 MathTreeOpAdd(
747 MathTreeOpMul(
748 MathTreeFunc1Log(self.Args[0]),
749 self.Args[1].CalcDerivative(arg)),
750 MathTreeOpMul(
751 self.Args[1],
752 MathTreeOpDiv(
753 self.Args[0].CalcDerivative(arg),
754 self.Args[0]))))
755 else:
756 return MathTreeOpMul(
757 self.Args[1],
758 MathTreeOpMul(
759 MathTreeOpPow(
760 self.Args[0],
761 MathTreeOpSub(
762 self.Args[1],
763 MathTreeValConst(1.0))),
764 self.Args[0].CalcDerivative(arg)))
765 else:
766 if self.Args[1].DependOn(arg):
767 return MathTreeOpMul(
768 MathTreeOpMul(
769 MathTreeOpPow(
770 self.Args[0],
771 self.Args[1]),
772 MathTreeFunc1Log(self.Args[0])),
773 self.Args[1].CalcDerivative(arg))
775 def Calc(HIDDEN_self, **args):
776 return HIDDEN_self.Args[0].Calc(**args) ** HIDDEN_self.Args[1].Calc(**args)
780 class UndefinedMathTreeParseError(Exception):
782 def __init__(self, ParseStr, MathTree):
783 self.ParseStr = ParseStr
784 self.MathTree = MathTree
786 def __str__(self):
787 return "\n" + str(self.ParseStr)
790 class RightParenthesisExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
791 class RightParenthesisFoundMathTreeParseError(UndefinedMathTreeParseError): pass
792 class CommaExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
793 class CommaFoundMathTreeParseError(UndefinedMathTreeParseError): pass
794 class OperatorExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
795 class OperandExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
798 DefaultMathTreeOps = (MathTreeOpPow, MathTreeOpDiv, MathTreeOpMul, MathTreeOpSub, MathTreeOpAdd)
799 DefaultMathTreeFuncs = (MathTreeFunc1Neg, MathTreeFunc1Abs, MathTreeFunc1Sgn, MathTreeFunc1Sqrt,
800 MathTreeFunc1Exp, MathTreeFunc1Log,
801 MathTreeFunc1Sin, MathTreeFunc1Cos, MathTreeFunc1Tan,
802 MathTreeFunc1ASin, MathTreeFunc1ACos, MathTreeFunc1ATan,
803 MathTreeFunc1SinD, MathTreeFunc1CosD, MathTreeFunc1TanD,
804 MathTreeFunc1ASinD, MathTreeFunc1ACosD, MathTreeFunc1ATanD,
805 MathTreeFunc2Norm)
807 DefaultMathTreeVals = (MathTreeValConst, MathTreeValVar)
809 class parser:
811 def __init__(self, MathTreeOps=DefaultMathTreeOps,
812 MathTreeFuncs=DefaultMathTreeFuncs,
813 MathTreeVals=DefaultMathTreeVals):
814 self.MathTreeOps = MathTreeOps
815 self.MathTreeFuncs = MathTreeFuncs
816 self.MathTreeVals = MathTreeVals
818 def parse(self, str):
819 return self.ParseMathTree(ParseStr(str))
821 def ParseMathTree(self, arg):
822 Tree = None
823 Match = arg.MatchPattern(re.compile(r"\s*-(?![0-9\.])"))
824 if Match:
825 Tree = MathTreeFunc1Neg()
826 while 1:
827 i = arg.MatchStr("(")
828 if i:
829 try:
830 self.ParseMathTree(arg)
831 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
832 except RightParenthesisFoundMathTreeParseError, e:
833 if isinstance(e.MathTree, MathTreeOp):
834 e.MathTree.ParenthesisBarrier = 1
835 if Tree is not None:
836 SubTree = Tree # XXX: four lines code dublication
837 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
838 SubTree = SubTree.Args[1]
839 SubTree.AddArg(e.MathTree)
840 else:
841 Tree = e.MathTree
842 else:
843 for FuncClass in self.MathTreeFuncs:
844 Func = FuncClass()
845 if Func.InitByParser(arg):
846 if Tree is not None:
847 SubTree = Tree # XXX: four lines code dublication
848 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
849 SubTree = SubTree.Args[1]
850 SubTree.AddArg(Func)
851 else:
852 Tree = Func
853 while 1:
854 try:
855 self.ParseMathTree(arg)
856 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
857 except CommaFoundMathTreeParseError, e:
858 try:
859 Func.AddArg(e.MathTree, NotLast=1)
860 except ArgCountError:
861 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
862 continue
863 except RightParenthesisFoundMathTreeParseError, e:
864 try:
865 Func.AddArg(e.MathTree, Last=1)
866 except ArgCountError:
867 raise CommaExpectedMathTreeParseError(arg, Tree)
868 break
869 break
870 else:
871 FuncExtern = MathTreeFuncExtern()
872 if FuncExtern.InitByParser(arg):
873 if Tree is not None:
874 SubTree = Tree # XXX: four lines code dublication
875 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
876 SubTree = SubTree.Args[1]
877 SubTree.AddArg(FuncExtern)
878 else:
879 Tree = FuncExtern
880 while 1:
881 try:
882 self.ParseMathTree(arg)
883 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
884 except CommaFoundMathTreeParseError, e:
885 FuncExtern.AddArg(e.MathTree)
886 continue
887 except RightParenthesisFoundMathTreeParseError, e:
888 FuncExtern.AddArg(e.MathTree)
889 break
890 else:
891 for ValClass in self.MathTreeVals:
892 Val = ValClass()
893 if Val.InitByParser(arg):
894 if Tree is not None:
895 SubTree = Tree # XXX: four lines code dublication
896 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
897 SubTree = SubTree.Args[1]
898 SubTree.AddArg(Val)
899 else:
900 Tree = Val
901 break
902 else:
903 raise OperandExpectedMathTreeParseError(arg, Tree)
904 if arg.AllDone():
905 return Tree
906 i = arg.MatchStr(")")
907 if i:
908 raise RightParenthesisFoundMathTreeParseError(arg, Tree)
909 i = arg.MatchStr(",")
910 if i:
911 raise CommaFoundMathTreeParseError(arg, Tree)
912 for OpClass in self.MathTreeOps:
913 Op = OpClass()
914 if Op.InitByParser(arg):
915 SubTree = Tree
916 SubTreeRoot = None
917 while isinstance(SubTree, MathTreeOp) and\
918 Op.level > SubTree.level and\
919 not SubTree.ParenthesisBarrier:
920 SubTreeRoot = SubTree
921 SubTree = SubTree.Args[1]
922 if SubTreeRoot:
923 Op.AddArg(SubTree)
924 SubTreeRoot.Args[1] = Op
925 else:
926 Op.AddArg(Tree)
927 Tree = Op
928 break
929 else:
930 raise OperatorExpectedMathTreeParseError(arg, Tree)