new parser: FuncExtern and multiple arguments to functions
[PyX/mjg.git] / pyx / mathtree.py
blobad9f95c49c719d3c24ad786a1177b61bb4d8fee8
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
26 import symbol, token
27 import parser as pythonparser
30 class ParseStr:
32 def __init__(self, StrToParse, Pos = 0):
33 self.StrToParse = StrToParse
34 self.Pos = Pos
36 def __repr__(self):
37 return "ParseStr('" + self.StrToParse + "', " + str(self.Pos) + ")"
39 def __str__(self, Indent = ""):
40 WhiteSpaces = ""
41 for i in range(self.Pos):
42 WhiteSpaces = WhiteSpaces + " "
43 return Indent + self.StrToParse + "\n" + Indent + WhiteSpaces + "^"
45 def NextNonWhiteSpace(self, i = None):
46 if i == None:
47 i = self.Pos
48 while self.StrToParse[i] in string.whitespace:
49 i = i + 1
50 return i
52 def MatchStr(self, Str):
53 try:
54 i = self.NextNonWhiteSpace()
55 if self.StrToParse[i: i + len(Str)] == Str:
56 self.Pos = i + len(Str)
57 return Str
58 except IndexError:
59 pass
61 def MatchStrParenthesis(self, Str):
62 try:
63 i = self.NextNonWhiteSpace()
64 if self.StrToParse[i: i + len(Str)] == Str:
65 i = i + len(Str)
66 i = self.NextNonWhiteSpace(i)
67 if self.StrToParse[i: i + 1] == "(":
68 self.Pos = i + 1
69 return Str
70 except IndexError:
71 pass
73 def MatchPattern(self, Pat):
74 try:
75 i = self.NextNonWhiteSpace()
76 Match = Pat.match(self.StrToParse[i:])
77 if Match:
78 self.Pos = i + Match.end()
79 return Match.group()
80 except IndexError:
81 pass
83 def AllDone(self):
84 try:
85 self.NextNonWhiteSpace()
86 except IndexError:
87 return 1
88 return 0
91 class ArgCountError(Exception): pass
92 class DerivativeError(Exception): pass
94 class MathTree:
96 def __init__(self, ArgCount, *Args):
97 self.ArgCount = ArgCount
98 self.Args = []
99 for arg in Args:
100 self.AddArg(arg)
102 def __repr__(self, depth = 0):
103 indent = ""
104 SingleIndent = " "
105 for i in range(depth):
106 indent = indent + SingleIndent
107 result = indent + self.__class__.__name__ + "(\n"
108 for SubTree in self.Args:
109 if isinstance(SubTree, MathTree):
110 result = result + SubTree.__repr__(depth + 1)
111 else:
112 result = result + indent + SingleIndent + repr(SubTree)
114 if SubTree != self.Args[-1]:
115 result = result + ",\n"
116 else:
117 result = result + ")"
118 return result
120 def AddArg(self, Arg, Last=0, NotLast=0):
121 if len(self.Args) == self.ArgCount:
122 raise ArgCountError
123 self.Args.append(Arg)
124 if NotLast and len(self.Args) == self.ArgCount:
125 raise ArgCountError
126 if Last and len(self.Args) != self.ArgCount:
127 raise ArgCountError
129 def DependOn(self, arg):
130 for Arg in self.Args:
131 if Arg.DependOn(arg):
132 return 1
133 return 0
135 def Derivative(self, arg):
136 if not self.DependOn(arg):
137 return MathTreeValConst(0.0)
138 return self.CalcDerivative(arg)
140 def VarList(self):
141 list = [ ]
142 for Arg in self.Args:
143 newlist = Arg.VarList()
144 for x in newlist:
145 if x not in list:
146 list.append(x)
147 return list
150 class MathTreeVal(MathTree):
152 def __init__(self, *args):
153 MathTree.__init__(self, 1, *args)
155 def __str__(self):
156 return str(self.Args[0])
159 ConstPattern = re.compile(r"-?\d*((\d\.?)|(\.?\d))\d*(E[+-]?\d+)?",
160 re.IGNORECASE)
162 class MathTreeValConst(MathTreeVal):
164 def InitByParser(self, arg):
165 Match = arg.MatchPattern(ConstPattern)
166 if Match:
167 self.AddArg(string.atof(Match))
168 return 1
170 def CalcDerivative(self, arg):
171 raise DerivativeError("expression doesn't depend on \"%s\"" % arg)
173 def Derivative(self, arg):
174 return MathTreeValConst(0.0)
176 def DependOn(self, arg):
177 return 0
179 def VarList(self):
180 return [ ]
182 def Calc(HIDDEN_self, **args):
183 return HIDDEN_self.Args[0]
186 VarPattern = re.compile(r"[a-z_][a-z0-9_]*", re.IGNORECASE)
187 MathConst = {"pi": math.pi, "e": math.e}
189 class MathTreeValVar(MathTreeVal):
191 def InitByParser(self, arg):
192 Match = arg.MatchPattern(VarPattern)
193 if Match:
194 self.AddArg(Match)
195 return 1
197 def CalcDerivative(self, arg):
198 if arg != self.Args[0]:
199 raise DerivativeError("expression doesn't depend on \"%s\"" % arg)
200 return MathTreeValConst(1.0)
202 def DependOn(self, arg):
203 if arg == self.Args[0]:
204 return 1
205 return 0
207 def VarList(self):
208 if self.Args[0] in MathConst.keys():
209 return []
210 return [self.Args[0]]
212 def Calc(HIDDEN_self, **args):
213 if HIDDEN_self.Args[0] in args.keys():
214 return float(args[HIDDEN_self.Args[0]])
215 return MathConst[HIDDEN_self.Args[0]]
218 class MathTreeFunc(MathTree):
220 def __init__(self, name, ArgCount, *args):
221 self.name = name
222 MathTree.__init__(self, ArgCount, *args)
224 def InitByParser(self, arg):
225 return arg.MatchStrParenthesis(self.name)
227 def __str__(self):
228 args = ""
229 for SubTree in self.Args:
230 args = args + str(SubTree)
231 if SubTree != self.Args[-1]:
232 args = args + ","
233 return self.name + "(" + args + ")"
236 class MathTreeFunc1(MathTreeFunc):
238 def __init__(self, name, *args):
239 MathTreeFunc.__init__(self, name, 1, *args)
242 class MathTreeFunc1Neg(MathTreeFunc1):
244 def __init__(self, *args):
245 MathTreeFunc1.__init__(self, "neg", *args)
247 def CalcDerivative(self, arg):
248 return MathTreeFunc1Neg(self.Args[0].CalcDerivative(arg))
250 def Calc(HIDDEN_self, **args):
251 return -HIDDEN_self.Args[0].Calc(**args)
254 class MathTreeFunc1Abs(MathTreeFunc1):
256 def __init__(self, *args):
257 MathTreeFunc1.__init__(self, "abs", *args)
259 def CalcDerivative(self, arg):
260 return MathTreeOpMul(
261 MathTreeFunc1Sgn(self.Args[0]),
262 self.Args[0].CalcDerivative(arg))
264 def Calc(HIDDEN_self, **args):
265 return abs(HIDDEN_self.Args[0].Calc(**args))
268 class MathTreeFunc1Sgn(MathTreeFunc1):
270 def __init__(self, *args):
271 MathTreeFunc1.__init__(self, "sgn", *args)
273 def CalcDerivative(self, arg):
274 return MathTreeValConst(0.0)
276 def Calc(HIDDEN_self, **args):
277 if HIDDEN_self.Args[0].Calc(**args) < 0:
278 return -1.0
279 return 1.0
282 class MathTreeFunc1Sqrt(MathTreeFunc1):
284 def __init__(self, *args):
285 MathTreeFunc1.__init__(self, "sqrt", *args)
287 def CalcDerivative(self, arg):
288 return MathTreeOpMul(
289 MathTreeOpDiv(
290 MathTreeValConst(0.5),
291 self),
292 self.Args[0].CalcDerivative(arg))
294 def Calc(HIDDEN_self, **args):
295 return math.sqrt(HIDDEN_self.Args[0].Calc(**args))
298 class MathTreeFunc1Exp(MathTreeFunc1):
300 def __init__(self, *args):
301 MathTreeFunc1.__init__(self, "exp", *args)
303 def CalcDerivative(self, arg):
304 return MathTreeOpMul(self, self.Args[0].CalcDerivative(arg))
306 def Calc(HIDDEN_self, **args):
307 return math.exp(HIDDEN_self.Args[0].Calc(**args))
310 class MathTreeFunc1Log(MathTreeFunc1):
312 def __init__(self, *args):
313 MathTreeFunc1.__init__(self, "log", *args)
315 def CalcDerivative(self, arg):
316 return MathTreeOpDiv(self.Args[0].CalcDerivative(arg), self.Args[0])
318 def Calc(HIDDEN_self, **args):
319 return math.log(HIDDEN_self.Args[0].Calc(**args))
322 class MathTreeFunc1Sin(MathTreeFunc1):
324 def __init__(self, *args):
325 MathTreeFunc1.__init__(self, "sin", *args)
327 def CalcDerivative(self, arg):
328 return MathTreeOpMul(
329 MathTreeFunc1Cos(self.Args[0]),
330 self.Args[0].CalcDerivative(arg))
332 def Calc(HIDDEN_self, **args):
333 return math.sin(HIDDEN_self.Args[0].Calc(**args))
336 class MathTreeFunc1Cos(MathTreeFunc1):
338 def __init__(self, *args):
339 MathTreeFunc1.__init__(self, "cos", *args)
341 def CalcDerivative(self, arg):
342 return MathTreeOpMul(
343 MathTreeFunc1Neg(MathTreeFunc1Sin(self.Args[0])),
344 self.Args[0].CalcDerivative(arg))
346 def Calc(HIDDEN_self, **args):
347 return math.cos(HIDDEN_self.Args[0].Calc(**args))
350 class MathTreeFunc1Tan(MathTreeFunc1):
352 def __init__(self, *args):
353 MathTreeFunc1.__init__(self, "tan", *args)
355 def CalcDerivative(self, arg):
356 return MathTreeOpDiv(
357 self.Args[0].CalcDerivative(arg),
358 MathTreeOpPow(
359 MathTreeFunc1Cos(self.Args[0]),
360 MathTreeValConst(2.0)))
362 def Calc(HIDDEN_self, **args):
363 return math.tan(HIDDEN_self.Args[0].Calc(**args))
366 class MathTreeFunc1ASin(MathTreeFunc1):
368 def __init__(self, *args):
369 MathTreeFunc1.__init__(self, "asin", *args)
371 def CalcDerivative(self, arg):
372 return MathTreeOpDiv(
373 self.Args[0].CalcDerivative(arg),
374 MathTreeFunc1Sqrt(
375 MathTreeOpSub(
376 MathTreeValConst(1.0),
377 MathTreeOpPow(
378 self.Args[0],
379 MathTreeValConst(2.0)))))
381 def Calc(HIDDEN_self, **args):
382 return math.asin(HIDDEN_self.Args[0].Calc(**args))
385 class MathTreeFunc1ACos(MathTreeFunc1):
387 def __init__(self, *args):
388 MathTreeFunc1.__init__(self, "acos", *args)
390 def CalcDerivate(self, arg):
391 return MathTreeOpDiv(
392 MathTreeFunc1Neg(self.Args[0].CalcDerivative(arg)),
393 MathTreeFunc1Sqrt(
394 MathTreeOpSub(
395 MathTreeValConst(1.0),
396 MathTreeOpPow(
397 self.Args[0],
398 MathTreeValConst(2.0)))))
400 def Calc(HIDDEN_self, **args):
401 return math.acos(HIDDEN_self.Args[0].Calc(**args))
404 class MathTreeFunc1ATan(MathTreeFunc1):
406 def __init__(self, *args):
407 MathTreeFunc1.__init__(self, "atan", *args)
409 def CalcDerivate(self, arg):
410 return MathTreeOpDiv(
411 self.Args[0].CalcDerivative(arg),
412 MathTreeOpAdd(
413 MathTreeValConst(1.0),
414 MathTreeOpPow(
415 self.Args[0],
416 MathTreeValConst(2.0))))
418 def Calc(HIDDEN_self, **args):
419 return math.atan(HIDDEN_self.Args[0].Calc(**args))
422 class MathTreeFunc1SinD(MathTreeFunc1):
424 def __init__(self, *args):
425 MathTreeFunc1.__init__(self, "sind", *args)
427 def CalcDerivative(self, arg):
428 return MathTreeOpMul(
429 MathTreeFunc1CosD(self.Args[0]),
430 MathTreeOpMul(
431 MathTreeValConst(math.pi/180.0),
432 self.Args[0].CalcDerivative(arg)))
434 def Calc(HIDDEN_self, **args):
435 return math.sin(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
438 class MathTreeFunc1CosD(MathTreeFunc1):
440 def __init__(self, *args):
441 MathTreeFunc1.__init__(self, "cosd", *args)
443 def CalcDerivative(self, arg):
444 return MathTreeOpMul(
445 MathTreeFunc1Neg(MathTreeFunc1Sin(self.Args[0])),
446 MathTreeOpMul(
447 MathTreeValConst(math.pi/180.0),
448 self.Args[0].CalcDerivative(arg)))
450 def Calc(HIDDEN_self, **args):
451 return math.cos(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
454 class MathTreeFunc1TanD(MathTreeFunc1):
456 def __init__(self, *args):
457 MathTreeFunc1.__init__(self, "tand", *args)
459 def CalcDerivative(self, arg):
460 return MathTreeOpDiv(
461 MathTreeOpMul(
462 MathTreeValConst(math.pi/180.0),
463 self.Args[0].CalcDerivative(arg)),
464 MathTreeOpPow(
465 MathTreeFunc1Cos(self.Args[0]),
466 MathTreeValConst(2.0)))
468 def Calc(HIDDEN_self, **args):
469 return math.tan(math.pi/180.0*HIDDEN_self.Args[0].Calc(**args))
472 class MathTreeFunc1ASinD(MathTreeFunc1):
474 def __init__(self, *args):
475 MathTreeFunc1.__init__(self, "asind", *args)
477 def CalcDerivative(self, arg):
478 return MathTreeOpDiv(
479 MathTreeOpMul(
480 MathTreeValConst(180.0/math.pi),
481 self.Args[0].CalcDerivative(arg)),
482 MathTreeFunc1Sqrt(
483 MathTreeOpSub(
484 MathTreeValConst(1.0),
485 MathTreeOpPow(
486 self.Args[0],
487 MathTreeValConst(2.0)))))
489 def Calc(HIDDEN_self, **args):
490 return 180.0/math.pi*math.asin(HIDDEN_self.Args[0].Calc(**args))
493 class MathTreeFunc1ACosD(MathTreeFunc1):
495 def __init__(self, *args):
496 MathTreeFunc1.__init__(self, "acosd", *args)
498 def CalcDerivate(self, arg):
499 return MathTreeOpDiv(
500 MathTreeFunc1Neg(
501 MathTreeOpMul(
502 MathTreeValConst(180.0/math.pi),
503 self.Args[0].CalcDerivative(arg))),
504 MathTreeFunc1Sqrt(
505 MathTreeOpSub(
506 MathTreeValConst(1.0),
507 MathTreeOpPow(
508 self.Args[0],
509 MathTreeValConst(2.0)))))
511 def Calc(HIDDEN_self, **args):
512 return 180.0/math.pi*math.acos(HIDDEN_self.Args[0].Calc(**args))
515 class MathTreeFunc1ATanD(MathTreeFunc1):
517 def __init__(self, *args):
518 MathTreeFunc1.__init__(self, "atand", *args)
520 def CalcDerivate(self, arg):
521 return MathTreeOpDiv(
522 MathTreeOpMul(
523 MathTreeValConst(180.0/math.pi),
524 self.Args[0].CalcDerivative(arg)),
525 MathTreeOpAdd(
526 MathTreeValConst(1.0),
527 MathTreeOpPow(
528 self.Args[0],
529 MathTreeValConst(2.0))))
531 def Calc(HIDDEN_self, **args):
532 return 180.0/math.pi*math.atan(HIDDEN_self.Args[0].Calc(**args))
535 class MathTreeFunc2(MathTreeFunc):
537 def __init__(self, name, *args):
538 MathTreeFunc.__init__(self, name, 2, *args)
541 class MathTreeFunc2Norm(MathTreeFunc2):
543 def __init__(self, *args):
544 MathTreeFunc2.__init__(self, "norm", *args)
546 def CalcDerivative(self, arg):
547 if self.Args[0].DependOn(arg):
548 if self.Args[1].DependOn(arg):
549 return MathTreeOpDiv(
550 MathTreeOpAdd(
551 MathTreeOpMul(
552 self.Args[0],
553 self.Args[0].CalcDerivative(arg)),
554 MathTreeOpMul(
555 self.Args[1],
556 self.Args[1].CalcDerivative(arg))),
557 self)
558 else:
559 return MathTreeOpDiv(
560 MathTreeOpMul(
561 self.Args[0],
562 self.Args[0].CalcDerivative(arg)),
563 self)
564 else:
565 if self.Args[1].DependOn(arg):
566 return MathTreeOpDiv(
567 MathTreeOpMul(
568 self.Args[1],
569 self.Args[1].CalcDerivative(arg)),
570 self)
572 def Calc(HIDDEN_self, **args):
573 return math.sqrt(HIDDEN_self.Args[0].Calc(**args) ** 2 +
574 HIDDEN_self.Args[1].Calc(**args) ** 2)
577 FuncExternPattern = re.compile(r"([a-z_][a-z0-9_]*)\s*\(", re.IGNORECASE)
579 class MathTreeFuncExtern(MathTreeFunc):
581 def __init__(self, *args):
582 MathTreeFunc.__init__(self, None, -1, *args)
584 def InitByParser(self, arg):
585 Match = arg.MatchPattern(FuncExternPattern)
586 if Match:
587 self.name = Match[:-1].strip()
588 return self.name
590 def SetName(self, arg):
591 self.name = arg.strip()
592 return self
594 def Calc(HIDDEN_self, **args):
595 return args[HIDDEN_self.name](*[arg.Calc(**args) for arg in HIDDEN_self.Args])
598 class MathTreeOp(MathTree):
600 def __init__(self, level, symbol, *args):
601 self.ParenthesisBarrier = 0
602 self.level = level
603 self.symbol = symbol
604 MathTree.__init__(self, 2, *args)
606 def __str__(self):
607 result = ""
608 if isinstance(self.Args[0], MathTreeOp) and\
609 self.level > self.Args[0].level:
610 result = result + "(" + str(self.Args[0]) + ")"
611 else:
612 result = result + str(self.Args[0])
613 result = result + self.symbol
614 if isinstance(self.Args[1], MathTreeOp) and\
615 self.level >= self.Args[1].level:
616 result = result + "(" + str(self.Args[1]) + ")"
617 else:
618 result = result + str(self.Args[1])
619 return result
621 def InitByParser(self, arg):
622 return arg.MatchStr(self.symbol)
625 class MathTreeOpAdd(MathTreeOp):
627 def __init__(self, *args):
628 MathTreeOp.__init__(self, 1, "+", *args)
630 def CalcDerivative(self, arg):
631 if self.Args[0].DependOn(arg):
632 if self.Args[1].DependOn(arg):
633 return MathTreeOpAdd(
634 self.Args[0].CalcDerivative(arg),
635 self.Args[1].CalcDerivative(arg))
636 else:
637 return self.Args[0].CalcDerivative(arg)
638 else:
639 if self.Args[1].DependOn(arg):
640 return self.Args[1].CalcDerivative(arg)
642 def Calc(HIDDEN_self, **args):
643 return HIDDEN_self.Args[0].Calc(**args) + HIDDEN_self.Args[1].Calc(**args)
646 class MathTreeOpSub(MathTreeOp):
648 def __init__(self, *args):
649 MathTreeOp.__init__(self, 1, "-", *args)
651 def CalcDerivative(self, arg):
652 if self.Args[0].DependOn(arg):
653 if self.Args[1].DependOn(arg):
654 return MathTreeOpSub(
655 self.Args[0].CalcDerivative(arg),
656 self.Args[1].CalcDerivative(arg))
657 else:
658 return self.Args[0].CalcDerivative(arg)
659 else:
660 if self.Args[1].DependOn(arg):
661 return MathTreeFunc1Neg(self.Args[1].CalcDerivative(arg))
663 def Calc(HIDDEN_self, **args):
664 return HIDDEN_self.Args[0].Calc(**args) - HIDDEN_self.Args[1].Calc(**args)
667 class MathTreeOpMul(MathTreeOp):
669 def __init__(self, *args):
670 MathTreeOp.__init__(self, 2, "*", *args)
672 def CalcDerivative(self, arg):
673 if self.Args[0].DependOn(arg):
674 if self.Args[1].DependOn(arg):
675 return MathTreeOpAdd(
676 MathTreeOpMul(
677 self.Args[0],
678 self.Args[1].CalcDerivative(arg)),
679 MathTreeOpMul(
680 self.Args[0].CalcDerivative(arg),
681 self.Args[1]))
682 else:
683 return MathTreeOpMul(
684 self.Args[0].CalcDerivative(arg),
685 self.Args[1])
686 else:
687 if self.Args[1].DependOn(arg):
688 return MathTreeOpMul(
689 self.Args[0],
690 self.Args[1].CalcDerivative(arg))
692 def Calc(HIDDEN_self, **args):
693 return HIDDEN_self.Args[0].Calc(**args) * HIDDEN_self.Args[1].Calc(**args)
696 class MathTreeOpDiv(MathTreeOp):
698 def __init__(self, *args):
699 MathTreeOp.__init__(self, 2, "/", *args)
701 def CalcDerivative(self, arg):
702 if self.Args[0].DependOn(arg):
703 if self.Args[1].DependOn(arg):
704 return MathTreeOpMul(
705 MathTreeOpSub(
706 MathTreeOpMul(
707 self.Args[0].CalcDerivative(arg),
708 self.Args[1]),
709 MathTreeOpMul(
710 self.Args[0],
711 self.Args[1].CalcDerivative(arg))),
712 MathTreeOpPow(
713 self.Args[1],
714 MathTreeValConst(-2.0)))
715 else:
716 return MathTreeOpDiv(
717 self.Args[0].CalcDerivative(arg),
718 self.Args[1])
719 else:
720 if self.Args[1].DependOn(arg):
721 return MathTreeOpMul(
722 MathTreeOpMul(
723 MathTreeFunc1Neg(self.Args[0]),
724 MathTreeOpPow(
725 self.Args[1],
726 MathTreeValConst(-2.0))),
727 self.Args[1].CalcDerivative(arg))
729 def Calc(HIDDEN_self, **args):
730 return HIDDEN_self.Args[0].Calc(**args) / HIDDEN_self.Args[1].Calc(**args)
733 class MathTreeOpPow(MathTreeOp):
735 def __init__(self, *args):
736 MathTreeOp.__init__(self, 3, "^", *args)
738 def InitByParser(self, arg):
739 pos = arg.MatchStr("^")
740 if pos:
741 return 1
742 else:
743 return arg.MatchStr("**")
745 def CalcDerivative(self, arg):
746 if self.Args[0].DependOn(arg):
747 if self.Args[1].DependOn(arg):
748 return MathTreeOpMul(
749 MathTreeOpPow(
750 self.Args[0],
751 self.Args[1]),
752 MathTreeOpAdd(
753 MathTreeOpMul(
754 MathTreeFunc1Log(self.Args[0]),
755 self.Args[1].CalcDerivative(arg)),
756 MathTreeOpMul(
757 self.Args[1],
758 MathTreeOpDiv(
759 self.Args[0].CalcDerivative(arg),
760 self.Args[0]))))
761 else:
762 return MathTreeOpMul(
763 self.Args[1],
764 MathTreeOpMul(
765 MathTreeOpPow(
766 self.Args[0],
767 MathTreeOpSub(
768 self.Args[1],
769 MathTreeValConst(1.0))),
770 self.Args[0].CalcDerivative(arg)))
771 else:
772 if self.Args[1].DependOn(arg):
773 return MathTreeOpMul(
774 MathTreeOpMul(
775 MathTreeOpPow(
776 self.Args[0],
777 self.Args[1]),
778 MathTreeFunc1Log(self.Args[0])),
779 self.Args[1].CalcDerivative(arg))
781 def Calc(HIDDEN_self, **args):
782 return HIDDEN_self.Args[0].Calc(**args) ** HIDDEN_self.Args[1].Calc(**args)
786 class UndefinedMathTreeParseError(Exception):
788 def __init__(self, ParseStr, MathTree):
789 self.ParseStr = ParseStr
790 self.MathTree = MathTree
792 def __str__(self):
793 return "\n" + str(self.ParseStr)
796 class RightParenthesisExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
797 class RightParenthesisFoundMathTreeParseError(UndefinedMathTreeParseError): pass
798 class CommaExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
799 class CommaFoundMathTreeParseError(UndefinedMathTreeParseError): pass
800 class OperatorExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
801 class OperandExpectedMathTreeParseError(UndefinedMathTreeParseError): pass
804 DefaultMathTreeOps = (MathTreeOpPow, MathTreeOpDiv, MathTreeOpMul, MathTreeOpSub, MathTreeOpAdd)
805 DefaultMathTreeFuncs = (MathTreeFunc1Neg, MathTreeFunc1Abs, MathTreeFunc1Sgn, MathTreeFunc1Sqrt,
806 MathTreeFunc1Exp, MathTreeFunc1Log,
807 MathTreeFunc1Sin, MathTreeFunc1Cos, MathTreeFunc1Tan,
808 MathTreeFunc1ASin, MathTreeFunc1ACos, MathTreeFunc1ATan,
809 MathTreeFunc1SinD, MathTreeFunc1CosD, MathTreeFunc1TanD,
810 MathTreeFunc1ASinD, MathTreeFunc1ACosD, MathTreeFunc1ATanD,
811 MathTreeFunc2Norm)
813 DefaultMathTreeVals = (MathTreeValConst, MathTreeValVar)
815 class parser:
817 def __init__(self, MathTreeOps=DefaultMathTreeOps,
818 MathTreeFuncs=DefaultMathTreeFuncs,
819 MathTreeVals=DefaultMathTreeVals):
820 self.MathTreeOps = MathTreeOps
821 self.MathTreeFuncs = MathTreeFuncs
822 self.MathTreeVals = MathTreeVals
824 # def parse(self, str):
825 # return self.ParseMathTree(ParseStr(str))
826 def parse(self, str):
827 # prepare raw string:
828 # "^" -> "**"
829 thestr = re.sub("\^","**", str) # to be removed <joergl>
830 thestr = re.sub("\$","_col_", str)
831 return self.astseq2mtree(pythonparser.expr(thestr).totuple())
833 def ParseMathTree(self, arg):
834 Tree = None
835 #Match = arg.MatchPattern(re.compile(r"\s*-(?![0-9\.])"))
836 Match = arg.MatchPattern(re.compile(r"\s*-")) # XXX another quick workaround
837 if Match:
838 #Tree = MathTreeFunc1Neg()
839 Tree = MathTreeOpSub(MathTreeValConst(0)) # XXX quick workaround
840 while 1:
841 i = arg.MatchStr("(")
842 if i:
843 try:
844 self.ParseMathTree(arg)
845 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
846 except RightParenthesisFoundMathTreeParseError, e:
847 if isinstance(e.MathTree, MathTreeOp):
848 e.MathTree.ParenthesisBarrier = 1
849 if Tree is not None:
850 SubTree = Tree # XXX: four lines code dublication
851 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
852 SubTree = SubTree.Args[1]
853 SubTree.AddArg(e.MathTree)
854 else:
855 Tree = e.MathTree
856 else:
857 for FuncClass in self.MathTreeFuncs:
858 Func = FuncClass()
859 if Func.InitByParser(arg):
860 if Tree is not None:
861 SubTree = Tree # XXX: four lines code dublication
862 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
863 SubTree = SubTree.Args[1]
864 SubTree.AddArg(Func)
865 else:
866 Tree = Func
867 while 1:
868 try:
869 self.ParseMathTree(arg)
870 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
871 except CommaFoundMathTreeParseError, e:
872 try:
873 Func.AddArg(e.MathTree, NotLast=1)
874 except ArgCountError:
875 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
876 continue
877 except RightParenthesisFoundMathTreeParseError, e:
878 try:
879 Func.AddArg(e.MathTree, Last=1)
880 except ArgCountError:
881 raise CommaExpectedMathTreeParseError(arg, Tree)
882 break
883 break
884 else:
885 FuncExtern = MathTreeFuncExtern()
886 if FuncExtern.InitByParser(arg):
887 if Tree is not None:
888 SubTree = Tree # XXX: four lines code dublication
889 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
890 SubTree = SubTree.Args[1]
891 SubTree.AddArg(FuncExtern)
892 else:
893 Tree = FuncExtern
894 while 1:
895 try:
896 self.ParseMathTree(arg)
897 raise RightParenthesisExpectedMathTreeParseError(arg, Tree)
898 except CommaFoundMathTreeParseError, e:
899 FuncExtern.AddArg(e.MathTree)
900 continue
901 except RightParenthesisFoundMathTreeParseError, e:
902 FuncExtern.AddArg(e.MathTree)
903 break
904 else:
905 for ValClass in self.MathTreeVals:
906 Val = ValClass()
907 if Val.InitByParser(arg):
908 if Tree is not None:
909 SubTree = Tree # XXX: four lines code dublication
910 while isinstance(SubTree, MathTreeOp) and len(SubTree.Args) == 2:
911 SubTree = SubTree.Args[1]
912 SubTree.AddArg(Val)
913 else:
914 Tree = Val
915 break
916 else:
917 raise OperandExpectedMathTreeParseError(arg, Tree)
918 if arg.AllDone():
919 return Tree
920 i = arg.MatchStr(")")
921 if i:
922 raise RightParenthesisFoundMathTreeParseError(arg, Tree)
923 i = arg.MatchStr(",")
924 if i:
925 raise CommaFoundMathTreeParseError(arg, Tree)
926 for OpClass in self.MathTreeOps:
927 Op = OpClass()
928 if Op.InitByParser(arg):
929 SubTree = Tree
930 SubTreeRoot = None
931 while isinstance(SubTree, MathTreeOp) and\
932 Op.level > SubTree.level and\
933 not SubTree.ParenthesisBarrier:
934 SubTreeRoot = SubTree
935 SubTree = SubTree.Args[1]
936 if SubTreeRoot:
937 Op.AddArg(SubTree)
938 SubTreeRoot.Args[1] = Op
939 else:
940 Op.AddArg(Tree)
941 Tree = Op
942 break
943 else:
944 raise OperatorExpectedMathTreeParseError(arg, Tree)
947 def astseq2mtree(self, astseq, isfunc=0):
948 # astseq has to be a sequence!
949 tree = None
951 if token.ISTERMINAL(astseq[0]):
952 raise Exception("")
954 if astseq[0] == symbol.arith_expr: # {{{
955 try:
956 # 1. arith_expr "PLUS" term
957 if astseq[-2][0] == token.PLUS:
958 tree = MathTreeOpAdd(
959 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
960 self.astseq2mtree(astseq[-1], isfunc=isfunc))
961 # 2. arith_expr "MINUS" term
962 elif astseq[-2][0] == token.MINUS:
963 tree = MathTreeOpSub(
964 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
965 self.astseq2mtree(astseq[-1], isfunc=isfunc))
966 else:
967 raise Exception("")
968 except:
969 # 3. term
970 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
971 return tree # }}}
973 if astseq[0] == symbol.term: # {{{
974 try:
975 # 1. term "STAR" factor
976 if astseq[-2][0] == token.STAR:
977 tree = MathTreeOpMul(
978 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
979 self.astseq2mtree(astseq[-1], isfunc=isfunc))
980 # 2. term "SLASH" factor
981 elif astseq[-2][0] == token.SLASH:
982 tree = MathTreeOpDiv(
983 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
984 self.astseq2mtree(astseq[-1], isfunc=isfunc))
985 else:
986 raise Exception("")
987 except:
988 # 3. factor
989 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
990 return tree # }}}
992 if astseq[0] == symbol.factor: # {{{
993 if len(astseq) == 3:
994 # 1. "PLUS" factor
995 if astseq[1][0] == token.PLUS:
996 tree = self.astseq2mtree(astseq[2], isfunc=isfunc)
997 # 2. "MINUS" factor
998 elif astseq[1][0] == token.MINUS:
999 tree = MathTreeFunc1Neg(self.astseq2mtree(astseq[2], isfunc=isfunc))
1000 else:
1001 raise Exception("unknown factor")
1002 elif len(astseq) == 2:
1003 # 3. power
1004 tree = self.astseq2mtree(astseq[1], isfunc=isfunc)
1005 else:
1006 raise Exception("wrong length of factor")
1007 return tree # }}}
1009 if astseq[0] == symbol.power: # {{{
1010 try:
1011 # 1. "DOUBLESTAR" factor
1012 if astseq[-2][0] == token.DOUBLESTAR:
1013 tree = MathTreeOpPow(
1014 self.astseq2mtree(astseq[:-2], isfunc=isfunc),
1015 self.astseq2mtree(astseq[-1], isfunc=isfunc))
1016 else:
1017 raise Exception("")
1018 except:
1019 # 2. atom + [trailer]
1020 if len(astseq) == 3:
1021 # we have a function call atom + "LPAR" + argumentlist + "RPAR"
1022 if astseq[2][0] != symbol.trailer or \
1023 astseq[2][1][0] != token.LPAR or \
1024 astseq[2][2][0] != symbol.arglist or \
1025 astseq[2][3][0] != token.RPAR:
1026 raise Exception("wrong function call")
1027 tree = self.astseq2mtree(astseq[1], isfunc=1)
1028 for subtree in self.astseq2mtree(astseq[2][2], isfunc=0):
1029 tree.AddArg(subtree)
1030 else:
1031 tree = self.astseq2mtree(astseq[1], isfunc=0)
1033 return tree # }}}
1035 if astseq[0] == symbol.atom: # {{{
1036 # only one nontrivial term:
1037 if len(astseq) == 2:
1038 if astseq[1][0] == token.NUMBER:
1039 # 1. a number
1040 # XXX: for evaluation of brackets we will need integers as well
1041 tree = MathTreeValConst(string.atof(astseq[1][1]))
1042 elif astseq[1][0] == token.NAME:
1043 # 2. a function
1044 if isfunc:
1045 # a known function
1046 for funcclass in self.MathTreeFuncs:
1047 func = funcclass() # ist das guenstig, da jedesmal eine Instanz zu erzeugen?
1048 if func.name == astseq[1][1]:
1049 return func
1050 # an unknown function
1051 tree = MathTreeFuncExtern()
1052 tree.SetName(astseq[1][1])
1053 else:
1054 # 3. a named constant
1055 for const in MathConst.keys():
1056 if const == astseq[1][1]:
1057 return MathTreeValConst(MathConst[const])
1058 # 4. a variable
1059 return MathTreeValVar(astseq[1][1])
1060 elif len(astseq) == 4:
1061 # parentheses or brackets for structuring an atom
1062 if (astseq[1][0] == token.LPAR and astseq[3][0] == token.RPAR) or \
1063 (astseq[1][0] == token.LSQB and astseq[3][0] == token.RSQB):
1064 tree = self.astseq2mtree(astseq[2], isfunc=isfunc)
1065 return tree # }}}
1067 if astseq[0] == symbol.arglist: # {{{
1068 treelist = []
1069 for arg in astseq[1:]:
1070 if arg[0] == token.COMMA:
1071 continue
1072 elif arg[0] == symbol.argument:
1073 treelist.append(self.astseq2mtree(arg, isfunc=isfunc))
1074 return treelist # }}}
1076 return self.astseq2mtree(astseq[1], isfunc=isfunc)