fix typo
[PyX/mjg.git] / pyx / mathtree.py
blobbda3ab333b6452cc46d8bea29ccbf1f8a5af3ead
1 #!/usr/bin/env python
2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002-2004 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2003-2004 Michael Schindler <m-schindler@users.sourceforge.net>
7 # Copyright (C) 2002-2004 André Wobst <wobsta@users.sourceforge.net>
9 # This file is part of PyX (http://pyx.sourceforge.net/).
11 # PyX is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # PyX is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with PyX; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 import string, re, math
28 __oldparser__ = 1
29 __newparser__ = 2
30 __useparser__ = __oldparser__
31 #__useparser__ = __newparser__
33 if __useparser__ == __newparser__:
34 import symbol, token
35 import parser as pythonparser
37 class ParseStr:
39 def __init__(self, StrToParse, Pos = 0):
40 self.StrToParse = StrToParse
41 self.Pos = Pos
43 def __repr__(self):
44 return "ParseStr('" + self.StrToParse + "', " + str(self.Pos) + ")"
46 def __str__(self, Indent = ""):
47 WhiteSpaces = ""
48 for i in range(self.Pos):
49 WhiteSpaces = WhiteSpaces + " "
50 return Indent + self.StrToParse + "\n" + Indent + WhiteSpaces + "^"
52 def NextNonWhiteSpace(self, i = None):
53 if i == None:
54 i = self.Pos
55 while self.StrToParse[i] in string.whitespace:
56 i = i + 1
57 return i
59 def MatchStr(self, Str):
60 try:
61 i = self.NextNonWhiteSpace()
62 if self.StrToParse[i: i + len(Str)] == Str:
63 self.Pos = i + len(Str)
64 return Str
65 except IndexError:
66 pass
68 def MatchStrParenthesis(self, Str):
69 try:
70 i = self.NextNonWhiteSpace()
71 if self.StrToParse[i: i + len(Str)] == Str:
72 i = i + len(Str)
73 i = self.NextNonWhiteSpace(i)
74 if self.StrToParse[i: i + 1] == "(":
75 self.Pos = i + 1
76 return Str
77 except IndexError:
78 pass
80 def MatchPattern(self, Pat):
81 try:
82 i = self.NextNonWhiteSpace()
83 Match = Pat.match(self.StrToParse[i:])
84 if Match:
85 self.Pos = i + Match.end()
86 return Match.group()
87 except IndexError:
88 pass
90 def AllDone(self):
91 try:
92 self.NextNonWhiteSpace()
93 except IndexError:
94 return 1
95 return 0
98 class ArgCountError(Exception): pass
99 class DerivativeError(Exception): pass
101 class MathTree:
103 def __init__(self, ArgCount, *Args):
104 self.ArgCount = ArgCount
105 self.Args = []
106 for arg in Args:
107 self.AddArg(arg)
109 def __repr__(self, depth = 0):
110 indent = ""
111 SingleIndent = " "
112 for i in range(depth):
113 indent = indent + SingleIndent
114 result = indent + self.__class__.__name__ + "(\n"
115 for SubTree in self.Args:
116 if isinstance(SubTree, MathTree):
117 result = result + SubTree.__repr__(depth + 1)
118 else:
119 result = result + indent + SingleIndent + repr(SubTree)
121 if SubTree != self.Args[-1]:
122 result = result + ",\n"
123 else:
124 result = result + ")"
125 return result
127 def AddArg(self, Arg, Last=0, NotLast=0):
128 if len(self.Args) == self.ArgCount:
129 raise ArgCountError
130 self.Args.append(Arg)
131 if NotLast and len(self.Args) == self.ArgCount:
132 raise ArgCountError
133 if Last and len(self.Args) != self.ArgCount:
134 raise ArgCountError
136 def DependOn(self, arg):
137 for Arg in self.Args:
138 if Arg.DependOn(arg):
139 return 1
140 return 0
142 def Derivative(self, arg):
143 if not self.DependOn(arg):
144 return MathTreeValConst(0.0)
145 return self.CalcDerivative(arg)
147 def VarList(self):
148 list = [ ]
149 for Arg in self.Args:
150 newlist = Arg.VarList()
151 for x in newlist:
152 if x not in list:
153 list.append(x)
154 return list
157 class MathTreeVal(MathTree):
159 def __init__(self, *args):
160 MathTree.__init__(self, 1, *args)
162 def __str__(self):
163 return str(self.Args[0])
166 ConstPattern = re.compile(r"-?\d*((\d\.?)|(\.?\d))\d*(E[+-]?\d+)?",
167 re.IGNORECASE)
169 class MathTreeValConst(MathTreeVal):
171 def InitByParser(self, arg):
172 Match = arg.MatchPattern(ConstPattern)
173 if Match:
174 self.AddArg(string.atof(Match))
175 return 1
177 def CalcDerivative(self, arg):
178 raise DerivativeError("expression doesn't depend on \"%s\"" % arg)
180 def Derivative(self, arg):
181 return MathTreeValConst(0.0)
183 def DependOn(self, arg):
184 return 0
186 def VarList(self):
187 return [ ]
189 def Calc(HIDDEN_self, **args):
190 return HIDDEN_self.Args[0]
193 VarPattern = re.compile(r"[a-z_][a-z0-9_]*", re.IGNORECASE)
194 MathConst = {"pi": math.pi, "e": math.e}
196 class MathTreeValVar(MathTreeVal):
198 def InitByParser(self, arg):
199 Match = arg.MatchPattern(VarPattern)
200 if Match:
201 self.AddArg(Match)
202 return 1
204 def CalcDerivative(self, arg):
205 if arg != self.Args[0]:
206 raise DerivativeError("expression doesn't depend on \"%s\"" % arg)
207 return MathTreeValConst(1.0)
209 def DependOn(self, arg):
210 if arg == self.Args[0]:
211 return 1
212 return 0
214 def VarList(self):
215 if self.Args[0] in MathConst.keys():
216 return []
217 return [self.Args[0]]
219 def Calc(HIDDEN_self, **args):
220 if HIDDEN_self.Args[0] in args.keys():
221 return float(args[HIDDEN_self.Args[0]])
222 return MathConst[HIDDEN_self.Args[0]]
225 class MathTreeFunc(MathTree):
227 def __init__(self, name, ArgCount, *args):
228 self.name = name
229 MathTree.__init__(self, ArgCount, *args)
231 def InitByParser(self, arg):
232 return arg.MatchStrParenthesis(self.name)
234 def __str__(self):
235 args = ""
236 for SubTree in self.Args:
237 args = args + str(SubTree)
238 if SubTree != self.Args[-1]:
239 args = args + ","
240 return self.name + "(" + args + ")"
243 class MathTreeFunc1(MathTreeFunc):
245 def __init__(self, name, *args):
246 MathTreeFunc.__init__(self, name, 1, *args)
249 class MathTreeFunc1Neg(MathTreeFunc1):
251 def __init__(self, *args):
252 MathTreeFunc1.__init__(self, "neg", *args)
254 def CalcDerivative(self, arg):
255 return MathTreeFunc1Neg(self.Args[0].CalcDerivative(arg))
257 def Calc(HIDDEN_self, **args):
258 return -HIDDEN_self.Args[0].Calc(**args)
261 class MathTreeFunc1Abs(MathTreeFunc1):
263 def __init__(self, *args):
264 MathTreeFunc1.__init__(self, "abs", *args)
266 def CalcDerivative(self, arg):
267 return MathTreeOpMul(
268 MathTreeFunc1Sgn(self.Args[0]),
269 self.Args[0].CalcDerivative(arg))
271 def Calc(HIDDEN_self, **args):
272 return abs(HIDDEN_self.Args[0].Calc(**args))
275 class MathTreeFunc1Sgn(MathTreeFunc1):
277 def __init__(self, *args):
278 MathTreeFunc1.__init__(self, "sgn", *args)
280 def CalcDerivative(self, arg):
281 return MathTreeValConst(0.0)
283 def Calc(HIDDEN_self, **args):
284 if HIDDEN_self.Args[0].Calc(**args) < 0:
285 return -1.0
286 return 1.0
289 class MathTreeFunc1Sqrt(MathTreeFunc1):
291 def __init__(self, *args):
292 MathTreeFunc1.__init__(self, "sqrt", *args)
294 def CalcDerivative(self, arg):
295 return MathTreeOpMul(
296 MathTreeOpDiv(
297 MathTreeValConst(0.5),
298 self),
299 self.Args[0].CalcDerivative(arg))
301 def Calc(HIDDEN_self, **args):
302 return math.sqrt(HIDDEN_self.Args[0].Calc(**args))
305 class MathTreeFunc1Exp(MathTreeFunc1):
307 def __init__(self, *args):
308 MathTreeFunc1.__init__(self, "exp", *args)
310 def CalcDerivative(self, arg):
311 return MathTreeOpMul(self, self.Args[0].CalcDerivative(arg))
313 def Calc(HIDDEN_self, **args):
314 return math.exp(HIDDEN_self.Args[0].Calc(**args))
317 class MathTreeFunc1Log(MathTreeFunc1):
319 def __init__(self, *args):
320 MathTreeFunc1.__init__(self, "log", *args)
322 def CalcDerivative(self, arg):
323 return MathTreeOpDiv(self.Args[0].CalcDerivative(arg), self.Args[0])
325 def Calc(HIDDEN_self, **args):
326 return math.log(HIDDEN_self.Args[0].Calc(**args))
329 class MathTreeFunc1Sin(MathTreeFunc1):
331 def __init__(self, *args):
332 MathTreeFunc1.__init__(self, "sin", *args)
334 def CalcDerivative(self, arg):
335 return MathTreeOpMul(
336 MathTreeFunc1Cos(self.Args[0]),
337 self.Args[0].CalcDerivative(arg))
339 def Calc(HIDDEN_self, **args):
340 return math.sin(HIDDEN_self.Args[0].Calc(**args))
343 class MathTreeFunc1Cos(MathTreeFunc1):
345 def __init__(self, *args):
346 MathTreeFunc1.__init__(self, "cos", *args)
348 def CalcDerivative(self, arg):
349 return MathTreeOpMul(
350 MathTreeFunc1Neg(MathTreeFunc1Sin(self.Args[0])),
351 self.Args[0].CalcDerivative(arg))
353 def Calc(HIDDEN_self, **args):
354 return math.cos(HIDDEN_self.Args[0].Calc(**args))
357 class MathTreeFunc1Tan(MathTreeFunc1):
359 def __init__(self, *args):
360 MathTreeFunc1.__init__(self, "tan", *args)
362 def CalcDerivative(self, arg):
363 return MathTreeOpDiv(
364 self.Args[0].CalcDerivative(arg),
365 MathTreeOpPow(
366 MathTreeFunc1Cos(self.Args[0]),
367 MathTreeValConst(2.0)))
369 def Calc(HIDDEN_self, **args):
370 return math.tan(HIDDEN_self.Args[0].Calc(**args))
373 class MathTreeFunc1ASin(MathTreeFunc1):
375 def __init__(self, *args):
376 MathTreeFunc1.__init__(self, "asin", *args)
378 def CalcDerivative(self, arg):
379 return MathTreeOpDiv(
380 self.Args[0].CalcDerivative(arg),
381 MathTreeFunc1Sqrt(
382 MathTreeOpSub(
383 MathTreeValConst(1.0),
384 MathTreeOpPow(
385 self.Args[0],
386 MathTreeValConst(2.0)))))
388 def Calc(HIDDEN_self, **args):
389 return math.asin(HIDDEN_self.Args[0].Calc(**args))
392 class MathTreeFunc1ACos(MathTreeFunc1):
394 def __init__(self, *args):
395 MathTreeFunc1.__init__(self, "acos", *args)
397 def CalcDerivate(self, arg):
398 return MathTreeOpDiv(
399 MathTreeFunc1Neg(self.Args[0].CalcDerivative(arg)),
400 MathTreeFunc1Sqrt(
401 MathTreeOpSub(
402 MathTreeValConst(1.0),
403 MathTreeOpPow(
404 self.Args[0],
405 MathTreeValConst(2.0)))))
407 def Calc(HIDDEN_self, **args):
408 return math.acos(HIDDEN_self.Args[0].Calc(**args))
411 class MathTreeFunc1ATan(MathTreeFunc1):
413 def __init__(self, *args):
414 MathTreeFunc1.__init__(self, "atan", *args)
416 def CalcDerivate(self, arg):
417 return MathTreeOpDiv(
418 self.Args[0].CalcDerivative(arg),
419 MathTreeOpAdd(
420 MathTreeValConst(1.0),
421 MathTreeOpPow(
422 self.Args[0],
423 MathTreeValConst(2.0))))
425 def Calc(HIDDEN_self, **args):
426 return math.atan(HIDDEN_self.Args[0].Calc(**args))
429 class MathTreeFunc1SinD(MathTreeFunc1):
431 def __init__(self, *args):
432 MathTreeFunc1.__init__(self, "sind", *args)
434 def CalcDerivative(self, arg):
435 return MathTreeOpMul(
436 MathTreeFunc1CosD(self.Args[0]),
437 MathTreeOpMul(
438 MathTreeValConst(math.pi/180.0),
439 self.Args[0].CalcDerivative(arg)))
441 def Calc(HIDDEN_self, **args):
442 return math.sin(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
445 class MathTreeFunc1CosD(MathTreeFunc1):
447 def __init__(self, *args):
448 MathTreeFunc1.__init__(self, "cosd", *args)
450 def CalcDerivative(self, arg):
451 return MathTreeOpMul(
452 MathTreeFunc1Neg(MathTreeFunc1Sin(self.Args[0])),
453 MathTreeOpMul(
454 MathTreeValConst(math.pi/180.0),
455 self.Args[0].CalcDerivative(arg)))
457 def Calc(HIDDEN_self, **args):
458 return math.cos(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
461 class MathTreeFunc1TanD(MathTreeFunc1):
463 def __init__(self, *args):
464 MathTreeFunc1.__init__(self, "tand", *args)
466 def CalcDerivative(self, arg):
467 return MathTreeOpDiv(
468 MathTreeOpMul(
469 MathTreeValConst(math.pi/180.0),
470 self.Args[0].CalcDerivative(arg)),
471 MathTreeOpPow(
472 MathTreeFunc1Cos(self.Args[0]),
473 MathTreeValConst(2.0)))
475 def Calc(HIDDEN_self, **args):
476 return math.tan(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
479 class MathTreeFunc1ASinD(MathTreeFunc1):
481 def __init__(self, *args):
482 MathTreeFunc1.__init__(self, "asind", *args)
484 def CalcDerivative(self, arg):
485 return MathTreeOpDiv(
486 MathTreeOpMul(
487 MathTreeValConst(180.0/math.pi),
488 self.Args[0].CalcDerivative(arg)),
489 MathTreeFunc1Sqrt(
490 MathTreeOpSub(
491 MathTreeValConst(1.0),
492 MathTreeOpPow(
493 self.Args[0],
494 MathTreeValConst(2.0)))))
496 def Calc(HIDDEN_self, **args):
497 return 180.0/math.pi*math.asin(HIDDEN_self.Args[0].Calc(**args))
500 class MathTreeFunc1ACosD(MathTreeFunc1):
502 def __init__(self, *args):
503 MathTreeFunc1.__init__(self, "acosd", *args)
505 def CalcDerivate(self, arg):
506 return MathTreeOpDiv(
507 MathTreeFunc1Neg(
508 MathTreeOpMul(
509 MathTreeValConst(180.0/math.pi),
510 self.Args[0].CalcDerivative(arg))),
511 MathTreeFunc1Sqrt(
512 MathTreeOpSub(
513 MathTreeValConst(1.0),
514 MathTreeOpPow(
515 self.Args[0],
516 MathTreeValConst(2.0)))))
518 def Calc(HIDDEN_self, **args):
519 return 180.0/math.pi*math.acos(HIDDEN_self.Args[0].Calc(**args))
522 class MathTreeFunc1ATanD(MathTreeFunc1):
524 def __init__(self, *args):
525 MathTreeFunc1.__init__(self, "atand", *args)
527 def CalcDerivate(self, arg):
528 return MathTreeOpDiv(
529 MathTreeOpMul(
530 MathTreeValConst(180.0/math.pi),
531 self.Args[0].CalcDerivative(arg)),
532 MathTreeOpAdd(
533 MathTreeValConst(1.0),
534 MathTreeOpPow(
535 self.Args[0],
536 MathTreeValConst(2.0))))
538 def Calc(HIDDEN_self, **args):
539 return 180.0/math.pi*math.atan(HIDDEN_self.Args[0].Calc(**args))
542 class MathTreeFunc2(MathTreeFunc):
544 def __init__(self, name, *args):
545 MathTreeFunc.__init__(self, name, 2, *args)
548 class MathTreeFunc2Norm(MathTreeFunc2):
550 def __init__(self, *args):
551 MathTreeFunc2.__init__(self, "norm", *args)
553 def CalcDerivative(self, arg):
554 if self.Args[0].DependOn(arg):
555 if self.Args[1].DependOn(arg):
556 return MathTreeOpDiv(
557 MathTreeOpAdd(
558 MathTreeOpMul(
559 self.Args[0],
560 self.Args[0].CalcDerivative(arg)),
561 MathTreeOpMul(
562 self.Args[1],
563 self.Args[1].CalcDerivative(arg))),
564 self)
565 else:
566 return MathTreeOpDiv(
567 MathTreeOpMul(
568 self.Args[0],
569 self.Args[0].CalcDerivative(arg)),
570 self)
571 else:
572 if self.Args[1].DependOn(arg):
573 return MathTreeOpDiv(
574 MathTreeOpMul(
575 self.Args[1],
576 self.Args[1].CalcDerivative(arg)),
577 self)
579 def Calc(HIDDEN_self, **args):
580 return math.sqrt(HIDDEN_self.Args[0].Calc(**args) ** 2 +
581 HIDDEN_self.Args[1].Calc(**args) ** 2)
584 FuncExternPattern = re.compile(r"([a-z_][a-z0-9_]*)\s*\(", re.IGNORECASE)
586 class MathTreeFuncExtern(MathTreeFunc):
588 def __init__(self, *args):
589 MathTreeFunc.__init__(self, None, -1, *args)
591 def InitByParser(self, arg):
592 Match = arg.MatchPattern(FuncExternPattern)
593 if Match:
594 self.name = Match[:-1].strip()
595 return self.name
597 def SetName(self, arg):
598 self.name = arg.strip()
599 return self
601 def Calc(HIDDEN_self, **args):
602 return args[HIDDEN_self.name](*[arg.Calc(**args) for arg in HIDDEN_self.Args])
605 class MathTreeOp(MathTree):
607 def __init__(self, level, symbol, *args):
608 self.ParenthesisBarrier = 0
609 self.level = level
610 self.symbol = symbol
611 MathTree.__init__(self, 2, *args)
613 def __str__(self):
614 result = ""
615 if isinstance(self.Args[0], MathTreeOp) and\
616 self.level > self.Args[0].level:
617 result = result + "(" + str(self.Args[0]) + ")"
618 else:
619 result = result + str(self.Args[0])
620 result = result + self.symbol
621 if isinstance(self.Args[1], MathTreeOp) and\
622 self.level >= self.Args[1].level:
623 result = result + "(" + str(self.Args[1]) + ")"
624 else:
625 result = result + str(self.Args[1])
626 return result
628 def InitByParser(self, arg):
629 return arg.MatchStr(self.symbol)
632 class MathTreeOpAdd(MathTreeOp):
634 def __init__(self, *args):
635 MathTreeOp.__init__(self, 1, "+", *args)
637 def CalcDerivative(self, arg):
638 if self.Args[0].DependOn(arg):
639 if self.Args[1].DependOn(arg):
640 return MathTreeOpAdd(
641 self.Args[0].CalcDerivative(arg),
642 self.Args[1].CalcDerivative(arg))
643 else:
644 return self.Args[0].CalcDerivative(arg)
645 else:
646 if self.Args[1].DependOn(arg):
647 return self.Args[1].CalcDerivative(arg)
649 def Calc(HIDDEN_self, **args):
650 return HIDDEN_self.Args[0].Calc(**args) + HIDDEN_self.Args[1].Calc(**args)
653 class MathTreeOpSub(MathTreeOp):
655 def __init__(self, *args):
656 MathTreeOp.__init__(self, 1, "-", *args)
658 def CalcDerivative(self, arg):
659 if self.Args[0].DependOn(arg):
660 if self.Args[1].DependOn(arg):
661 return MathTreeOpSub(
662 self.Args[0].CalcDerivative(arg),
663 self.Args[1].CalcDerivative(arg))
664 else:
665 return self.Args[0].CalcDerivative(arg)
666 else:
667 if self.Args[1].DependOn(arg):
668 return MathTreeFunc1Neg(self.Args[1].CalcDerivative(arg))
670 def Calc(HIDDEN_self, **args):
671 return HIDDEN_self.Args[0].Calc(**args) - HIDDEN_self.Args[1].Calc(**args)
674 class MathTreeOpMul(MathTreeOp):
676 def __init__(self, *args):
677 MathTreeOp.__init__(self, 2, "*", *args)
679 def CalcDerivative(self, arg):
680 if self.Args[0].DependOn(arg):
681 if self.Args[1].DependOn(arg):
682 return MathTreeOpAdd(
683 MathTreeOpMul(
684 self.Args[0],
685 self.Args[1].CalcDerivative(arg)),
686 MathTreeOpMul(
687 self.Args[0].CalcDerivative(arg),
688 self.Args[1]))
689 else:
690 return MathTreeOpMul(
691 self.Args[0].CalcDerivative(arg),
692 self.Args[1])
693 else:
694 if self.Args[1].DependOn(arg):
695 return MathTreeOpMul(
696 self.Args[0],
697 self.Args[1].CalcDerivative(arg))
699 def Calc(HIDDEN_self, **args):
700 return HIDDEN_self.Args[0].Calc(**args) * HIDDEN_self.Args[1].Calc(**args)
703 class MathTreeOpDiv(MathTreeOp):
705 def __init__(self, *args):
706 MathTreeOp.__init__(self, 2, "/", *args)
708 def CalcDerivative(self, arg):
709 if self.Args[0].DependOn(arg):
710 if self.Args[1].DependOn(arg):
711 return MathTreeOpMul(
712 MathTreeOpSub(
713 MathTreeOpMul(
714 self.Args[0].CalcDerivative(arg),
715 self.Args[1]),
716 MathTreeOpMul(
717 self.Args[0],
718 self.Args[1].CalcDerivative(arg))),
719 MathTreeOpPow(
720 self.Args[1],
721 MathTreeValConst(-2.0)))
722 else:
723 return MathTreeOpDiv(
724 self.Args[0].CalcDerivative(arg),
725 self.Args[1])
726 else:
727 if self.Args[1].DependOn(arg):
728 return MathTreeOpMul(
729 MathTreeOpMul(
730 MathTreeFunc1Neg(self.Args[0]),
731 MathTreeOpPow(
732 self.Args[1],
733 MathTreeValConst(-2.0))),
734 self.Args[1].CalcDerivative(arg))
736 def Calc(HIDDEN_self, **args):
737 return HIDDEN_self.Args[0].Calc(**args) / HIDDEN_self.Args[1].Calc(**args)
740 class MathTreeOpPow(MathTreeOp):
742 def __init__(self, *args):
743 MathTreeOp.__init__(self, 3, "^", *args)
745 def InitByParser(self, arg):
746 pos = arg.MatchStr("^")
747 if pos:
748 return 1
749 else:
750 return arg.MatchStr("**")
752 def CalcDerivative(self, arg):
753 if self.Args[0].DependOn(arg):
754 if self.Args[1].DependOn(arg):
755 return MathTreeOpMul(
756 MathTreeOpPow(
757 self.Args[0],
758 self.Args[1]),
759 MathTreeOpAdd(
760 MathTreeOpMul(
761 MathTreeFunc1Log(self.Args[0]),
762 self.Args[1].CalcDerivative(arg)),
763 MathTreeOpMul(
764 self.Args[1],
765 MathTreeOpDiv(
766 self.Args[0].CalcDerivative(arg),
767 self.Args[0]))))
768 else:
769 return MathTreeOpMul(
770 self.Args[1],
771 MathTreeOpMul(
772 MathTreeOpPow(
773 self.Args[0],
774 MathTreeOpSub(
775 self.Args[1],
776 MathTreeValConst(1.0))),
777 self.Args[0].CalcDerivative(arg)))
778 else:
779 if self.Args[1].DependOn(arg):
780 return MathTreeOpMul(
781 MathTreeOpMul(
782 MathTreeOpPow(
783 self.Args[0],
784 self.Args[1]),
785 MathTreeFunc1Log(self.Args[0])),
786 self.Args[1].CalcDerivative(arg))
788 def Calc(HIDDEN_self, **args):
789 return HIDDEN_self.Args[0].Calc(**args) ** HIDDEN_self.Args[1].Calc(**args)
793 class UndefinedMathTreeParseError(Exception):
795 def __init__(self, ParseStr, MathTree):
796 self.ParseStr = ParseStr
797 self.MathTree = MathTree
799 def __str__(self):
800 return "\n" + str(self.ParseStr)
803 class RightParenthesisExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
804 class RightParenthesisFoundMathTreeParseError(UndefinedMathTreeParseError): pass
805 class CommaExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
806 class CommaFoundMathTreeParseError(UndefinedMathTreeParseError): pass
807 class OperatorExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
808 class OperandExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
811 DefaultMathTreeOps = (MathTreeOpPow, MathTreeOpDiv, MathTreeOpMul, MathTreeOpSub, MathTreeOpAdd)
812 DefaultMathTreeFuncs = (MathTreeFunc1Neg, MathTreeFunc1Abs, MathTreeFunc1Sgn, MathTreeFunc1Sqrt,
813 MathTreeFunc1Exp, MathTreeFunc1Log,
814 MathTreeFunc1Sin, MathTreeFunc1Cos, MathTreeFunc1Tan,
815 MathTreeFunc1ASin, MathTreeFunc1ACos, MathTreeFunc1ATan,
816 MathTreeFunc1SinD, MathTreeFunc1CosD, MathTreeFunc1TanD,
817 MathTreeFunc1ASinD, MathTreeFunc1ACosD, MathTreeFunc1ATanD,
818 MathTreeFunc2Norm)
820 DefaultMathTreeVals = (MathTreeValConst, MathTreeValVar)
822 class parser:
824 def __init__(self, MathTreeOps=DefaultMathTreeOps,
825 MathTreeFuncs=DefaultMathTreeFuncs,
826 MathTreeVals=DefaultMathTreeVals):
827 self.MathTreeOps = MathTreeOps
828 self.MathTreeFuncs = MathTreeFuncs
829 self.MathTreeVals = MathTreeVals
830 self.isnewparser = 0
832 def parse(self, str):
833 if __useparser__ == __oldparser__:
834 return self.old_parse(str)
835 elif __useparser__ == __newparser__:
836 return self.new_parse(str)
837 else:
838 RuntimeError("invalid __useparser__")
840 def old_parse(self, str):
841 return self.ParseMathTree(ParseStr(str))
843 def new_parse(self, str):
844 # prepare raw string:
845 # "^" -> "**"
846 thestr = re.sub("^\s*", "", str)
847 thestr = re.sub("\^","**", thestr) # to be removed <joergl>
848 thestr = re.sub("\$","_col_", thestr)
849 return self.astseq2mtree(pythonparser.expr(thestr).totuple())
851 def ParseMathTree(self, arg):
852 Tree = None
853 #Match = arg.MatchPattern(re.compile(r"\s*-(?![0-9\.])"))
854 Match = arg.MatchPattern(re.compile(r"\s*-")) # XXX another quick workaround
855 if Match:
856 #Tree = MathTreeFunc1Neg()
857 Tree = MathTreeOpSub(MathTreeValConst(0)) # XXX quick workaround
858 while 1:
859 i = arg.MatchStr("(")
860 if i:
861 try:
862 self.ParseMathTree(arg)
863 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
864 except RightParenthesisFoundMathTreeParseError, e:
865 if isinstance(e.MathTree, MathTreeOp):
866 e.MathTree.ParenthesisBarrier = 1
867 if Tree is not None:
868 SubTree = Tree # XXX: four lines code dublication
869 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
870 SubTree = SubTree.Args[1]
871 SubTree.AddArg(e.MathTree)
872 else:
873 Tree = e.MathTree
874 else:
875 for FuncClass in self.MathTreeFuncs:
876 Func = FuncClass()
877 if Func.InitByParser(arg):
878 if Tree is not None:
879 SubTree = Tree # XXX: four lines code dublication
880 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
881 SubTree = SubTree.Args[1]
882 SubTree.AddArg(Func)
883 else:
884 Tree = Func
885 while 1:
886 try:
887 self.ParseMathTree(arg)
888 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
889 except CommaFoundMathTreeParseError, e:
890 try:
891 Func.AddArg(e.MathTree, NotLast=1)
892 except ArgCountError:
893 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
894 continue
895 except RightParenthesisFoundMathTreeParseError, e:
896 try:
897 Func.AddArg(e.MathTree, Last=1)
898 except ArgCountError:
899 raise CommaExpectedMathTreeParseError(arg, Tree)
900 break
901 break
902 else:
903 FuncExtern = MathTreeFuncExtern()
904 if FuncExtern.InitByParser(arg):
905 if Tree is not None:
906 SubTree = Tree # XXX: four lines code dublication
907 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
908 SubTree = SubTree.Args[1]
909 SubTree.AddArg(FuncExtern)
910 else:
911 Tree = FuncExtern
912 while 1:
913 try:
914 self.ParseMathTree(arg)
915 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
916 except CommaFoundMathTreeParseError, e:
917 FuncExtern.AddArg(e.MathTree)
918 continue
919 except RightParenthesisFoundMathTreeParseError, e:
920 FuncExtern.AddArg(e.MathTree)
921 break
922 else:
923 for ValClass in self.MathTreeVals:
924 Val = ValClass()
925 if Val.InitByParser(arg):
926 if Tree is not None:
927 SubTree = Tree # XXX: four lines code dublication
928 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
929 SubTree = SubTree.Args[1]
930 SubTree.AddArg(Val)
931 else:
932 Tree = Val
933 break
934 else:
935 raise OperandExpectedMathTreeParseError(arg, Tree)
936 if arg.AllDone():
937 return Tree
938 i = arg.MatchStr(")")
939 if i:
940 raise RightParenthesisFoundMathTreeParseError(arg, Tree)
941 i = arg.MatchStr(",")
942 if i:
943 raise CommaFoundMathTreeParseError(arg, Tree)
944 for OpClass in self.MathTreeOps:
945 Op = OpClass()
946 if Op.InitByParser(arg):
947 SubTree = Tree
948 SubTreeRoot = None
949 while isinstance(SubTree, MathTreeOp) and\
950 Op.level > SubTree.level and\
951 not SubTree.ParenthesisBarrier:
952 SubTreeRoot = SubTree
953 SubTree = SubTree.Args[1]
954 if SubTreeRoot:
955 Op.AddArg(SubTree)
956 SubTreeRoot.Args[1] = Op
957 else:
958 Op.AddArg(Tree)
959 Tree = Op
960 break
961 else:
962 raise OperatorExpectedMathTreeParseError(arg, Tree)
965 def astseq2mtree(self, astseq, isfunc=0):
966 # astseq has to be a sequence!
967 tree = None
969 if token.ISTERMINAL(astseq[0]):
970 raise Exception("")
972 if astseq[0] == symbol.arith_expr: # {{{
973 try:
974 # 1. arith_expr "PLUS" term
975 if astseq[-2][0] == token.PLUS:
976 tree = MathTreeOpAdd(
977 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
978 self.astseq2mtree(astseq[-1], isfunc=isfunc))
979 # 2. arith_expr "MINUS" term
980 elif astseq[-2][0] == token.MINUS:
981 tree = MathTreeOpSub(
982 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
983 self.astseq2mtree(astseq[-1], isfunc=isfunc))
984 else:
985 raise Exception("")
986 except:
987 # 3. term
988 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
989 return tree # }}}
991 if astseq[0] == symbol.term: # {{{
992 try:
993 # 1. term "STAR" factor
994 if astseq[-2][0] == token.STAR:
995 tree = MathTreeOpMul(
996 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
997 self.astseq2mtree(astseq[-1], isfunc=isfunc))
998 # 2. term "SLASH" factor
999 elif astseq[-2][0] == token.SLASH:
1000 tree = MathTreeOpDiv(
1001 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
1002 self.astseq2mtree(astseq[-1], isfunc=isfunc))
1003 else:
1004 raise Exception("")
1005 except:
1006 # 3. factor
1007 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
1008 return tree # }}}
1010 if astseq[0] == symbol.factor: # {{{
1011 if len(astseq) == 3:
1012 # 1. "PLUS" factor
1013 if astseq[1][0] == token.PLUS:
1014 tree = self.astseq2mtree(astseq[2], isfunc=isfunc)
1015 # 2. "MINUS" factor
1016 elif astseq[1][0] == token.MINUS:
1017 tree = MathTreeFunc1Neg(self.astseq2mtree(astseq[2], isfunc=isfunc))
1018 else:
1019 raise Exception("unknown factor")
1020 elif len(astseq) == 2:
1021 # 3. power
1022 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
1023 else:
1024 raise Exception("wrong length of factor")
1025 return tree # }}}
1027 if astseq[0] == symbol.power: # {{{
1028 try:
1029 # 1. "DOUBLESTAR" factor
1030 if astseq[-2][0] == token.DOUBLESTAR:
1031 tree = MathTreeOpPow(
1032 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
1033 self.astseq2mtree(astseq[-1], isfunc=isfunc))
1034 else:
1035 raise Exception("")
1036 except:
1037 # 2. atom + [trailer]
1038 if len(astseq) == 3:
1039 # we have a function call atom + "LPAR" + argumentlist + "RPAR"
1040 if astseq[2][0] != symbol.trailer or \
1041 astseq[2][1][0] != token.LPAR or \
1042 astseq[2][2][0] != symbol.arglist or \
1043 astseq[2][3][0] != token.RPAR:
1044 raise Exception("wrong function call")
1045 tree = self.astseq2mtree(astseq[1], isfunc=1)
1046 for subtree in self.astseq2mtree(astseq[2][2], isfunc=0):
1047 tree.AddArg(subtree)
1048 else:
1049 tree = self.astseq2mtree(astseq[1], isfunc=0)
1051 return tree # }}}
1053 if astseq[0] == symbol.atom: # {{{
1054 # only one nontrivial term:
1055 if len(astseq) == 2:
1056 if astseq[1][0] == token.NUMBER:
1057 # 1. a number
1058 # XXX: for evaluation of brackets we will need integers as well
1059 tree = MathTreeValConst(string.atof(astseq[1][1]))
1060 elif astseq[1][0] == token.NAME:
1061 # 2. a function
1062 if isfunc:
1063 # a known function
1064 for funcclass in self.MathTreeFuncs:
1065 func = funcclass() # ist das guenstig, da jedesmal eine Instanz zu erzeugen?
1066 # doofe Frage, nein! <wobsta>
1067 if func.name == astseq[1][1]:
1068 return func
1069 # an unknown function
1070 tree = MathTreeFuncExtern()
1071 tree.SetName(astseq[1][1])
1072 else:
1073 # 3. a named constant
1074 for const in MathConst.keys():
1075 # XXX: change to self.MathConstants
1076 if const == astseq[1][1]:
1077 return MathTreeValConst(MathConst[const])
1078 # 4. a variable
1079 return MathTreeValVar(astseq[1][1])
1080 elif len(astseq) == 4:
1081 # parentheses or brackets for structuring an atom
1082 if (astseq[1][0] == token.LPAR and astseq[3][0] == token.RPAR) or \
1083 (astseq[1][0] == token.LSQB and astseq[3][0] == token.RSQB):
1084 tree = self.astseq2mtree(astseq[2], isfunc=isfunc)
1085 else:
1086 raise Exception("symbol.atom with unknown number of arguments")
1087 return tree # }}}
1089 if astseq[0] == symbol.arglist: # {{{
1090 treelist = []
1091 for arg in astseq[1:]:
1092 if arg[0] == token.COMMA:
1093 continue
1094 elif arg[0] == symbol.argument:
1095 treelist.append(self.astseq2mtree(arg, isfunc=isfunc))
1096 return treelist # }}}
1098 if astseq[0] == symbol.testlist: # {{{
1099 treelist = []
1100 for arg in astseq[1:]:
1101 if arg[0] == token.COMMA:
1102 continue
1103 elif arg[0] == symbol.test:
1104 treelist.append(self.astseq2mtree(arg, isfunc=isfunc))
1105 if len(treelist) == 1: return treelist[0]
1106 else: return treelist # }}}
1108 return self.astseq2mtree(astseq[1], isfunc=isfunc)