new attribute handling in text module completed
[PyX/mjg.git] / pyx / mathtree.py
blob201d9a89b2d42eea0a5ed1c34c9af231c35c370c
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
27 __oldparser__ = 1
28 __newparser__ = 2
29 __useparser__ = __oldparser__
30 #__useparser__ = __newparser__
32 if __useparser__ == __newparser__:
33 import symbol, token
34 import parser as pythonparser
36 class ParseStr:
38 def __init__(self, StrToParse, Pos = 0):
39 self.StrToParse = StrToParse
40 self.Pos = Pos
42 def __repr__(self):
43 return "ParseStr('" + self.StrToParse + "', " + str(self.Pos) + ")"
45 def __str__(self, Indent = ""):
46 WhiteSpaces = ""
47 for i in range(self.Pos):
48 WhiteSpaces = WhiteSpaces + " "
49 return Indent + self.StrToParse + "\n" + Indent + WhiteSpaces + "^"
51 def NextNonWhiteSpace(self, i = None):
52 if i == None:
53 i = self.Pos
54 while self.StrToParse[i] in string.whitespace:
55 i = i + 1
56 return i
58 def MatchStr(self, Str):
59 try:
60 i = self.NextNonWhiteSpace()
61 if self.StrToParse[i: i + len(Str)] == Str:
62 self.Pos = i + len(Str)
63 return Str
64 except IndexError:
65 pass
67 def MatchStrParenthesis(self, Str):
68 try:
69 i = self.NextNonWhiteSpace()
70 if self.StrToParse[i: i + len(Str)] == Str:
71 i = i + len(Str)
72 i = self.NextNonWhiteSpace(i)
73 if self.StrToParse[i: i + 1] == "(":
74 self.Pos = i + 1
75 return Str
76 except IndexError:
77 pass
79 def MatchPattern(self, Pat):
80 try:
81 i = self.NextNonWhiteSpace()
82 Match = Pat.match(self.StrToParse[i:])
83 if Match:
84 self.Pos = i + Match.end()
85 return Match.group()
86 except IndexError:
87 pass
89 def AllDone(self):
90 try:
91 self.NextNonWhiteSpace()
92 except IndexError:
93 return 1
94 return 0
97 class ArgCountError(Exception): pass
98 class DerivativeError(Exception): pass
100 class MathTree:
102 def __init__(self, ArgCount, *Args):
103 self.ArgCount = ArgCount
104 self.Args = []
105 for arg in Args:
106 self.AddArg(arg)
108 def __repr__(self, depth = 0):
109 indent = ""
110 SingleIndent = " "
111 for i in range(depth):
112 indent = indent + SingleIndent
113 result = indent + self.__class__.__name__ + "(\n"
114 for SubTree in self.Args:
115 if isinstance(SubTree, MathTree):
116 result = result + SubTree.__repr__(depth + 1)
117 else:
118 result = result + indent + SingleIndent + repr(SubTree)
120 if SubTree != self.Args[-1]:
121 result = result + ",\n"
122 else:
123 result = result + ")"
124 return result
126 def AddArg(self, Arg, Last=0, NotLast=0):
127 if len(self.Args) == self.ArgCount:
128 raise ArgCountError
129 self.Args.append(Arg)
130 if NotLast and len(self.Args) == self.ArgCount:
131 raise ArgCountError
132 if Last and len(self.Args) != self.ArgCount:
133 raise ArgCountError
135 def DependOn(self, arg):
136 for Arg in self.Args:
137 if Arg.DependOn(arg):
138 return 1
139 return 0
141 def Derivative(self, arg):
142 if not self.DependOn(arg):
143 return MathTreeValConst(0.0)
144 return self.CalcDerivative(arg)
146 def VarList(self):
147 list = [ ]
148 for Arg in self.Args:
149 newlist = Arg.VarList()
150 for x in newlist:
151 if x not in list:
152 list.append(x)
153 return list
156 class MathTreeVal(MathTree):
158 def __init__(self, *args):
159 MathTree.__init__(self, 1, *args)
161 def __str__(self):
162 return str(self.Args[0])
165 ConstPattern = re.compile(r"-?\d*((\d\.?)|(\.?\d))\d*(E[+-]?\d+)?",
166 re.IGNORECASE)
168 class MathTreeValConst(MathTreeVal):
170 def InitByParser(self, arg):
171 Match = arg.MatchPattern(ConstPattern)
172 if Match:
173 self.AddArg(string.atof(Match))
174 return 1
176 def CalcDerivative(self, arg):
177 raise DerivativeError("expression doesn't depend on \"%s\"" % arg)
179 def Derivative(self, arg):
180 return MathTreeValConst(0.0)
182 def DependOn(self, arg):
183 return 0
185 def VarList(self):
186 return [ ]
188 def Calc(HIDDEN_self, **args):
189 return HIDDEN_self.Args[0]
192 VarPattern = re.compile(r"[a-z_][a-z0-9_]*", re.IGNORECASE)
193 MathConst = {"pi": math.pi, "e": math.e}
195 class MathTreeValVar(MathTreeVal):
197 def InitByParser(self, arg):
198 Match = arg.MatchPattern(VarPattern)
199 if Match:
200 self.AddArg(Match)
201 return 1
203 def CalcDerivative(self, arg):
204 if arg != self.Args[0]:
205 raise DerivativeError("expression doesn't depend on \"%s\"" % arg)
206 return MathTreeValConst(1.0)
208 def DependOn(self, arg):
209 if arg == self.Args[0]:
210 return 1
211 return 0
213 def VarList(self):
214 if self.Args[0] in MathConst.keys():
215 return []
216 return [self.Args[0]]
218 def Calc(HIDDEN_self, **args):
219 if HIDDEN_self.Args[0] in args.keys():
220 return float(args[HIDDEN_self.Args[0]])
221 return MathConst[HIDDEN_self.Args[0]]
224 class MathTreeFunc(MathTree):
226 def __init__(self, name, ArgCount, *args):
227 self.name = name
228 MathTree.__init__(self, ArgCount, *args)
230 def InitByParser(self, arg):
231 return arg.MatchStrParenthesis(self.name)
233 def __str__(self):
234 args = ""
235 for SubTree in self.Args:
236 args = args + str(SubTree)
237 if SubTree != self.Args[-1]:
238 args = args + ","
239 return self.name + "(" + args + ")"
242 class MathTreeFunc1(MathTreeFunc):
244 def __init__(self, name, *args):
245 MathTreeFunc.__init__(self, name, 1, *args)
248 class MathTreeFunc1Neg(MathTreeFunc1):
250 def __init__(self, *args):
251 MathTreeFunc1.__init__(self, "neg", *args)
253 def CalcDerivative(self, arg):
254 return MathTreeFunc1Neg(self.Args[0].CalcDerivative(arg))
256 def Calc(HIDDEN_self, **args):
257 return -HIDDEN_self.Args[0].Calc(**args)
260 class MathTreeFunc1Abs(MathTreeFunc1):
262 def __init__(self, *args):
263 MathTreeFunc1.__init__(self, "abs", *args)
265 def CalcDerivative(self, arg):
266 return MathTreeOpMul(
267 MathTreeFunc1Sgn(self.Args[0]),
268 self.Args[0].CalcDerivative(arg))
270 def Calc(HIDDEN_self, **args):
271 return abs(HIDDEN_self.Args[0].Calc(**args))
274 class MathTreeFunc1Sgn(MathTreeFunc1):
276 def __init__(self, *args):
277 MathTreeFunc1.__init__(self, "sgn", *args)
279 def CalcDerivative(self, arg):
280 return MathTreeValConst(0.0)
282 def Calc(HIDDEN_self, **args):
283 if HIDDEN_self.Args[0].Calc(**args) < 0:
284 return -1.0
285 return 1.0
288 class MathTreeFunc1Sqrt(MathTreeFunc1):
290 def __init__(self, *args):
291 MathTreeFunc1.__init__(self, "sqrt", *args)
293 def CalcDerivative(self, arg):
294 return MathTreeOpMul(
295 MathTreeOpDiv(
296 MathTreeValConst(0.5),
297 self),
298 self.Args[0].CalcDerivative(arg))
300 def Calc(HIDDEN_self, **args):
301 return math.sqrt(HIDDEN_self.Args[0].Calc(**args))
304 class MathTreeFunc1Exp(MathTreeFunc1):
306 def __init__(self, *args):
307 MathTreeFunc1.__init__(self, "exp", *args)
309 def CalcDerivative(self, arg):
310 return MathTreeOpMul(self, self.Args[0].CalcDerivative(arg))
312 def Calc(HIDDEN_self, **args):
313 return math.exp(HIDDEN_self.Args[0].Calc(**args))
316 class MathTreeFunc1Log(MathTreeFunc1):
318 def __init__(self, *args):
319 MathTreeFunc1.__init__(self, "log", *args)
321 def CalcDerivative(self, arg):
322 return MathTreeOpDiv(self.Args[0].CalcDerivative(arg), self.Args[0])
324 def Calc(HIDDEN_self, **args):
325 return math.log(HIDDEN_self.Args[0].Calc(**args))
328 class MathTreeFunc1Sin(MathTreeFunc1):
330 def __init__(self, *args):
331 MathTreeFunc1.__init__(self, "sin", *args)
333 def CalcDerivative(self, arg):
334 return MathTreeOpMul(
335 MathTreeFunc1Cos(self.Args[0]),
336 self.Args[0].CalcDerivative(arg))
338 def Calc(HIDDEN_self, **args):
339 return math.sin(HIDDEN_self.Args[0].Calc(**args))
342 class MathTreeFunc1Cos(MathTreeFunc1):
344 def __init__(self, *args):
345 MathTreeFunc1.__init__(self, "cos", *args)
347 def CalcDerivative(self, arg):
348 return MathTreeOpMul(
349 MathTreeFunc1Neg(MathTreeFunc1Sin(self.Args[0])),
350 self.Args[0].CalcDerivative(arg))
352 def Calc(HIDDEN_self, **args):
353 return math.cos(HIDDEN_self.Args[0].Calc(**args))
356 class MathTreeFunc1Tan(MathTreeFunc1):
358 def __init__(self, *args):
359 MathTreeFunc1.__init__(self, "tan", *args)
361 def CalcDerivative(self, arg):
362 return MathTreeOpDiv(
363 self.Args[0].CalcDerivative(arg),
364 MathTreeOpPow(
365 MathTreeFunc1Cos(self.Args[0]),
366 MathTreeValConst(2.0)))
368 def Calc(HIDDEN_self, **args):
369 return math.tan(HIDDEN_self.Args[0].Calc(**args))
372 class MathTreeFunc1ASin(MathTreeFunc1):
374 def __init__(self, *args):
375 MathTreeFunc1.__init__(self, "asin", *args)
377 def CalcDerivative(self, arg):
378 return MathTreeOpDiv(
379 self.Args[0].CalcDerivative(arg),
380 MathTreeFunc1Sqrt(
381 MathTreeOpSub(
382 MathTreeValConst(1.0),
383 MathTreeOpPow(
384 self.Args[0],
385 MathTreeValConst(2.0)))))
387 def Calc(HIDDEN_self, **args):
388 return math.asin(HIDDEN_self.Args[0].Calc(**args))
391 class MathTreeFunc1ACos(MathTreeFunc1):
393 def __init__(self, *args):
394 MathTreeFunc1.__init__(self, "acos", *args)
396 def CalcDerivate(self, arg):
397 return MathTreeOpDiv(
398 MathTreeFunc1Neg(self.Args[0].CalcDerivative(arg)),
399 MathTreeFunc1Sqrt(
400 MathTreeOpSub(
401 MathTreeValConst(1.0),
402 MathTreeOpPow(
403 self.Args[0],
404 MathTreeValConst(2.0)))))
406 def Calc(HIDDEN_self, **args):
407 return math.acos(HIDDEN_self.Args[0].Calc(**args))
410 class MathTreeFunc1ATan(MathTreeFunc1):
412 def __init__(self, *args):
413 MathTreeFunc1.__init__(self, "atan", *args)
415 def CalcDerivate(self, arg):
416 return MathTreeOpDiv(
417 self.Args[0].CalcDerivative(arg),
418 MathTreeOpAdd(
419 MathTreeValConst(1.0),
420 MathTreeOpPow(
421 self.Args[0],
422 MathTreeValConst(2.0))))
424 def Calc(HIDDEN_self, **args):
425 return math.atan(HIDDEN_self.Args[0].Calc(**args))
428 class MathTreeFunc1SinD(MathTreeFunc1):
430 def __init__(self, *args):
431 MathTreeFunc1.__init__(self, "sind", *args)
433 def CalcDerivative(self, arg):
434 return MathTreeOpMul(
435 MathTreeFunc1CosD(self.Args[0]),
436 MathTreeOpMul(
437 MathTreeValConst(math.pi/180.0),
438 self.Args[0].CalcDerivative(arg)))
440 def Calc(HIDDEN_self, **args):
441 return math.sin(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
444 class MathTreeFunc1CosD(MathTreeFunc1):
446 def __init__(self, *args):
447 MathTreeFunc1.__init__(self, "cosd", *args)
449 def CalcDerivative(self, arg):
450 return MathTreeOpMul(
451 MathTreeFunc1Neg(MathTreeFunc1Sin(self.Args[0])),
452 MathTreeOpMul(
453 MathTreeValConst(math.pi/180.0),
454 self.Args[0].CalcDerivative(arg)))
456 def Calc(HIDDEN_self, **args):
457 return math.cos(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
460 class MathTreeFunc1TanD(MathTreeFunc1):
462 def __init__(self, *args):
463 MathTreeFunc1.__init__(self, "tand", *args)
465 def CalcDerivative(self, arg):
466 return MathTreeOpDiv(
467 MathTreeOpMul(
468 MathTreeValConst(math.pi/180.0),
469 self.Args[0].CalcDerivative(arg)),
470 MathTreeOpPow(
471 MathTreeFunc1Cos(self.Args[0]),
472 MathTreeValConst(2.0)))
474 def Calc(HIDDEN_self, **args):
475 return math.tan(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
478 class MathTreeFunc1ASinD(MathTreeFunc1):
480 def __init__(self, *args):
481 MathTreeFunc1.__init__(self, "asind", *args)
483 def CalcDerivative(self, arg):
484 return MathTreeOpDiv(
485 MathTreeOpMul(
486 MathTreeValConst(180.0/math.pi),
487 self.Args[0].CalcDerivative(arg)),
488 MathTreeFunc1Sqrt(
489 MathTreeOpSub(
490 MathTreeValConst(1.0),
491 MathTreeOpPow(
492 self.Args[0],
493 MathTreeValConst(2.0)))))
495 def Calc(HIDDEN_self, **args):
496 return 180.0/math.pi*math.asin(HIDDEN_self.Args[0].Calc(**args))
499 class MathTreeFunc1ACosD(MathTreeFunc1):
501 def __init__(self, *args):
502 MathTreeFunc1.__init__(self, "acosd", *args)
504 def CalcDerivate(self, arg):
505 return MathTreeOpDiv(
506 MathTreeFunc1Neg(
507 MathTreeOpMul(
508 MathTreeValConst(180.0/math.pi),
509 self.Args[0].CalcDerivative(arg))),
510 MathTreeFunc1Sqrt(
511 MathTreeOpSub(
512 MathTreeValConst(1.0),
513 MathTreeOpPow(
514 self.Args[0],
515 MathTreeValConst(2.0)))))
517 def Calc(HIDDEN_self, **args):
518 return 180.0/math.pi*math.acos(HIDDEN_self.Args[0].Calc(**args))
521 class MathTreeFunc1ATanD(MathTreeFunc1):
523 def __init__(self, *args):
524 MathTreeFunc1.__init__(self, "atand", *args)
526 def CalcDerivate(self, arg):
527 return MathTreeOpDiv(
528 MathTreeOpMul(
529 MathTreeValConst(180.0/math.pi),
530 self.Args[0].CalcDerivative(arg)),
531 MathTreeOpAdd(
532 MathTreeValConst(1.0),
533 MathTreeOpPow(
534 self.Args[0],
535 MathTreeValConst(2.0))))
537 def Calc(HIDDEN_self, **args):
538 return 180.0/math.pi*math.atan(HIDDEN_self.Args[0].Calc(**args))
541 class MathTreeFunc2(MathTreeFunc):
543 def __init__(self, name, *args):
544 MathTreeFunc.__init__(self, name, 2, *args)
547 class MathTreeFunc2Norm(MathTreeFunc2):
549 def __init__(self, *args):
550 MathTreeFunc2.__init__(self, "norm", *args)
552 def CalcDerivative(self, arg):
553 if self.Args[0].DependOn(arg):
554 if self.Args[1].DependOn(arg):
555 return MathTreeOpDiv(
556 MathTreeOpAdd(
557 MathTreeOpMul(
558 self.Args[0],
559 self.Args[0].CalcDerivative(arg)),
560 MathTreeOpMul(
561 self.Args[1],
562 self.Args[1].CalcDerivative(arg))),
563 self)
564 else:
565 return MathTreeOpDiv(
566 MathTreeOpMul(
567 self.Args[0],
568 self.Args[0].CalcDerivative(arg)),
569 self)
570 else:
571 if self.Args[1].DependOn(arg):
572 return MathTreeOpDiv(
573 MathTreeOpMul(
574 self.Args[1],
575 self.Args[1].CalcDerivative(arg)),
576 self)
578 def Calc(HIDDEN_self, **args):
579 return math.sqrt(HIDDEN_self.Args[0].Calc(**args) ** 2 +
580 HIDDEN_self.Args[1].Calc(**args) ** 2)
583 FuncExternPattern = re.compile(r"([a-z_][a-z0-9_]*)\s*\(", re.IGNORECASE)
585 class MathTreeFuncExtern(MathTreeFunc):
587 def __init__(self, *args):
588 MathTreeFunc.__init__(self, None, -1, *args)
590 def InitByParser(self, arg):
591 Match = arg.MatchPattern(FuncExternPattern)
592 if Match:
593 self.name = Match[:-1].strip()
594 return self.name
596 def SetName(self, arg):
597 self.name = arg.strip()
598 return self
600 def Calc(HIDDEN_self, **args):
601 return args[HIDDEN_self.name](*[arg.Calc(**args) for arg in HIDDEN_self.Args])
604 class MathTreeOp(MathTree):
606 def __init__(self, level, symbol, *args):
607 self.ParenthesisBarrier = 0
608 self.level = level
609 self.symbol = symbol
610 MathTree.__init__(self, 2, *args)
612 def __str__(self):
613 result = ""
614 if isinstance(self.Args[0], MathTreeOp) and\
615 self.level > self.Args[0].level:
616 result = result + "(" + str(self.Args[0]) + ")"
617 else:
618 result = result + str(self.Args[0])
619 result = result + self.symbol
620 if isinstance(self.Args[1], MathTreeOp) and\
621 self.level >= self.Args[1].level:
622 result = result + "(" + str(self.Args[1]) + ")"
623 else:
624 result = result + str(self.Args[1])
625 return result
627 def InitByParser(self, arg):
628 return arg.MatchStr(self.symbol)
631 class MathTreeOpAdd(MathTreeOp):
633 def __init__(self, *args):
634 MathTreeOp.__init__(self, 1, "+", *args)
636 def CalcDerivative(self, arg):
637 if self.Args[0].DependOn(arg):
638 if self.Args[1].DependOn(arg):
639 return MathTreeOpAdd(
640 self.Args[0].CalcDerivative(arg),
641 self.Args[1].CalcDerivative(arg))
642 else:
643 return self.Args[0].CalcDerivative(arg)
644 else:
645 if self.Args[1].DependOn(arg):
646 return self.Args[1].CalcDerivative(arg)
648 def Calc(HIDDEN_self, **args):
649 return HIDDEN_self.Args[0].Calc(**args) + HIDDEN_self.Args[1].Calc(**args)
652 class MathTreeOpSub(MathTreeOp):
654 def __init__(self, *args):
655 MathTreeOp.__init__(self, 1, "-", *args)
657 def CalcDerivative(self, arg):
658 if self.Args[0].DependOn(arg):
659 if self.Args[1].DependOn(arg):
660 return MathTreeOpSub(
661 self.Args[0].CalcDerivative(arg),
662 self.Args[1].CalcDerivative(arg))
663 else:
664 return self.Args[0].CalcDerivative(arg)
665 else:
666 if self.Args[1].DependOn(arg):
667 return MathTreeFunc1Neg(self.Args[1].CalcDerivative(arg))
669 def Calc(HIDDEN_self, **args):
670 return HIDDEN_self.Args[0].Calc(**args) - HIDDEN_self.Args[1].Calc(**args)
673 class MathTreeOpMul(MathTreeOp):
675 def __init__(self, *args):
676 MathTreeOp.__init__(self, 2, "*", *args)
678 def CalcDerivative(self, arg):
679 if self.Args[0].DependOn(arg):
680 if self.Args[1].DependOn(arg):
681 return MathTreeOpAdd(
682 MathTreeOpMul(
683 self.Args[0],
684 self.Args[1].CalcDerivative(arg)),
685 MathTreeOpMul(
686 self.Args[0].CalcDerivative(arg),
687 self.Args[1]))
688 else:
689 return MathTreeOpMul(
690 self.Args[0].CalcDerivative(arg),
691 self.Args[1])
692 else:
693 if self.Args[1].DependOn(arg):
694 return MathTreeOpMul(
695 self.Args[0],
696 self.Args[1].CalcDerivative(arg))
698 def Calc(HIDDEN_self, **args):
699 return HIDDEN_self.Args[0].Calc(**args) * HIDDEN_self.Args[1].Calc(**args)
702 class MathTreeOpDiv(MathTreeOp):
704 def __init__(self, *args):
705 MathTreeOp.__init__(self, 2, "/", *args)
707 def CalcDerivative(self, arg):
708 if self.Args[0].DependOn(arg):
709 if self.Args[1].DependOn(arg):
710 return MathTreeOpMul(
711 MathTreeOpSub(
712 MathTreeOpMul(
713 self.Args[0].CalcDerivative(arg),
714 self.Args[1]),
715 MathTreeOpMul(
716 self.Args[0],
717 self.Args[1].CalcDerivative(arg))),
718 MathTreeOpPow(
719 self.Args[1],
720 MathTreeValConst(-2.0)))
721 else:
722 return MathTreeOpDiv(
723 self.Args[0].CalcDerivative(arg),
724 self.Args[1])
725 else:
726 if self.Args[1].DependOn(arg):
727 return MathTreeOpMul(
728 MathTreeOpMul(
729 MathTreeFunc1Neg(self.Args[0]),
730 MathTreeOpPow(
731 self.Args[1],
732 MathTreeValConst(-2.0))),
733 self.Args[1].CalcDerivative(arg))
735 def Calc(HIDDEN_self, **args):
736 return HIDDEN_self.Args[0].Calc(**args) / HIDDEN_self.Args[1].Calc(**args)
739 class MathTreeOpPow(MathTreeOp):
741 def __init__(self, *args):
742 MathTreeOp.__init__(self, 3, "^", *args)
744 def InitByParser(self, arg):
745 pos = arg.MatchStr("^")
746 if pos:
747 return 1
748 else:
749 return arg.MatchStr("**")
751 def CalcDerivative(self, arg):
752 if self.Args[0].DependOn(arg):
753 if self.Args[1].DependOn(arg):
754 return MathTreeOpMul(
755 MathTreeOpPow(
756 self.Args[0],
757 self.Args[1]),
758 MathTreeOpAdd(
759 MathTreeOpMul(
760 MathTreeFunc1Log(self.Args[0]),
761 self.Args[1].CalcDerivative(arg)),
762 MathTreeOpMul(
763 self.Args[1],
764 MathTreeOpDiv(
765 self.Args[0].CalcDerivative(arg),
766 self.Args[0]))))
767 else:
768 return MathTreeOpMul(
769 self.Args[1],
770 MathTreeOpMul(
771 MathTreeOpPow(
772 self.Args[0],
773 MathTreeOpSub(
774 self.Args[1],
775 MathTreeValConst(1.0))),
776 self.Args[0].CalcDerivative(arg)))
777 else:
778 if self.Args[1].DependOn(arg):
779 return MathTreeOpMul(
780 MathTreeOpMul(
781 MathTreeOpPow(
782 self.Args[0],
783 self.Args[1]),
784 MathTreeFunc1Log(self.Args[0])),
785 self.Args[1].CalcDerivative(arg))
787 def Calc(HIDDEN_self, **args):
788 return HIDDEN_self.Args[0].Calc(**args) ** HIDDEN_self.Args[1].Calc(**args)
792 class UndefinedMathTreeParseError(Exception):
794 def __init__(self, ParseStr, MathTree):
795 self.ParseStr = ParseStr
796 self.MathTree = MathTree
798 def __str__(self):
799 return "\n" + str(self.ParseStr)
802 class RightParenthesisExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
803 class RightParenthesisFoundMathTreeParseError(UndefinedMathTreeParseError): pass
804 class CommaExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
805 class CommaFoundMathTreeParseError(UndefinedMathTreeParseError): pass
806 class OperatorExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
807 class OperandExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
810 DefaultMathTreeOps = (MathTreeOpPow, MathTreeOpDiv, MathTreeOpMul, MathTreeOpSub, MathTreeOpAdd)
811 DefaultMathTreeFuncs = (MathTreeFunc1Neg, MathTreeFunc1Abs, MathTreeFunc1Sgn, MathTreeFunc1Sqrt,
812 MathTreeFunc1Exp, MathTreeFunc1Log,
813 MathTreeFunc1Sin, MathTreeFunc1Cos, MathTreeFunc1Tan,
814 MathTreeFunc1ASin, MathTreeFunc1ACos, MathTreeFunc1ATan,
815 MathTreeFunc1SinD, MathTreeFunc1CosD, MathTreeFunc1TanD,
816 MathTreeFunc1ASinD, MathTreeFunc1ACosD, MathTreeFunc1ATanD,
817 MathTreeFunc2Norm)
819 DefaultMathTreeVals = (MathTreeValConst, MathTreeValVar)
821 class parser:
823 def __init__(self, MathTreeOps=DefaultMathTreeOps,
824 MathTreeFuncs=DefaultMathTreeFuncs,
825 MathTreeVals=DefaultMathTreeVals):
826 self.MathTreeOps = MathTreeOps
827 self.MathTreeFuncs = MathTreeFuncs
828 self.MathTreeVals = MathTreeVals
829 self.isnewparser = 0
831 def parse(self, str):
832 if __useparser__ == __oldparser__:
833 return self.old_parse(str)
834 elif __useparser__ == __newparser__:
835 return self.new_parse(str)
836 else:
837 RuntimeError("invalid __useparser__")
839 def old_parse(self, str):
840 return self.ParseMathTree(ParseStr(str))
842 def new_parse(self, str):
843 # prepare raw string:
844 # "^" -> "**"
845 thestr = re.sub("^\s*", "", str)
846 thestr = re.sub("\^","**", thestr) # to be removed <joergl>
847 thestr = re.sub("\$","_col_", thestr)
848 return self.astseq2mtree(pythonparser.expr(thestr).totuple())
850 def ParseMathTree(self, arg):
851 Tree = None
852 #Match = arg.MatchPattern(re.compile(r"\s*-(?![0-9\.])"))
853 Match = arg.MatchPattern(re.compile(r"\s*-")) # XXX another quick workaround
854 if Match:
855 #Tree = MathTreeFunc1Neg()
856 Tree = MathTreeOpSub(MathTreeValConst(0)) # XXX quick workaround
857 while 1:
858 i = arg.MatchStr("(")
859 if i:
860 try:
861 self.ParseMathTree(arg)
862 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
863 except RightParenthesisFoundMathTreeParseError, e:
864 if isinstance(e.MathTree, MathTreeOp):
865 e.MathTree.ParenthesisBarrier = 1
866 if Tree is not None:
867 SubTree = Tree # XXX: four lines code dublication
868 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
869 SubTree = SubTree.Args[1]
870 SubTree.AddArg(e.MathTree)
871 else:
872 Tree = e.MathTree
873 else:
874 for FuncClass in self.MathTreeFuncs:
875 Func = FuncClass()
876 if Func.InitByParser(arg):
877 if Tree is not None:
878 SubTree = Tree # XXX: four lines code dublication
879 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
880 SubTree = SubTree.Args[1]
881 SubTree.AddArg(Func)
882 else:
883 Tree = Func
884 while 1:
885 try:
886 self.ParseMathTree(arg)
887 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
888 except CommaFoundMathTreeParseError, e:
889 try:
890 Func.AddArg(e.MathTree, NotLast=1)
891 except ArgCountError:
892 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
893 continue
894 except RightParenthesisFoundMathTreeParseError, e:
895 try:
896 Func.AddArg(e.MathTree, Last=1)
897 except ArgCountError:
898 raise CommaExpectedMathTreeParseError(arg, Tree)
899 break
900 break
901 else:
902 FuncExtern = MathTreeFuncExtern()
903 if FuncExtern.InitByParser(arg):
904 if Tree is not None:
905 SubTree = Tree # XXX: four lines code dublication
906 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
907 SubTree = SubTree.Args[1]
908 SubTree.AddArg(FuncExtern)
909 else:
910 Tree = FuncExtern
911 while 1:
912 try:
913 self.ParseMathTree(arg)
914 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
915 except CommaFoundMathTreeParseError, e:
916 FuncExtern.AddArg(e.MathTree)
917 continue
918 except RightParenthesisFoundMathTreeParseError, e:
919 FuncExtern.AddArg(e.MathTree)
920 break
921 else:
922 for ValClass in self.MathTreeVals:
923 Val = ValClass()
924 if Val.InitByParser(arg):
925 if Tree is not None:
926 SubTree = Tree # XXX: four lines code dublication
927 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
928 SubTree = SubTree.Args[1]
929 SubTree.AddArg(Val)
930 else:
931 Tree = Val
932 break
933 else:
934 raise OperandExpectedMathTreeParseError(arg, Tree)
935 if arg.AllDone():
936 return Tree
937 i = arg.MatchStr(")")
938 if i:
939 raise RightParenthesisFoundMathTreeParseError(arg, Tree)
940 i = arg.MatchStr(",")
941 if i:
942 raise CommaFoundMathTreeParseError(arg, Tree)
943 for OpClass in self.MathTreeOps:
944 Op = OpClass()
945 if Op.InitByParser(arg):
946 SubTree = Tree
947 SubTreeRoot = None
948 while isinstance(SubTree, MathTreeOp) and\
949 Op.level > SubTree.level and\
950 not SubTree.ParenthesisBarrier:
951 SubTreeRoot = SubTree
952 SubTree = SubTree.Args[1]
953 if SubTreeRoot:
954 Op.AddArg(SubTree)
955 SubTreeRoot.Args[1] = Op
956 else:
957 Op.AddArg(Tree)
958 Tree = Op
959 break
960 else:
961 raise OperatorExpectedMathTreeParseError(arg, Tree)
964 def astseq2mtree(self, astseq, isfunc=0):
965 # astseq has to be a sequence!
966 tree = None
968 if token.ISTERMINAL(astseq[0]):
969 raise Exception("")
971 if astseq[0] == symbol.arith_expr: # {{{
972 try:
973 # 1. arith_expr "PLUS" term
974 if astseq[-2][0] == token.PLUS:
975 tree = MathTreeOpAdd(
976 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
977 self.astseq2mtree(astseq[-1], isfunc=isfunc))
978 # 2. arith_expr "MINUS" term
979 elif astseq[-2][0] == token.MINUS:
980 tree = MathTreeOpSub(
981 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
982 self.astseq2mtree(astseq[-1], isfunc=isfunc))
983 else:
984 raise Exception("")
985 except:
986 # 3. term
987 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
988 return tree # }}}
990 if astseq[0] == symbol.term: # {{{
991 try:
992 # 1. term "STAR" factor
993 if astseq[-2][0] == token.STAR:
994 tree = MathTreeOpMul(
995 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
996 self.astseq2mtree(astseq[-1], isfunc=isfunc))
997 # 2. term "SLASH" factor
998 elif astseq[-2][0] == token.SLASH:
999 tree = MathTreeOpDiv(
1000 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
1001 self.astseq2mtree(astseq[-1], isfunc=isfunc))
1002 else:
1003 raise Exception("")
1004 except:
1005 # 3. factor
1006 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
1007 return tree # }}}
1009 if astseq[0] == symbol.factor: # {{{
1010 if len(astseq) == 3:
1011 # 1. "PLUS" factor
1012 if astseq[1][0] == token.PLUS:
1013 tree = self.astseq2mtree(astseq[2], isfunc=isfunc)
1014 # 2. "MINUS" factor
1015 elif astseq[1][0] == token.MINUS:
1016 tree = MathTreeFunc1Neg(self.astseq2mtree(astseq[2], isfunc=isfunc))
1017 else:
1018 raise Exception("unknown factor")
1019 elif len(astseq) == 2:
1020 # 3. power
1021 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
1022 else:
1023 raise Exception("wrong length of factor")
1024 return tree # }}}
1026 if astseq[0] == symbol.power: # {{{
1027 try:
1028 # 1. "DOUBLESTAR" factor
1029 if astseq[-2][0] == token.DOUBLESTAR:
1030 tree = MathTreeOpPow(
1031 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
1032 self.astseq2mtree(astseq[-1], isfunc=isfunc))
1033 else:
1034 raise Exception("")
1035 except:
1036 # 2. atom + [trailer]
1037 if len(astseq) == 3:
1038 # we have a function call atom + "LPAR" + argumentlist + "RPAR"
1039 if astseq[2][0] != symbol.trailer or \
1040 astseq[2][1][0] != token.LPAR or \
1041 astseq[2][2][0] != symbol.arglist or \
1042 astseq[2][3][0] != token.RPAR:
1043 raise Exception("wrong function call")
1044 tree = self.astseq2mtree(astseq[1], isfunc=1)
1045 for subtree in self.astseq2mtree(astseq[2][2], isfunc=0):
1046 tree.AddArg(subtree)
1047 else:
1048 tree = self.astseq2mtree(astseq[1], isfunc=0)
1050 return tree # }}}
1052 if astseq[0] == symbol.atom: # {{{
1053 # only one nontrivial term:
1054 if len(astseq) == 2:
1055 if astseq[1][0] == token.NUMBER:
1056 # 1. a number
1057 # XXX: for evaluation of brackets we will need integers as well
1058 tree = MathTreeValConst(string.atof(astseq[1][1]))
1059 elif astseq[1][0] == token.NAME:
1060 # 2. a function
1061 if isfunc:
1062 # a known function
1063 for funcclass in self.MathTreeFuncs:
1064 func = funcclass() # ist das guenstig, da jedesmal eine Instanz zu erzeugen?
1065 # doofe Frage, nein! <wobsta>
1066 if func.name == astseq[1][1]:
1067 return func
1068 # an unknown function
1069 tree = MathTreeFuncExtern()
1070 tree.SetName(astseq[1][1])
1071 else:
1072 # 3. a named constant
1073 for const in MathConst.keys():
1074 # XXX: change to self.MathConstants
1075 if const == astseq[1][1]:
1076 return MathTreeValConst(MathConst[const])
1077 # 4. a variable
1078 return MathTreeValVar(astseq[1][1])
1079 elif len(astseq) == 4:
1080 # parentheses or brackets for structuring an atom
1081 if (astseq[1][0] == token.LPAR and astseq[3][0] == token.RPAR) or \
1082 (astseq[1][0] == token.LSQB and astseq[3][0] == token.RSQB):
1083 tree = self.astseq2mtree(astseq[2], isfunc=isfunc)
1084 else:
1085 raise Exception("symbol.atom with unknown number of arguments")
1086 return tree # }}}
1088 if astseq[0] == symbol.arglist: # {{{
1089 treelist = []
1090 for arg in astseq[1:]:
1091 if arg[0] == token.COMMA:
1092 continue
1093 elif arg[0] == symbol.argument:
1094 treelist.append(self.astseq2mtree(arg, isfunc=isfunc))
1095 return treelist # }}}
1097 if astseq[0] == symbol.testlist: # {{{
1098 treelist = []
1099 for arg in astseq[1:]:
1100 if arg[0] == token.COMMA:
1101 continue
1102 elif arg[0] == symbol.test:
1103 treelist.append(self.astseq2mtree(arg, isfunc=isfunc))
1104 if len(treelist) == 1: return treelist[0]
1105 else: return treelist # }}}
1107 return self.astseq2mtree(astseq[1], isfunc=isfunc)