/[escript]/trunk/escript/py_src/util.py
ViewVC logotype

Diff of /trunk/escript/py_src/util.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/esys2/escript/py_src/util.py revision 148 by jgs, Tue Aug 23 01:24:31 2005 UTC trunk/escript/py_src/util.py revision 396 by gross, Wed Dec 21 05:08:25 2005 UTC
# Line 1  Line 1 
1  # $Id$  # $Id$
2    #
3  ## @file util.py  #      COPYRIGHT ACcESS 2004 -  All Rights Reserved
4    #
5    #   This software is the property of ACcESS.  No part of this code
6    #   may be copied in any form or by any means without the expressed written
7    #   consent of ACcESS.  Copying, use or modification of this software
8    #   by any unauthorised person is illegal unless that
9    #   person has a software license agreement with ACcESS.
10    #
11    
12  """  """
13  @brief Utility functions for escript  Utility functions for escript
14    
15  TODO for Data:  @remark:  This module is under construction and is still tested!!!
16    
17    * binary operations @:               (a@b)[:,*]=a[:]@b[:,*] if rank(a)<rank(b)  @var __author__: name of author
18                  @=+,-,*,/,**           (a@b)[:]=a[:]@b[:] if rank(a)=rank(b)  @var __licence__: licence agreement
19                                         (a@b)[*,:]=a[*,:]@b[:] if rank(a)>rank(b)  @var __url__: url entry point on documentation
20      @var __version__: version
21    * implementation of outer outer(a,b)[:,*]=a[:]*b[*]  @var __date__: date of the version
   * trace: trace(arg,axis0=a0,axis1=a1)(:,&,*)=sum_i trace(:,i,&,i,*) (i are at index a0 and a1)  
22  """  """
23                                                                                                                                                                                                        
24    __author__="Lutz Gross, l.gross@uq.edu.au"
25    __licence__="contact: esys@access.uq.edu.au"
26    __url__="http://www.iservo.edu.au/esys/escript"
27    __version__="$Revision$"
28    __date__="$Date$"
29    
30    
31    import math
32  import numarray  import numarray
33  import escript  import escript
34    import os
35    
36    # missing tests:
37    
38    # def pokeShape(arg):
39    # def pokeDim(arg):
40    # def commonShape(arg0,arg1):
41    # def commonDim(*args):
42    # def testForZero(arg):
43    # def matchType(arg0=0.,arg1=0.):
44    # def matchShape(arg0,arg1):
45    
46    # def maximum(arg0,arg1):
47    # def minimum(arg0,arg1):
48    # def clip(arg,minval,maxval)
49    
50    # def transpose(arg,axis=None):
51    # def trace(arg,axis0=0,axis1=1):
52    # def reorderComponents(arg,index):
53    
54    # def integrate(arg,where=None):
55    # def interpolate(arg,where):
56    # def div(arg,where=None):
57    # def grad(arg,where=None):
58    
59    #
60    # slicing: get
61    #          set
62    #
63    # and derivatives
64    
65    #=========================================================
66    #   some helpers:
67    #=========================================================
68    def saveVTK(filename,domain=None,**data):
69        """
70        writes a L{Data} objects into a files using the the VTK XML file format.
71    
72        Example:
73    
74           tmp=Scalar(..)
75           v=Vector(..)
76           saveVTK("solution.xml",temperature=tmp,velovity=v)
77    
78        tmp and v are written into "solution.xml" where tmp is named "temperature" and v is named "velovity"
79    
80        @param filename: file name of the output file
81        @type filename: C{str}
82        @param domain: domain of the L{Data} object. If not specified, the domain of the given L{Data} objects is used.
83        @type domain: L{escript.Domain}
84        @keyword <name>: writes the assigned value to the VTK file using <name> as identifier.
85        @type <name>: L{Data} object.
86        @note: The data objects have to be defined on the same domain. They may not be in the same L{FunctionSpace} but one cannot expect that all L{FunctionSpace} can be mixed. Typically, data on the boundary and data on the interior cannot be mixed.
87        """
88        if domain==None:
89           for i in data.keys():
90              if not data[i].isEmpty(): domain=data[i].getFunctionSpace().getDomain()
91        if domain==None:
92            raise ValueError,"no domain detected."
93        else:
94            domain.saveVTK(filename,data)
95    
96    def saveDX(filename,domain=None,**data):
97        """
98        writes a L{Data} objects into a files using the the DX file format.
99    
100        Example:
101    
102           tmp=Scalar(..)
103           v=Vector(..)
104           saveDX("solution.dx",temperature=tmp,velovity=v)
105    
106        tmp and v are written into "solution.dx" where tmp is named "temperature" and v is named "velovity".
107    
108        @param filename: file name of the output file
109        @type filename: C{str}
110        @param domain: domain of the L{Data} object. If not specified, the domain of the given L{Data} objects is used.
111        @type domain: L{escript.Domain}
112        @keyword <name>: writes the assigned value to the DX file using <name> as identifier. The identifier can be used to select the data set when data are imported into DX.
113        @type <name>: L{Data} object.
114        @note: The data objects have to be defined on the same domain. They may not be in the same L{FunctionSpace} but one cannot expect that all L{FunctionSpace} can be mixed. Typically, data on the boundary and data on the interior cannot be mixed.
115        """
116        if domain==None:
117           for i in data.keys():
118              if not data[i].isEmpty(): domain=data[i].getFunctionSpace().getDomain()
119        if domain==None:
120            raise ValueError,"no domain detected."
121        else:
122            domain.saveDX(filename,data)
123    
124    def kronecker(d=3):
125       """
126       return the kronecker S{delta}-symbol
127    
128       @param d: dimension or an object that has the C{getDim} method defining the dimension
129       @type d: C{int} or any object with a C{getDim} method
130       @return: the object u of rank 2 with M{u[i,j]=1} for M{i=j} and M{u[i,j]=0} otherwise
131       @rtype d: L{numarray.NumArray} of rank 2.
132       @remark: the function is identical L{identity}
133       """
134       return identityTensor(d)
135    
136    def identity(shape=()):
137       """
138       return the shape x shape identity tensor
139    
140       @param shape: input shape for the identity tensor
141       @type shape: C{tuple} of C{int}
142       @return: array of shape shape x shape with M{u[i,k]=1} for M{i=k} and M{u[i,k]=0} otherwise for len(shape)=1 and, for len(shape)=2: M{u[i,j,k,l]=1} for M{i=k and j=l} and M{u[i,j,k,l]=0} otherwise.
143       @rtype: L{numarray.NumArray} of rank 1, rankk 2 or rank 4.
144       @raise ValueError: if len(shape)>2.
145       """
146       if len(shape)>0:
147          out=numarray.zeros(shape+shape,numarray.Float)
148          if len(shape)==1:
149              for i0 in range(shape[0]):
150                 out[i0,i0]=1.
151    
152          elif len(shape)==2:
153              for i0 in range(shape[0]):
154                 for i1 in range(shape[1]):
155                    out[i0,i1,i0,i1]=1.
156          else:
157              raise ValueError,"identity: length of shape is restricted to 2."
158       else:
159          out=1.
160       return out
161    
162    def identityTensor(d=3):
163       """
164       return the dxd identity matrix
165    
166       @param d: dimension or an object that has the C{getDim} method defining the dimension
167       @type d: C{int} or any object with a C{getDim} method
168       @return: the object u of rank 2 with M{u[i,j]=1} for M{i=j} and M{u[i,j]=0} otherwise
169       @rtype: L{numarray.NumArray} of rank 2.
170       """
171       if hasattr(d,"getDim"):
172          d=d.getDim()
173       return identity(shape=(d,))
174    
175    def identityTensor4(d=3):
176       """
177       return the dxdxdxd identity tensor
178    
179       @param d: dimension or an object that has the C{getDim} method defining the dimension
180       @type d: C{int} or any object with a C{getDim} method
181       @return: the object u of rank 4 with M{u[i,j,k,l]=1} for M{i=k and j=l} and M{u[i,j,k,l]=0} otherwise
182       @rtype: L{numarray.NumArray} of rank 4.
183       """
184       if hasattr(d,"getDim"):
185          d=d.getDim()
186       return identity((d,d))
187    
188    def unitVector(i=0,d=3):
189       """
190       return a unit vector u of dimension d with nonzero index i:
191    
192       @param i: index
193       @type i: C{int}
194       @param d: dimension or an object that has the C{getDim} method defining the dimension
195       @type d: C{int} or any object with a C{getDim} method
196       @return: the object u of rank 1 with M{u[j]=1} for M{j=i} and M{u[i]=0} otherwise
197       @rtype: L{numarray.NumArray} of rank 1.
198       """
199       return kronecker(d)[i]
200    
201    #=========================================================================
202    #   global reduction operations (these functions have no symbolic version)
203    #=========================================================================
204    def Lsup(arg):
205        """
206        returns the Lsup-norm of argument arg. This is the maximum absolute value over all data points.
207        This function is equivalent to sup(abs(arg)).
208    
209        @param arg: argument
210        @type arg: C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
211        @return: maximum value of the absolute value of arg over all components and all data points
212        @rtype: C{float}
213        @raise TypeError: if type of arg cannot be processed
214        """
215        if isinstance(arg,numarray.NumArray):
216            return sup(abs(arg))
217        elif isinstance(arg,escript.Data):
218            return arg._Lsup()
219        elif isinstance(arg,float):
220            return abs(arg)
221        elif isinstance(arg,int):
222            return abs(float(arg))
223        else:
224          raise TypeError,"Lsup: Unknown argument type."
225    
226    def sup(arg):
227        """
228        returns the maximum value over all data points.
229    
230        @param arg: argument
231        @type arg: C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
232        @return: maximum value of arg over all components and all data points
233        @rtype: C{float}
234        @raise TypeError: if type of arg cannot be processed
235        """
236        if isinstance(arg,numarray.NumArray):
237            return arg.max()
238        elif isinstance(arg,escript.Data):
239            return arg._sup()
240        elif isinstance(arg,float):
241            return arg
242        elif isinstance(arg,int):
243            return float(arg)
244        else:
245          raise TypeError,"sup: Unknown argument type."
246    
247    def inf(arg):
248        """
249        returns the maximum value over all data points.
250    
251        @param arg: argument
252        @type arg: C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
253        @return : minimum value of arg over all components and all data points
254        @rtype: C{float}
255        @raise TypeError: if type of arg cannot be processed
256        """
257        if isinstance(arg,numarray.NumArray):
258            return arg.min()
259        elif isinstance(arg,escript.Data):
260            return arg._inf()
261        elif isinstance(arg,float):
262            return arg
263        elif isinstance(arg,int):
264            return float(arg)
265        else:
266          raise TypeError,"inf: Unknown argument type."
267    
268    
269    #=========================================================================
270    #   some little helpers
271    #=========================================================================
272    def pokeShape(arg):
273        """
274        identifies the shape of its argument
275    
276        @param arg: a given object
277        @type arg: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, C{Symbol}
278        @return: the shape of the argument
279        @rtype: C{tuple} of C{int}
280        @raise TypeError: if type of arg cannot be processed
281        """
282    
283        if isinstance(arg,numarray.NumArray):
284            return arg.shape
285        elif isinstance(arg,escript.Data):
286            return arg.getShape()
287        elif isinstance(arg,float):
288            return ()
289        elif isinstance(arg,int):
290            return ()
291        elif isinstance(arg,Symbol):
292            return arg.getShape()
293        else:
294          raise TypeError,"pokeShape: cannot identify shape"
295    
296    def pokeDim(arg):
297        """
298        identifies the spatial dimension of its argument
299    
300        @param arg: a given object
301        @type arg: any
302        @return: the spatial dimension of the argument, if available, or C{None}
303        @rtype: C{int} or C{None}
304        """
305    
306        if isinstance(arg,escript.Data):
307            return arg.getFunctionSpace().getDim()
308        elif isinstance(arg,Symbol):
309            return arg.getDim()
310        else:
311            return None
312    
313    def commonShape(arg0,arg1):
314        """
315        returns a shape to which arg0 can be extendent from the right and arg1 can be extended from the left.
316    
317        @param arg0: an object with a shape (see L{pokeShape})
318        @param arg1: an object with a shape (see L{pokeShape})
319        @return: the shape of arg0 or arg1 such that the left port equals the shape of arg0 and the right end equals the shape of arg1.
320        @rtype: C{tuple} of C{int}
321        @raise ValueError: if no shape can be found.
322        """
323        sh0=pokeShape(arg0)
324        sh1=pokeShape(arg1)
325        if len(sh0)<len(sh1):
326           if not sh0==sh1[:len(sh0)]:
327                 raise ValueError,"argument 0 cannot be extended to the shape of argument 1"
328           return sh1
329        elif len(sh0)>len(sh1):
330           if not sh1==sh0[:len(sh1)]:
331                 raise ValueError,"argument 1 cannot be extended to the shape of argument 0"
332           return sh0
333        else:
334           if not sh0==sh1:
335                 raise ValueError,"argument 1 and argument 0 have not the same shape."
336           return sh0
337    
338    def commonDim(*args):
339        """
340        identifies, if possible, the spatial dimension across a set of objects which may or my not have a spatial dimension.
341    
342        @param *args: given objects
343        @return: the spatial dimension of the objects with identifiable dimension (see L{pokeDim}). If none the objects has
344                 a spatial dimension C{None} is returned.
345        @rtype: C{int} or C{None}
346        @raise ValueError: if the objects with identifiable dimension don't have the same spatial dimension.
347        """
348        out=None
349        for a in args:
350           d=pokeDim(a)
351           if not out==None:
352              if not (d==None or out==d):
353                 raise ValueError,"dimension of arguments don't match"
354           else:
355              out=d
356        return out
357    
358    def testForZero(arg):
359        """
360        test the argument for being identical to Zero
361    
362  #===========================================================      @param arg: a given object
363  # a simple tool box to deal with _differentials of functions      @type arg: typically L{numarray.NumArray},L{escript.Data},C{float}, C{int}
364  #===========================================================      @return : True if the argument is identical to zero.
365        @rtype : C{bool}
366  class Symbol:      """
367     """symbol class"""      if isinstance(arg,numarray.NumArray):
368     def __init__(self,name="symbol",shape=(),dim=3,args=[]):         return not Lsup(arg)>0.
369         """creates an instance of a symbol of shape shape and spatial dimension dim      elif isinstance(arg,escript.Data):
370            The symbol may depending on a list of arguments args which         return False
371            may be symbols or other objects. name gives the name of the symbol."""      elif isinstance(arg,float):
372           return not Lsup(arg)>0.
373        elif isinstance(arg,int):
374           return not Lsup(arg)>0.
375        elif isinstance(arg,Symbol):
376           return False
377        else:
378           return False
379    
380    def matchType(arg0=0.,arg1=0.):
381        """
382        converting arg0 and arg1 both to the same type L{numarray.NumArray} or L{escript.Data} or, if one of arg0 or arg1 is of type L{Symbol}, the other one to be of type L{numarray.NumArray} or L{escript.Data}.
383    
384        @param arg0: first argument
385        @type arg0: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, C{Symbol}
386        @param arg1: second argument
387        @type arg1: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, C{Symbol}
388        @return: a tuple representing arg0 and arg1 with the same type or with one of them being a L{Symbol}
389        @rtype: C{tuple} of two L{numarray.NumArray}, two L{escript.Data}, a C{Symbol} and one of the types L{numarray.NumArray} or L{escript.Data}.  
390        @raise TypeError: if type of arg0 or arg1 cannot be processed
391        """
392        if isinstance(arg0,numarray.NumArray):
393           if isinstance(arg1,numarray.NumArray):
394              pass
395           elif isinstance(arg1,escript.Data):
396              arg0=escript.Data(arg0,arg1.getFunctionSpace())
397           elif isinstance(arg1,float):
398              arg1=numarray.array(arg1)
399           elif isinstance(arg1,int):
400              arg1=numarray.array(float(arg1))
401           elif isinstance(arg1,Symbol):
402              pass
403           else:
404              raise TypeError,"function: Unknown type of second argument."    
405        elif isinstance(arg0,escript.Data):
406           if isinstance(arg1,numarray.NumArray):
407              arg1=escript.Data(arg1,arg0.getFunctionSpace())
408           elif isinstance(arg1,escript.Data):
409              pass
410           elif isinstance(arg1,float):
411              arg1=escript.Data(arg1,(),arg0.getFunctionSpace())
412           elif isinstance(arg1,int):
413              arg1=escript.Data(float(arg1),(),arg0.getFunctionSpace())
414           elif isinstance(arg1,Symbol):
415              pass
416           else:
417              raise TypeError,"function: Unknown type of second argument."    
418        elif isinstance(arg0,Symbol):
419           if isinstance(arg1,numarray.NumArray):
420              pass
421           elif isinstance(arg1,escript.Data):
422              pass
423           elif isinstance(arg1,float):
424              arg1=numarray.array(arg1)
425           elif isinstance(arg1,int):
426              arg1=numarray.array(float(arg1))
427           elif isinstance(arg1,Symbol):
428              pass
429           else:
430              raise TypeError,"function: Unknown type of second argument."    
431        elif isinstance(arg0,float):
432           if isinstance(arg1,numarray.NumArray):
433              arg0=numarray.array(arg0)
434           elif isinstance(arg1,escript.Data):
435              arg0=escript.Data(arg0,arg1.getFunctionSpace())
436           elif isinstance(arg1,float):
437              arg0=numarray.array(arg0)
438              arg1=numarray.array(arg1)
439           elif isinstance(arg1,int):
440              arg0=numarray.array(arg0)
441              arg1=numarray.array(float(arg1))
442           elif isinstance(arg1,Symbol):
443              arg0=numarray.array(arg0)
444           else:
445              raise TypeError,"function: Unknown type of second argument."    
446        elif isinstance(arg0,int):
447           if isinstance(arg1,numarray.NumArray):
448              arg0=numarray.array(float(arg0))
449           elif isinstance(arg1,escript.Data):
450              arg0=escript.Data(float(arg0),arg1.getFunctionSpace())
451           elif isinstance(arg1,float):
452              arg0=numarray.array(float(arg0))
453              arg1=numarray.array(arg1)
454           elif isinstance(arg1,int):
455              arg0=numarray.array(float(arg0))
456              arg1=numarray.array(float(arg1))
457           elif isinstance(arg1,Symbol):
458              arg0=numarray.array(float(arg0))
459           else:
460              raise TypeError,"function: Unknown type of second argument."    
461        else:
462          raise TypeError,"function: Unknown type of first argument."    
463    
464        return arg0,arg1
465    
466    def matchShape(arg0,arg1):
467        """
468        
469    
470        If shape is not given the shape "largest" shape of args is used.
471    
472        @param args: a given ob
473        @type arg: typically L{numarray.NumArray},L{escript.Data},C{float}, C{int}
474        @return: True if the argument is identical to zero.
475        @rtype: C{list} of C{int}
476        """
477        sh=commonShape(arg0,arg1)
478        sh0=pokeShape(arg0)
479        sh1=pokeShape(arg1)
480        if len(sh0)<len(sh):
481           return outer(arg0,numarray.ones(sh[len(sh0):],numarray.Float)),arg1
482        elif len(sh1)<len(sh):
483           return arg0,outer(arg1,numarray.ones(sh[len(sh1):],numarray.Float))
484        else:
485           return arg0,arg1
486    #=========================================================
487    #   symbolic tool box starts here:
488    #=========================================================
489    class Symbol(object):
490       """
491       Symbol class.
492    
493       Symbol class objects provide the same functionality as L{numarray.NumArray} and L{escript.Data} objects
494       but they do not have a value and therefore cannot be plotted or visualize. The main purpose is the possibilty
495       calculate derivatives with respect to other Symbols used to define a Symbol.
496    
497       """
498       def __init__(self,shape=(),args=[],dim=None):
499           """
500           Creates an instance of a symbol of a given shape. The symbol may depending on a list of arguments args which may be
501           symbols or any other object.
502    
503           @param arg: the arguments of the symbol.
504           @type arg: C{list}
505           @param shape: the shape
506           @type shape: C{tuple} of C{int}
507           @param dim: spatial dimension of the symbol. If dim=C{None} the spatial dimension is undefined.  
508           @type dim: C{None} or C{int}  
509    
510           """
511           if len(shape)>4:
512               raise ValueError,"Symbol supports only tensors up to order 4"
513         self.__args=args         self.__args=args
        self.__name=name  
514         self.__shape=shape         self.__shape=shape
515         if hasattr(dim,"getDim"):         self.__dim=dim
            self.__dim=dim.getDim()  
        else:      
            self.__dim=dim  
        #  
        self.__cache_val=None  
        self.__cache_argval=None  
   
    def getArgument(self,i):  
        """returns the i-th argument"""  
        return self.__args[i]  
516    
517     def getDim(self):     def getArgument(self,i=None):
518         """returns the spatial dimension of the symbol"""         """
519         return self.__dim         returns the i-th argument of the symbol
520    
521           @param i: index of the argument requested.
522           @type i: C{int} or C{None}
523           @raise IndexError: if the requested index does not exist
524           @return: the vlaue of the i-th argument or i is not specified the list of all arguments.
525           @rtype: a single object or a list of objects
526           """
527           if i==None:
528              return self.__args
529           else:
530              if i<0 or i>=len(self.__args):
531                 raise IndexError,"there are only %s arguments"%len(self.__args)
532              return self.__args[i]
533    
534     def getRank(self):     def getRank(self):
535         """returns the rank of the symbol"""         """
536           the rank of the symbol
537    
538           @return: the rank of the symbol. This is length of the shape
539           @rtype: C{int}
540           """
541         return len(self.getShape())         return len(self.getShape())
542    
543     def getShape(self):     def getShape(self):
544         """returns the shape of the symbol"""         """
545           the shape of the symbol.
546    
547           @return : the shape of the symbol.
548           @rtype: C{tuple} of C{int}
549           """
550         return self.__shape         return self.__shape
551    
552     def getEvaluatedArguments(self,argval):     def getDim(self):
553         """returns the list of evaluated arguments by subsituting symbol u by argval[u]."""         """
554         if argval==self.__cache_argval:         the spatial dimension
555             print "%s: cached value used"%self  
556             return self.__cache_val         @return : the spatial dimension
557         else:         @rtype: C{int} if the dimension is defined. Otherwise C{None} is returned.
558             out=[]         """
559             for a  in self.__args:         return self.__dim
560                if isinstance(a,Symbol):    
561                  out.append(a.eval(argval))     def __str__(self):
562                else:         """
563                  out.append(a)         a string representation of the symbol.
564             self.__cache_argval=argval         @return: a string representation of the object
565             self.__cache_val=out         @rtype: C{str}
566             return out         """
567           args=[]
568           for arg in self.getArgument():
569              args.append(str(arg))
570           try:
571               out=self.getMyCode(args,format="str")
572           except NotImplementedError:
573               out="<Symbol %s>"%id(self)
574           return out
575          
576       def getSubstitutedArguments(self,argvals):
577           """
578           substitutes symbols in the arguments of this object and returns the result as a list.
579    
580           @param argvals: L{Symbols} and their substitutes. The L{Symbol} u in the expression defining this object is replaced by argvals[u].
581           @type argvals: C{dict} with keywords of type L{Symbol}.
582           @rtype: C{list} of objects
583           @return: list of the object assigned to the arguments through substitution or for the arguments which are not L{Symbols} the value assigned to the argument at instantiation.
584           """
585           out=[]
586           for a in self.getArgument():
587              if isinstance(a,Symbol):
588                 out.append(a.substitute(argvals))
589              else:
590                 out.append(a)
591           return out
592    
593     def getDifferentiatedArguments(self,arg):     def getDifferentiatedArguments(self,arg):
594         """returns the list of the arguments _differentiated by arg"""         """
595           applifies differentials to the arguments of this object and returns the result as a list.
596    
597           @param arg: the derivative is calculated with respect to arg
598           @type arg: typically L{escript.Symbol} but can also be C{float}, L{escript.Data}, L{numarray.NumArray} depending the involved functions and data.
599           @rtype: C{list} of objects
600           @return: list of object obtained by calculating the derivatives of the argumenst with respct to arg
601           """
602         out=[]         out=[]
603         for a in self.__args:         for a in self.getArgument():
604            if isinstance(a,Symbol):            if isinstance(a,Symbol):
605              out.append(a.diff(arg))               out.append(a.substitute(argvals))
606            else:            else:
607              out.append(0)                s=pokeShape(s)+arg.getShape()
608                  if len(s)>0:
609                     out.append(numarray.zeros(s),numarray.Float)
610                  else:
611                     out.append(a)
612         return out         return out
613    
614     def diff(self,arg):     def isAppropriateValue(self,arg):
615         """returns the _differention of self by arg."""        """
616         if self==arg:        checks if the given argument arg can be used as a substitution of this object. The method checks
617            out=numarray.zeros(tuple(2*list(self.getShape())),numarray.Float)        the shape of arg and, if the spatial dimension is defined, the spatial dimension of arg.    
618            if self.getRank()==0:  
619               out=1.        @param arg: a given object
620            elif self.getRank()==1:        @type arg: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, C{Symbol}
621                for i0 in range(self.getShape()[0]):        @return: True if arg is a suitbale object to be used for substitution. Otherwise False is returned.
622                   out[i0,i0]=1.          @rtype: C{bool}
623            elif self.getRank()==2:        """
624                for i0 in range(self.getShape()[0]):        if isinstance(arg,numarray.NumArray):
625                  for i1 in range(self.getShape()[1]):            return arg.shape==self.getShape()
626                       out[i0,i1,i0,i1]=1.          elif isinstance(arg,escript.Data):
627            elif self.getRank()==3:            if self.getDim()==None:
628                for i0 in range(self.getShape()[0]):                return arg.getShape()==self.getShape()
629                  for i1 in range(self.getShape()[1]):            elif self.getDim()==arg.getFunctionSpace().getDim():
630                    for i2 in range(self.getShape()[2]):                return arg.getShape()==self.getShape()
                      out[i0,i1,i2,i0,i1,i2]=1.    
           elif self.getRank()==4:  
               for i0 in range(self.getShape()[0]):  
                 for i1 in range(self.getShape()[1]):  
                   for i2 in range(self.getShape()[2]):  
                     for i3 in range(self.getShape()[3]):  
                        out[i0,i1,i2,i3,i0,i1,i2,i3]=1.    
631            else:            else:
632               raise ValueError,"differential support rank<5 only."                return False
633            return out        elif isinstance(arg,Symbol):
634         else:            if self.getDim()==None:
635            return self._diff(arg)                return arg.getShape()==self.getShape()
636              elif self.getDim()==arg.getDim():
637                  return arg.getShape()==self.getShape()
638              else:
639                  return False
640          elif isinstance(arg,float):
641              return ()==self.getShape()
642          elif isinstance(arg,int):
643              return ()==self.getShape()
644          else:
645             return False
646    
647     def _diff(self,arg):     def getMyCode(self,argstrs,format="escript"):
648         """return derivate of self with respect to arg (!=self).         """
649            This method is overwritten by a particular symbol"""         returns a program code that can be used to evaluate the symbol.
650         return 0  
651           @param argstrs: gives for each argument a string representing the argument for the evaluation.
652     def eval(self,argval):         @type argstrs: C{list} of C{str}.
653         """subsitutes symbol u in self by argval[u] and returns the result. If         @param format: specifies the format to be used. At the moment only "escript", "str" and "text" are supported.
654            self is not a key of argval then self is returned."""         @type format: C{str}
655         if argval.has_key(self):         @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
656           return argval[self]         @rtype: C{str}
657         else:         @raise NotImplementedError: if no implementation for the given format is available
658           return self         @note: This method has to be overwritten by subclasses.
659           """
660           raise NotImplementedError,"no code for %s representation available"%format
661    
662       def substitute(self,argvals):
663          """  
664          assigns new values to symbols in the definition of the symbol.
665          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
666    
667          @param argvals: new values assigned to symbols
668          @type argvals: C{dict} with keywords of type L{Symbol}.
669          @return: result of the substitution process. Operations are executed as much as possible.
670          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
671          @note: this method has to be overwritten by a particular L{Symbol}
672          @raise NotImplementedError: if no implementation for the given format is available
673          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
674          """
675          if argvals.has_key(self):
676             arg=argvals[self]
677             if self.isAppropriateValue(arg):
678                return arg
679             else:
680                raise TypeError,"Symbol: new value is not appropriate."
681          else:
682             raise NotImplementedError,"no substitution in %s avialable"%str(self)
683    
684     def __str__(self):     def diff(self,arg):
685         """returns a string representation of the symbol"""         """
686         return self.__name         returns the derivative of the symbol with respect to L{Symbol} arg
687    
688     def __add__(self,other):         @param arg: the derivative is calculated with respect to arg
689         """adds other to symbol self. if _testForZero(other) self is returned."""         @type arg: typically L{escript.Symbol} but can also be C{float}, L{escript.Data}, L{numarray.NumArray} depending the involved functions and data.
690         if _testForZero(other):         @return: derivative with respect to C{arg}
691            return self         @rtype: typically L{escript.Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
692           @note: this method is overwritten by a particular L{Symbol}
693           """
694           if arg==self:
695              return identity(self.getShape())
696         else:         else:
697            a=_matchShape([self,other])            s=self.getShape()+arg.getShape()
698            return Add_Symbol(a[0],a[1])            if len(s)>0:
699                 return numarray.zeros(s,numarray.Float)
700     def __radd__(self,other):            else:
701         """adds other to symbol self. if _testForZero(other) self is returned."""               return 0.
        return self+other  
702    
703     def __neg__(self):     def __neg__(self):
704         """returns -self."""         """
705           returns -self.
706    
707           @return:  a S{Symbol} representing the negative of the object
708           @rtype: L{DependendSymbol}
709           """
710         return self*(-1.)         return self*(-1.)
711    
712     def __pos__(self):     def __pos__(self):
713         """returns +self."""         """
714         return self         returns +self.
715    
716           @return:  a S{Symbol} representing the positive of the object
717           @rtype: L{DependendSymbol}
718           """
719           return self*(1.)
720    
721     def __abs__(self):     def __abs__(self):
722         """returns absolute value"""         """
723           returns a S{Symbol} representing the absolute value of the object.
724           """
725         return Abs_Symbol(self)         return Abs_Symbol(self)
726    
727       def __add__(self,other):
728           """
729           add another object to this object
730    
731           @param other: object to be added to this object
732           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
733           @return:  a S{Symbol} representing the sum of this object and C{other}
734           @rtype: L{DependendSymbol}
735           """
736           return add(self,other)
737    
738       def __radd__(self,other):
739           """
740           add this object to another object
741    
742           @param other: object this object is added to
743           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
744           @return: a S{Symbol} representing the sum of C{other} and this object object
745           @rtype: L{DependendSymbol}
746           """
747           return add(other,self)
748    
749     def __sub__(self,other):     def __sub__(self,other):
750         """subtracts other from symbol self. if _testForZero(other) self is returned."""         """
751         if _testForZero(other):         subtracts another object from this object
752            return self  
753         else:         @param other: object to be subtracted from this object
754            return self+(-other)         @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
755           @return: a S{Symbol} representing the difference of C{other} and this object
756           @rtype: L{DependendSymbol}
757           """
758           return add(self,-other)
759    
760     def __rsub__(self,other):     def __rsub__(self,other):
761         """subtracts symbol self from other."""         """
762         return -self+other         subtracts this object from another object
763    
764           @param other: object this object is been subtracted from
765           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
766           @return: a S{Symbol} representing the difference of this object and C{other}.
767           @rtype: L{DependendSymbol}
768           """
769           return add(-self,other)
770    
771       def __mul__(self,other):
772           """
773           multiplies this object with other object
774    
775           @param other: object to be mutiplied by this object
776           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
777           @return: a S{Symbol} representing the product of the object and C{other}.
778           @rtype: L{DependendSymbol} or 0 if other is identical to zero.
779           """
780           return mult(self,other)
781    
782       def __rmul__(self,other):
783           """
784           multiplies this object with other object
785    
786           @param other: object this object is multiplied with
787           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
788           @return: a S{Symbol} representing the product of C{other} and the object.
789           @rtype: L{DependendSymbol} or 0 if other is identical to zero.
790           """
791           return mult(other,self)
792    
793     def __div__(self,other):     def __div__(self,other):
794         """divides symbol self by other."""         """
795         if isinstance(other,Symbol):         divides this object by other object
796            a=_matchShape([self,other])  
797            return Div_Symbol(a[0],a[1])         @param other: object dividing this object
798         else:         @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
799            return self*(1./other)         @return: a S{Symbol} representing the quotient of this object and C{other}
800           @rtype: L{DependendSymbol}
801           """
802           return quotient(self,other)
803    
804     def __rdiv__(self,other):     def __rdiv__(self,other):
805         """dived other by symbol self. if _testForZero(other) 0 is returned."""         """
806         if _testForZero(other):         divides this object by other object
807            return 0  
808         else:         @param other: object dividing this object
809            a=_matchShape([self,other])         @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
810            return Div_Symbol(a[0],a[1])         @return: a S{Symbol} representing the quotient of C{other} and this object
811           @rtype: L{DependendSymbol} or 0 if C{other} is identical to zero.
812           """
813           return quotient(other,self)
814    
815     def __pow__(self,other):     def __pow__(self,other):
816         """raises symbol self to the power of other"""         """
817         a=_matchShape([self,other])         raises this object to the power of other
818         return Power_Symbol(a[0],a[1])  
819           @param other: exponent
820           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
821           @return: a S{Symbol} representing the power of this object to C{other}
822           @rtype: L{DependendSymbol} or 1 if C{other} is identical to zero.
823           """
824           return power(self,other)
825    
826     def __rpow__(self,other):     def __rpow__(self,other):
827         """raises other to the symbol self"""         """
828         a=_matchShape([self,other])         raises an object to the power of this object
        return Power_Symbol(a[1],a[0])  
829    
830     def __mul__(self,other):         @param other: basis
831         """multiplies other by symbol self. if _testForZero(other) 0 is returned."""         @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
832         if _testForZero(other):         @return: a S{Symbol} representing the power of C{other} to this object
833            return 0         @rtype: L{DependendSymbol} or 0 if C{other} is identical to zero.
834         else:         """
835            a=_matchShape([self,other])         return power(other,self)
           return Mult_Symbol(a[0],a[1])  
836    
837     def __rmul__(self,other):  class DependendSymbol(Symbol):
838         """multiplies other by symbol self. if _testSForZero(other) 0 is returned."""     """
839         return self*other     DependendSymbol extents L{Symbol} by modifying the == operator to allow two instances to be equal.
840       Two DependendSymbol are equal if they have the same shape, the same arguments and one of them has an unspecified spatial dimension or the spatial dimension is identical  
841      
842       Example:
843      
844       u1=Symbol(shape=(3,4),dim=2,args=[4.])
845       u2=Symbol(shape=(3,4),dim=2,args=[4.])
846       print u1==u2
847       False
848      
849          but  
850    
851     def __getitem__(self,sl):     u1=DependendSymbol(shape=(3,4),dim=2,args=[4.])
852            print sl     u2=DependendSymbol(shape=(3,4),dim=2,args=[4.])
853       u3=DependendSymbol(shape=(2,),dim=2,args=[4.])  
854       print u1==u2, u1==u3
855       True False
856    
857  def Float_Symbol(Symbol):     @note: DependendSymbol should be used as return value of functions with L{Symbol} arguments. This will allow the optimizer to remove redundant function calls.
858      def __init__(self,name="symbol",shape=(),args=[]):     """
859          Symbol.__init__(self,dim=0,name="symbol",shape=(),args=[])     def __eq__(self,other):
860          """
861  class ScalarSymbol(Symbol):        checks if other equals self
862     """a scalar symbol"""  
863     def __init__(self,dim=3,name="scalar"):        @param other: any object
864        """creates a scalar symbol of spatial dimension dim"""        @return: True if other has the same class like self, and the shape, the spatial diemsnion and the arguments are equal.
865        if hasattr(dim,"getDim"):        @rtype: C{bool}
866             d=dim.getDim()        """
867        else:            if isinstance(other,DependendSymbol):
868             d=dim           if self.__class__==other.__class__:  
869        Symbol.__init__(self,shape=(),dim=d,name=name)              if self.getShape()==other.getShape():
870                  if self.getArgument()==other.getArgument():
871  class VectorSymbol(Symbol):                   if self.getDim()==None or other.getDim()==None or self.getDim()==other.getDim():
872     """a vector symbol"""                      return True
873     def __init__(self,dim=3,name="vector"):        return False
       """creates a vector symbol of spatial dimension dim"""  
       if hasattr(dim,"getDim"):  
            d=dim.getDim()  
       else:      
            d=dim  
       Symbol.__init__(self,shape=(d,),dim=d,name=name)  
   
 class TensorSymbol(Symbol):  
    """a tensor symbol"""  
    def __init__(self,dim=3,name="tensor"):  
       """creates a tensor symbol of spatial dimension dim"""  
       if hasattr(dim,"getDim"):  
            d=dim.getDim()  
       else:      
            d=dim  
       Symbol.__init__(self,shape=(d,d),dim=d,name=name)  
   
 class Tensor3Symbol(Symbol):  
    """a tensor order 3 symbol"""  
    def __init__(self,dim=3,name="tensor3"):  
       """creates a tensor order 3 symbol of spatial dimension dim"""  
       if hasattr(dim,"getDim"):  
            d=dim.getDim()  
       else:      
            d=dim  
       Symbol.__init__(self,shape=(d,d,d),dim=d,name=name)  
   
 class Tensor4Symbol(Symbol):  
    """a tensor order 4 symbol"""  
    def __init__(self,dim=3,name="tensor4"):  
       """creates a tensor order 4 symbol of spatial dimension dim"""      
       if hasattr(dim,"getDim"):  
            d=dim.getDim()  
       else:      
            d=dim  
       Symbol.__init__(self,shape=(d,d,d,d),dim=d,name=name)  
874    
875  class Add_Symbol(Symbol):     def __ne__(self,other):
876     """symbol representing the sum of two arguments"""        """
877     def __init__(self,arg0,arg1):        checks if other equals self
878         a=[arg0,arg1]  
879         Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)        @param other: any object
880     def __str__(self):        @return: Flase if other has the same class like self, and the shape, the spatial diemsnion and the arguments are equal.
881        return "(%s+%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))        @rtype: C{bool}
882     def eval(self,argval):        """
883         a=self.getEvaluatedArguments(argval)        return not self==other
884         return a[0]+a[1]  #=========================================================
885     def _diff(self,arg):  #  Unary operations prserving the shape
886         a=self.getDifferentiatedArguments(arg)  #========================================================
887         return a[0]+a[1]  def log10(arg):
888       """
889       returns base-10 logarithm of argument arg
890    
891  class Mult_Symbol(Symbol):     @param arg: argument
892     """symbol representing the product of two arguments"""     @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
893     def __init__(self,arg0,arg1):     @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
894         a=[arg0,arg1]     @raises TypeError: if the type of the argument is not expected.
895         Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)     """
896     def __str__(self):     if isinstance(arg,numarray.NumArray):
897        return "(%s*%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))        return numarray.log10(arg)
898     def eval(self,argval):     elif isinstance(arg,escript.Data):
899         a=self.getEvaluatedArguments(argval)        return arg._log10()
900         return a[0]*a[1]     elif isinstance(arg,float):
901     def _diff(self,arg):        return math.log10(arg)
902         a=self.getDifferentiatedArguments(arg)     elif isinstance(arg,int):
903         return self.getArgument(1)*a[0]+self.getArgument(0)*a[1]        return math.log10(float(arg))
904       elif isinstance(arg,Symbol):
905          return log(arg)/log(10.)
906       else:
907          raise TypeError,"log10: Unknown argument type."
908    
909  class Div_Symbol(Symbol):  def wherePositive(arg):
910     """symbol representing the quotient of two arguments"""     """
911     def __init__(self,arg0,arg1):     returns mask of positive values of argument arg
        a=[arg0,arg1]  
        Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)  
    def __str__(self):  
       return "(%s/%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))  
    def eval(self,argval):  
        a=self.getEvaluatedArguments(argval)  
        return a[0]/a[1]  
    def _diff(self,arg):  
        a=self.getDifferentiatedArguments(arg)  
        return (a[0]*self.getArgument(1)-self.getArgument(0)*a[1])/ \  
                           (self.getArgument(1)*self.getArgument(1))  
912    
913  class Power_Symbol(Symbol):     @param arg: argument
914     """symbol representing the power of the first argument to the power of the second argument"""     @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
915     def __init__(self,arg0,arg1):     @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
916         a=[arg0,arg1]     @raises TypeError: if the type of the argument is not expected.
917         Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)     """
918     def __str__(self):     if isinstance(arg,numarray.NumArray):
919        return "(%s**%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))        out=numarray.greater(arg,numarray.zeros(arg.shape,numarray.Float))
920     def eval(self,argval):        if isinstance(out,float): out=numarray.array(out)
921         a=self.getEvaluatedArguments(argval)        return out
922         return a[0]**a[1]     elif isinstance(arg,escript.Data):
923     def _diff(self,arg):        return arg._wherePositive()
924         a=self.getDifferentiatedArguments(arg)     elif isinstance(arg,float):
925         return self*(a[1]*log(self.getArgument(0))+self.getArgument(1)/self.getArgument(0)*a[0])        if arg>0:
926            return 1.
927          else:
928            return 0.
929       elif isinstance(arg,int):
930          if arg>0:
931            return 1.
932          else:
933            return 0.
934       elif isinstance(arg,Symbol):
935          return WherePositive_Symbol(arg)
936       else:
937          raise TypeError,"wherePositive: Unknown argument type."
938    
939  class Abs_Symbol(Symbol):  class WherePositive_Symbol(DependendSymbol):
940     """symbol representing absolute value of its argument"""     """
941       L{Symbol} representing the result of the mask of positive values function
942       """
943     def __init__(self,arg):     def __init__(self,arg):
944         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
945     def __str__(self):        initialization of wherePositive L{Symbol} with argument arg
946        return "abs(%s)"%str(self.getArgument(0))        @param arg: argument of function
947     def eval(self,argval):        @type arg: typically L{Symbol}.
948         return abs(self.getEvaluatedArguments(argval)[0])        """
949     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
950         return sign(self.getArgument(0))*self.getDifferentiatedArguments(arg)[0]  
951       def getMyCode(self,argstrs,format="escript"):
952          """
953          returns a program code that can be used to evaluate the symbol.
954    
955          @param argstrs: gives for each argument a string representing the argument for the evaluation.
956          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
957          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
958          @type format: C{str}
959          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
960          @rtype: C{str}
961          @raise: NotImplementedError: if the requested format is not available
962          """
963          if isinstance(argstrs,list):
964              argstrs=argstrs[0]
965          if format=="escript" or format=="str"  or format=="text":
966             return "wherePositive(%s)"%argstrs
967          else:
968             raise NotImplementedError,"WherePositive_Symbol does not provide program code for format %s."%format
969    
970  #=========================================================     def substitute(self,argvals):
971  #   some little helpers        """
972  #=========================================================        assigns new values to symbols in the definition of the symbol.
973  def _testForZero(arg):        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
974     """returns True is arg is considered of being zero"""  
975     if isinstance(arg,int):        @param argvals: new values assigned to symbols
976        return not arg>0        @type argvals: C{dict} with keywords of type L{Symbol}.
977     elif isinstance(arg,float):        @return: result of the substitution process. Operations are executed as much as possible.
978        return not arg>0.        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
979     elif isinstance(arg,numarray.NumArray):        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
980        a=abs(arg)        """
981        while isinstance(a,numarray.NumArray): a=numarray.sometrue(a)        if argvals.has_key(self):
982        return not a>0           arg=argvals[self]
983             if self.isAppropriateValue(arg):
984                return arg
985             else:
986                raise TypeError,"%s: new value is not appropriate."%str(self)
987          else:
988             arg=self.getSubstitutedArguments(argvals)[0]
989             return wherePositive(arg)
990    
991    def whereNegative(arg):
992       """
993       returns mask of positive values of argument arg
994    
995       @param arg: argument
996       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
997       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
998       @raises TypeError: if the type of the argument is not expected.
999       """
1000       if isinstance(arg,numarray.NumArray):
1001          out=numarray.less(arg,numarray.zeros(arg.shape,numarray.Float))
1002          if isinstance(out,float): out=numarray.array(out)
1003          return out
1004       elif isinstance(arg,escript.Data):
1005          return arg._whereNegative()
1006       elif isinstance(arg,float):
1007          if arg<0:
1008            return 1.
1009          else:
1010            return 0.
1011       elif isinstance(arg,int):
1012          if arg<0:
1013            return 1.
1014          else:
1015            return 0.
1016       elif isinstance(arg,Symbol):
1017          return WhereNegative_Symbol(arg)
1018     else:     else:
1019        return False        raise TypeError,"whereNegative: Unknown argument type."
1020    
1021  def _extractDim(args):  class WhereNegative_Symbol(DependendSymbol):
1022      dim=None     """
1023      for a in args:     L{Symbol} representing the result of the mask of positive values function
1024         if hasattr(a,"getDim"):     """
1025            d=a.getDim()     def __init__(self,arg):
1026            if dim==None:        """
1027               dim=d        initialization of whereNegative L{Symbol} with argument arg
1028            else:        @param arg: argument of function
1029               if dim!=d: raise ValueError,"inconsistent spatial dimension of arguments"        @type arg: typically L{Symbol}.
1030      if dim==None:        """
1031         raise ValueError,"cannot recover spatial dimension"        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1032      return dim  
1033       def getMyCode(self,argstrs,format="escript"):
1034  def _identifyShape(arg):        """
1035     """identifies the shape of arg."""        returns a program code that can be used to evaluate the symbol.
1036     if hasattr(arg,"getShape"):  
1037         arg_shape=arg.getShape()        @param argstrs: gives for each argument a string representing the argument for the evaluation.
1038     elif hasattr(arg,"shape"):        @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1039       s=arg.shape        @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1040       if callable(s):        @type format: C{str}
1041         arg_shape=s()        @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1042       else:        @rtype: C{str}
1043         arg_shape=s        @raise: NotImplementedError: if the requested format is not available
1044     else:        """
1045         arg_shape=()        if isinstance(argstrs,list):
1046     return arg_shape            argstrs=argstrs[0]
1047          if format=="escript" or format=="str"  or format=="text":
1048  def _extractShape(args):           return "whereNegative(%s)"%argstrs
1049      """extracts the common shape of the list of arguments args"""        else:
1050      shape=None           raise NotImplementedError,"WhereNegative_Symbol does not provide program code for format %s."%format
     for a in args:  
        a_shape=_identifyShape(a)  
        if shape==None: shape=a_shape  
        if shape!=a_shape: raise ValueError,"inconsistent shape"  
     if shape==None:  
        raise ValueError,"cannot recover shape"  
     return shape  
   
 def _matchShape(args,shape=None):  
     """returns the list of arguments args as object which have all the specified shape.  
        if shape is not given the shape "largest" shape of args is used."""  
     # identify the list of shapes:  
     arg_shapes=[]  
     for a in args: arg_shapes.append(_identifyShape(a))  
     # get the largest shape (currently the longest shape):  
     if shape==None: shape=max(arg_shapes)  
       
     out=[]  
     for i in range(len(args)):  
        if shape==arg_shapes[i]:  
           out.append(args[i])  
        else:  
           if len(shape)==0: # then len(arg_shapes[i])>0  
             raise ValueError,"cannot adopt shape of %s to %s"%(str(args[i]),str(shape))  
           else:  
             if len(arg_shapes[i])==0:  
                 out.append(outer(args[i],numarray.ones(shape)))          
             else:    
                 raise ValueError,"cannot adopt shape of %s to %s"%(str(args[i]),str(shape))  
     return out    
1051    
1052  #=========================================================     def substitute(self,argvals):
1053  #   wrappers for various mathematical functions:        """
1054  #=========================================================        assigns new values to symbols in the definition of the symbol.
1055  def diff(arg,dep):        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1056      """returns the derivative of arg with respect to dep. If arg is not Symbol object  
1057         0 is returned"""        @param argvals: new values assigned to symbols
1058      if isinstance(arg,Symbol):        @type argvals: C{dict} with keywords of type L{Symbol}.
1059         return arg.diff(dep)        @return: result of the substitution process. Operations are executed as much as possible.
1060      elif hasattr(arg,"shape"):        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1061            if callable(arg.shape):        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1062                return numarray.zeros(arg.shape(),numarray.Float)        """
1063            else:        if argvals.has_key(self):
1064                return numarray.zeros(arg.shape,numarray.Float)           arg=argvals[self]
1065      else:           if self.isAppropriateValue(arg):
1066         return 0              return arg
1067             else:
1068                raise TypeError,"%s: new value is not appropriate."%str(self)
1069          else:
1070             arg=self.getSubstitutedArguments(argvals)[0]
1071             return whereNegative(arg)
1072    
1073  def exp(arg):  def whereNonNegative(arg):
1074      """     """
1075      @brief applies the exponential function to arg     returns mask of non-negative values of argument arg
1076      @param arg (input): argument  
1077      """     @param arg: argument
1078      if isinstance(arg,Symbol):     @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1079         return Exp_Symbol(arg)     @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1080      elif hasattr(arg,"exp"):     @raises TypeError: if the type of the argument is not expected.
1081         return arg.exp()     """
1082      else:     if isinstance(arg,numarray.NumArray):
1083         return numarray.exp(arg)        out=numarray.greater_equal(arg,numarray.zeros(arg.shape,numarray.Float))
1084          if isinstance(out,float): out=numarray.array(out)
1085          return out
1086       elif isinstance(arg,escript.Data):
1087          return arg._whereNonNegative()
1088       elif isinstance(arg,float):
1089          if arg<0:
1090            return 0.
1091          else:
1092            return 1.
1093       elif isinstance(arg,int):
1094          if arg<0:
1095            return 0.
1096          else:
1097            return 1.
1098       elif isinstance(arg,Symbol):
1099          return 1.-whereNegative(arg)
1100       else:
1101          raise TypeError,"whereNonNegative: Unknown argument type."
1102    
1103    def whereNonPositive(arg):
1104       """
1105       returns mask of non-positive values of argument arg
1106    
1107       @param arg: argument
1108       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1109       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1110       @raises TypeError: if the type of the argument is not expected.
1111       """
1112       if isinstance(arg,numarray.NumArray):
1113          out=numarray.less_equal(arg,numarray.zeros(arg.shape,numarray.Float))*1.
1114          if isinstance(out,float): out=numarray.array(out)
1115          return out
1116       elif isinstance(arg,escript.Data):
1117          return arg._whereNonPositive()
1118       elif isinstance(arg,float):
1119          if arg>0:
1120            return 0.
1121          else:
1122            return 1.
1123       elif isinstance(arg,int):
1124          if arg>0:
1125            return 0.
1126          else:
1127            return 1.
1128       elif isinstance(arg,Symbol):
1129          return 1.-wherePositive(arg)
1130       else:
1131          raise TypeError,"whereNonPositive: Unknown argument type."
1132    
1133    def whereZero(arg,tol=0.):
1134       """
1135       returns mask of zero entries of argument arg
1136    
1137       @param arg: argument
1138       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1139       @param tol: tolerance. values with absolute value less then tol are accepted as zero.
1140       @type tol: C{float}
1141       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1142       @raises TypeError: if the type of the argument is not expected.
1143       """
1144       if isinstance(arg,numarray.NumArray):
1145          out=numarray.less_equal(abs(arg)-tol,numarray.zeros(arg.shape,numarray.Float))*1.
1146          if isinstance(out,float): out=numarray.array(out)
1147          return out
1148       elif isinstance(arg,escript.Data):
1149          if tol>0.:
1150             return whereNegative(abs(arg)-tol)
1151          else:
1152             return arg._whereZero()
1153       elif isinstance(arg,float):
1154          if abs(arg)<=tol:
1155            return 1.
1156          else:
1157            return 0.
1158       elif isinstance(arg,int):
1159          if abs(float(arg))<=tol:
1160            return 1.
1161          else:
1162            return 0.
1163       elif isinstance(arg,Symbol):
1164          return WhereZero_Symbol(arg,tol)
1165       else:
1166          raise TypeError,"whereZero: Unknown argument type."
1167    
1168    class WhereZero_Symbol(DependendSymbol):
1169       """
1170       L{Symbol} representing the result of the mask of zero entries function
1171       """
1172       def __init__(self,arg,tol=0.):
1173          """
1174          initialization of whereZero L{Symbol} with argument arg
1175          @param arg: argument of function
1176          @type arg: typically L{Symbol}.
1177          """
1178          DependendSymbol.__init__(self,args=[arg,tol],shape=arg.getShape(),dim=arg.getDim())
1179    
1180       def getMyCode(self,argstrs,format="escript"):
1181          """
1182          returns a program code that can be used to evaluate the symbol.
1183    
1184          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1185          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1186          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1187          @type format: C{str}
1188          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1189          @rtype: C{str}
1190          @raise: NotImplementedError: if the requested format is not available
1191          """
1192          if format=="escript" or format=="str"  or format=="text":
1193             return "whereZero(%s,tol=%s)"%(argstrs[0],argstrs[1])
1194          else:
1195             raise NotImplementedError,"WhereZero_Symbol does not provide program code for format %s."%format
1196    
1197       def substitute(self,argvals):
1198          """
1199          assigns new values to symbols in the definition of the symbol.
1200          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1201    
1202          @param argvals: new values assigned to symbols
1203          @type argvals: C{dict} with keywords of type L{Symbol}.
1204          @return: result of the substitution process. Operations are executed as much as possible.
1205          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1206          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1207          """
1208          if argvals.has_key(self):
1209             arg=argvals[self]
1210             if self.isAppropriateValue(arg):
1211                return arg
1212             else:
1213                raise TypeError,"%s: new value is not appropriate."%str(self)
1214          else:
1215             arg=self.getSubstitutedArguments(argvals)
1216             return whereZero(arg[0],arg[1])
1217    
1218    def whereNonZero(arg,tol=0.):
1219       """
1220       returns mask of values different from zero of argument arg
1221    
1222       @param arg: argument
1223       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1224       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1225       @raises TypeError: if the type of the argument is not expected.
1226       """
1227       if isinstance(arg,numarray.NumArray):
1228          out=numarray.greater(abs(arg)-tol,numarray.zeros(arg.shape,numarray.Float))*1.
1229          if isinstance(out,float): out=numarray.array(out)
1230          return out
1231       elif isinstance(arg,escript.Data):
1232          if tol>0.:
1233             return 1.-whereZero(arg,tol)
1234          else:
1235             return arg._whereNonZero()
1236       elif isinstance(arg,float):
1237          if abs(arg)>tol:
1238            return 1.
1239          else:
1240            return 0.
1241       elif isinstance(arg,int):
1242          if abs(float(arg))>tol:
1243            return 1.
1244          else:
1245            return 0.
1246       elif isinstance(arg,Symbol):
1247          return 1.-whereZero(arg,tol)
1248       else:
1249          raise TypeError,"whereNonZero: Unknown argument type."
1250    
1251    def sin(arg):
1252       """
1253       returns sine of argument arg
1254    
1255       @param arg: argument
1256       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1257       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1258       @raises TypeError: if the type of the argument is not expected.
1259       """
1260       if isinstance(arg,numarray.NumArray):
1261          return numarray.sin(arg)
1262       elif isinstance(arg,escript.Data):
1263          return arg._sin()
1264       elif isinstance(arg,float):
1265          return math.sin(arg)
1266       elif isinstance(arg,int):
1267          return math.sin(arg)
1268       elif isinstance(arg,Symbol):
1269          return Sin_Symbol(arg)
1270       else:
1271          raise TypeError,"sin: Unknown argument type."
1272    
1273  class Exp_Symbol(Symbol):  class Sin_Symbol(DependendSymbol):
1274     """symbol representing the power of the first argument to the power of the second argument"""     """
1275       L{Symbol} representing the result of the sine function
1276       """
1277     def __init__(self,arg):     def __init__(self,arg):
1278         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
1279     def __str__(self):        initialization of sin L{Symbol} with argument arg
1280        return "exp(%s)"%str(self.getArgument(0))        @param arg: argument of function
1281     def eval(self,argval):        @type arg: typically L{Symbol}.
1282         return exp(self.getEvaluatedArguments(argval)[0])        """
1283     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1284         return self*self.getDifferentiatedArguments(arg)[0]  
1285       def getMyCode(self,argstrs,format="escript"):
1286          """
1287          returns a program code that can be used to evaluate the symbol.
1288    
1289          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1290          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1291          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1292          @type format: C{str}
1293          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1294          @rtype: C{str}
1295          @raise: NotImplementedError: if the requested format is not available
1296          """
1297          if isinstance(argstrs,list):
1298              argstrs=argstrs[0]
1299          if format=="escript" or format=="str"  or format=="text":
1300             return "sin(%s)"%argstrs
1301          else:
1302             raise NotImplementedError,"Sin_Symbol does not provide program code for format %s."%format
1303    
1304  def sqrt(arg):     def substitute(self,argvals):
1305      """        """
1306      @brief applies the squre root function to arg        assigns new values to symbols in the definition of the symbol.
1307      @param arg (input): argument        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1308      """  
1309      if isinstance(arg,Symbol):        @param argvals: new values assigned to symbols
1310         return Sqrt_Symbol(arg)        @type argvals: C{dict} with keywords of type L{Symbol}.
1311      elif hasattr(arg,"sqrt"):        @return: result of the substitution process. Operations are executed as much as possible.
1312         return arg.sqrt()        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1313      else:        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1314         return numarray.sqrt(arg)              """
1315          if argvals.has_key(self):
1316             arg=argvals[self]
1317             if self.isAppropriateValue(arg):
1318                return arg
1319             else:
1320                raise TypeError,"%s: new value is not appropriate."%str(self)
1321          else:
1322             arg=self.getSubstitutedArguments(argvals)[0]
1323             return sin(arg)
1324    
1325  class Sqrt_Symbol(Symbol):     def diff(self,arg):
1326     """symbol representing square root of argument"""        """
1327          differential of this object
1328    
1329          @param arg: the derivative is calculated with respect to arg
1330          @type arg: L{escript.Symbol}
1331          @return: derivative with respect to C{arg}
1332          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1333          """
1334          if arg==self:
1335             return identity(self.getShape())
1336          else:
1337             myarg=self.getArgument()[0]
1338             val=matchShape(cos(myarg),self.getDifferentiatedArguments(arg)[0])
1339             return val[0]*val[1]
1340    
1341    def cos(arg):
1342       """
1343       returns cosine of argument arg
1344    
1345       @param arg: argument
1346       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1347       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1348       @raises TypeError: if the type of the argument is not expected.
1349       """
1350       if isinstance(arg,numarray.NumArray):
1351          return numarray.cos(arg)
1352       elif isinstance(arg,escript.Data):
1353          return arg._cos()
1354       elif isinstance(arg,float):
1355          return math.cos(arg)
1356       elif isinstance(arg,int):
1357          return math.cos(arg)
1358       elif isinstance(arg,Symbol):
1359          return Cos_Symbol(arg)
1360       else:
1361          raise TypeError,"cos: Unknown argument type."
1362    
1363    class Cos_Symbol(DependendSymbol):
1364       """
1365       L{Symbol} representing the result of the cosine function
1366       """
1367     def __init__(self,arg):     def __init__(self,arg):
1368         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
1369     def __str__(self):        initialization of cos L{Symbol} with argument arg
1370        return "sqrt(%s)"%str(self.getArgument(0))        @param arg: argument of function
1371     def eval(self,argval):        @type arg: typically L{Symbol}.
1372         return sqrt(self.getEvaluatedArguments(argval)[0])        """
1373     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1374         return (-0.5)/self*self.getDifferentiatedArguments(arg)[0]  
1375       def getMyCode(self,argstrs,format="escript"):
1376          """
1377          returns a program code that can be used to evaluate the symbol.
1378    
1379          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1380          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1381          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1382          @type format: C{str}
1383          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1384          @rtype: C{str}
1385          @raise: NotImplementedError: if the requested format is not available
1386          """
1387          if isinstance(argstrs,list):
1388              argstrs=argstrs[0]
1389          if format=="escript" or format=="str"  or format=="text":
1390             return "cos(%s)"%argstrs
1391          else:
1392             raise NotImplementedError,"Cos_Symbol does not provide program code for format %s."%format
1393    
1394  def log(arg):     def substitute(self,argvals):
1395      """        """
1396      @brief applies the logarithmic function bases exp(1.) to arg        assigns new values to symbols in the definition of the symbol.
1397      @param arg (input): argument        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1398      """  
1399      if isinstance(arg,Symbol):        @param argvals: new values assigned to symbols
1400         return Log_Symbol(arg)        @type argvals: C{dict} with keywords of type L{Symbol}.
1401      elif hasattr(arg,"log"):        @return: result of the substitution process. Operations are executed as much as possible.
1402         return arg.log()        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1403      else:        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1404         return numarray.log(arg)        """
1405          if argvals.has_key(self):
1406             arg=argvals[self]
1407             if self.isAppropriateValue(arg):
1408                return arg
1409             else:
1410                raise TypeError,"%s: new value is not appropriate."%str(self)
1411          else:
1412             arg=self.getSubstitutedArguments(argvals)[0]
1413             return cos(arg)
1414    
1415       def diff(self,arg):
1416          """
1417          differential of this object
1418    
1419          @param arg: the derivative is calculated with respect to arg
1420          @type arg: L{escript.Symbol}
1421          @return: derivative with respect to C{arg}
1422          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1423          """
1424          if arg==self:
1425             return identity(self.getShape())
1426          else:
1427             myarg=self.getArgument()[0]
1428             val=matchShape(-sin(myarg),self.getDifferentiatedArguments(arg)[0])
1429             return val[0]*val[1]
1430    
1431    def tan(arg):
1432       """
1433       returns tangent of argument arg
1434    
1435  class Log_Symbol(Symbol):     @param arg: argument
1436     """symbol representing logarithm of the argument"""     @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1437       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1438       @raises TypeError: if the type of the argument is not expected.
1439       """
1440       if isinstance(arg,numarray.NumArray):
1441          return numarray.tan(arg)
1442       elif isinstance(arg,escript.Data):
1443          return arg._tan()
1444       elif isinstance(arg,float):
1445          return math.tan(arg)
1446       elif isinstance(arg,int):
1447          return math.tan(arg)
1448       elif isinstance(arg,Symbol):
1449          return Tan_Symbol(arg)
1450       else:
1451          raise TypeError,"tan: Unknown argument type."
1452    
1453    class Tan_Symbol(DependendSymbol):
1454       """
1455       L{Symbol} representing the result of the tangent function
1456       """
1457     def __init__(self,arg):     def __init__(self,arg):
1458         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
1459     def __str__(self):        initialization of tan L{Symbol} with argument arg
1460        return "log(%s)"%str(self.getArgument(0))        @param arg: argument of function
1461     def eval(self,argval):        @type arg: typically L{Symbol}.
1462         return log(self.getEvaluatedArguments(argval)[0])        """
1463     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1464         return self.getDifferentiatedArguments(arg)[0]/self.getArgument(0)  
1465       def getMyCode(self,argstrs,format="escript"):
1466          """
1467          returns a program code that can be used to evaluate the symbol.
1468    
1469          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1470          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1471          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1472          @type format: C{str}
1473          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1474          @rtype: C{str}
1475          @raise: NotImplementedError: if the requested format is not available
1476          """
1477          if isinstance(argstrs,list):
1478              argstrs=argstrs[0]
1479          if format=="escript" or format=="str"  or format=="text":
1480             return "tan(%s)"%argstrs
1481          else:
1482             raise NotImplementedError,"Tan_Symbol does not provide program code for format %s."%format
1483    
1484  def ln(arg):     def substitute(self,argvals):
1485      """        """
1486      @brief applies the natural logarithmic function to arg        assigns new values to symbols in the definition of the symbol.
1487      @param arg (input): argument        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1488      """  
1489      if isinstance(arg,Symbol):        @param argvals: new values assigned to symbols
1490         return Ln_Symbol(arg)        @type argvals: C{dict} with keywords of type L{Symbol}.
1491      elif hasattr(arg,"ln"):        @return: result of the substitution process. Operations are executed as much as possible.
1492         return arg.log()        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1493      else:        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1494         return numarray.log(arg)        """
1495          if argvals.has_key(self):
1496             arg=argvals[self]
1497             if self.isAppropriateValue(arg):
1498                return arg
1499             else:
1500                raise TypeError,"%s: new value is not appropriate."%str(self)
1501          else:
1502             arg=self.getSubstitutedArguments(argvals)[0]
1503             return tan(arg)
1504    
1505  class Ln_Symbol(Symbol):     def diff(self,arg):
1506     """symbol representing natural logarithm of the argument"""        """
1507          differential of this object
1508    
1509          @param arg: the derivative is calculated with respect to arg
1510          @type arg: L{escript.Symbol}
1511          @return: derivative with respect to C{arg}
1512          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1513          """
1514          if arg==self:
1515             return identity(self.getShape())
1516          else:
1517             myarg=self.getArgument()[0]
1518             val=matchShape(1./cos(myarg)**2,self.getDifferentiatedArguments(arg)[0])
1519             return val[0]*val[1]
1520    
1521    def asin(arg):
1522       """
1523       returns inverse sine of argument arg
1524    
1525       @param arg: argument
1526       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1527       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1528       @raises TypeError: if the type of the argument is not expected.
1529       """
1530       if isinstance(arg,numarray.NumArray):
1531          return numarray.arcsin(arg)
1532       elif isinstance(arg,escript.Data):
1533          return arg._asin()
1534       elif isinstance(arg,float):
1535          return math.asin(arg)
1536       elif isinstance(arg,int):
1537          return math.asin(arg)
1538       elif isinstance(arg,Symbol):
1539          return Asin_Symbol(arg)
1540       else:
1541          raise TypeError,"asin: Unknown argument type."
1542    
1543    class Asin_Symbol(DependendSymbol):
1544       """
1545       L{Symbol} representing the result of the inverse sine function
1546       """
1547     def __init__(self,arg):     def __init__(self,arg):
1548         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
1549     def __str__(self):        initialization of asin L{Symbol} with argument arg
1550        return "ln(%s)"%str(self.getArgument(0))        @param arg: argument of function
1551     def eval(self,argval):        @type arg: typically L{Symbol}.
1552         return ln(self.getEvaluatedArguments(argval)[0])        """
1553     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1554         return self.getDifferentiatedArguments(arg)[0]/self.getArgument(0)  
1555       def getMyCode(self,argstrs,format="escript"):
1556          """
1557          returns a program code that can be used to evaluate the symbol.
1558    
1559          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1560          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1561          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1562          @type format: C{str}
1563          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1564          @rtype: C{str}
1565          @raise: NotImplementedError: if the requested format is not available
1566          """
1567          if isinstance(argstrs,list):
1568              argstrs=argstrs[0]
1569          if format=="escript" or format=="str"  or format=="text":
1570             return "asin(%s)"%argstrs
1571          else:
1572             raise NotImplementedError,"Asin_Symbol does not provide program code for format %s."%format
1573    
1574  def sin(arg):     def substitute(self,argvals):
1575      """        """
1576      @brief applies the sin function to arg        assigns new values to symbols in the definition of the symbol.
1577      @param arg (input): argument        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1578      """  
1579      if isinstance(arg,Symbol):        @param argvals: new values assigned to symbols
1580         return Sin_Symbol(arg)        @type argvals: C{dict} with keywords of type L{Symbol}.
1581      elif hasattr(arg,"sin"):        @return: result of the substitution process. Operations are executed as much as possible.
1582         return arg.sin()        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1583      else:        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1584         return numarray.sin(arg)        """
1585          if argvals.has_key(self):
1586             arg=argvals[self]
1587             if self.isAppropriateValue(arg):
1588                return arg
1589             else:
1590                raise TypeError,"%s: new value is not appropriate."%str(self)
1591          else:
1592             arg=self.getSubstitutedArguments(argvals)[0]
1593             return asin(arg)
1594    
1595  class Sin_Symbol(Symbol):     def diff(self,arg):
1596     """symbol representing sin of the argument"""        """
1597          differential of this object
1598    
1599          @param arg: the derivative is calculated with respect to arg
1600          @type arg: L{escript.Symbol}
1601          @return: derivative with respect to C{arg}
1602          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1603          """
1604          if arg==self:
1605             return identity(self.getShape())
1606          else:
1607             myarg=self.getArgument()[0]
1608             val=matchShape(1./sqrt(1.-myarg**2),self.getDifferentiatedArguments(arg)[0])
1609             return val[0]*val[1]
1610    
1611    def acos(arg):
1612       """
1613       returns inverse cosine of argument arg
1614    
1615       @param arg: argument
1616       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1617       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1618       @raises TypeError: if the type of the argument is not expected.
1619       """
1620       if isinstance(arg,numarray.NumArray):
1621          return numarray.arccos(arg)
1622       elif isinstance(arg,escript.Data):
1623          return arg._acos()
1624       elif isinstance(arg,float):
1625          return math.acos(arg)
1626       elif isinstance(arg,int):
1627          return math.acos(arg)
1628       elif isinstance(arg,Symbol):
1629          return Acos_Symbol(arg)
1630       else:
1631          raise TypeError,"acos: Unknown argument type."
1632    
1633    class Acos_Symbol(DependendSymbol):
1634       """
1635       L{Symbol} representing the result of the inverse cosine function
1636       """
1637     def __init__(self,arg):     def __init__(self,arg):
1638         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
1639     def __str__(self):        initialization of acos L{Symbol} with argument arg
1640        return "sin(%s)"%str(self.getArgument(0))        @param arg: argument of function
1641     def eval(self,argval):        @type arg: typically L{Symbol}.
1642         return sin(self.getEvaluatedArguments(argval)[0])        """
1643     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1644         return cos(self.getArgument(0))*self.getDifferentiatedArguments(arg)[0]  
1645       def getMyCode(self,argstrs,format="escript"):
1646          """
1647          returns a program code that can be used to evaluate the symbol.
1648    
1649          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1650          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1651          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1652          @type format: C{str}
1653          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1654          @rtype: C{str}
1655          @raise: NotImplementedError: if the requested format is not available
1656          """
1657          if isinstance(argstrs,list):
1658              argstrs=argstrs[0]
1659          if format=="escript" or format=="str"  or format=="text":
1660             return "acos(%s)"%argstrs
1661          else:
1662             raise NotImplementedError,"Acos_Symbol does not provide program code for format %s."%format
1663    
1664  def cos(arg):     def substitute(self,argvals):
1665      """        """
1666      @brief applies the cos function to arg        assigns new values to symbols in the definition of the symbol.
1667      @param arg (input): argument        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1668      """  
1669      if isinstance(arg,Symbol):        @param argvals: new values assigned to symbols
1670         return Cos_Symbol(arg)        @type argvals: C{dict} with keywords of type L{Symbol}.
1671      elif hasattr(arg,"cos"):        @return: result of the substitution process. Operations are executed as much as possible.
1672         return arg.cos()        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1673      else:        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1674         return numarray.cos(arg)        """
1675          if argvals.has_key(self):
1676             arg=argvals[self]
1677             if self.isAppropriateValue(arg):
1678                return arg
1679             else:
1680                raise TypeError,"%s: new value is not appropriate."%str(self)
1681          else:
1682             arg=self.getSubstitutedArguments(argvals)[0]
1683             return acos(arg)
1684    
1685  class Cos_Symbol(Symbol):     def diff(self,arg):
1686     """symbol representing cos of the argument"""        """
1687          differential of this object
1688    
1689          @param arg: the derivative is calculated with respect to arg
1690          @type arg: L{escript.Symbol}
1691          @return: derivative with respect to C{arg}
1692          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1693          """
1694          if arg==self:
1695             return identity(self.getShape())
1696          else:
1697             myarg=self.getArgument()[0]
1698             val=matchShape(-1./sqrt(1.-myarg**2),self.getDifferentiatedArguments(arg)[0])
1699             return val[0]*val[1]
1700    
1701    def atan(arg):
1702       """
1703       returns inverse tangent of argument arg
1704    
1705       @param arg: argument
1706       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1707       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1708       @raises TypeError: if the type of the argument is not expected.
1709       """
1710       if isinstance(arg,numarray.NumArray):
1711          return numarray.arctan(arg)
1712       elif isinstance(arg,escript.Data):
1713          return arg._atan()
1714       elif isinstance(arg,float):
1715          return math.atan(arg)
1716       elif isinstance(arg,int):
1717          return math.atan(arg)
1718       elif isinstance(arg,Symbol):
1719          return Atan_Symbol(arg)
1720       else:
1721          raise TypeError,"atan: Unknown argument type."
1722    
1723    class Atan_Symbol(DependendSymbol):
1724       """
1725       L{Symbol} representing the result of the inverse tangent function
1726       """
1727     def __init__(self,arg):     def __init__(self,arg):
1728         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
1729     def __str__(self):        initialization of atan L{Symbol} with argument arg
1730        return "cos(%s)"%str(self.getArgument(0))        @param arg: argument of function
1731     def eval(self,argval):        @type arg: typically L{Symbol}.
1732         return cos(self.getEvaluatedArguments(argval)[0])        """
1733     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1734         return -sin(self.getArgument(0))*self.getDifferentiatedArguments(arg)[0]  
1735       def getMyCode(self,argstrs,format="escript"):
1736          """
1737          returns a program code that can be used to evaluate the symbol.
1738    
1739          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1740          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1741          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1742          @type format: C{str}
1743          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1744          @rtype: C{str}
1745          @raise: NotImplementedError: if the requested format is not available
1746          """
1747          if isinstance(argstrs,list):
1748              argstrs=argstrs[0]
1749          if format=="escript" or format=="str"  or format=="text":
1750             return "atan(%s)"%argstrs
1751          else:
1752             raise NotImplementedError,"Atan_Symbol does not provide program code for format %s."%format
1753    
1754  def tan(arg):     def substitute(self,argvals):
1755      """        """
1756      @brief applies the tan function to arg        assigns new values to symbols in the definition of the symbol.
1757      @param arg (input): argument        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1758      """  
1759      if isinstance(arg,Symbol):        @param argvals: new values assigned to symbols
1760         return Tan_Symbol(arg)        @type argvals: C{dict} with keywords of type L{Symbol}.
1761      elif hasattr(arg,"tan"):        @return: result of the substitution process. Operations are executed as much as possible.
1762         return arg.tan()        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1763      else:        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1764         return numarray.tan(arg)        """
1765          if argvals.has_key(self):
1766             arg=argvals[self]
1767             if self.isAppropriateValue(arg):
1768                return arg
1769             else:
1770                raise TypeError,"%s: new value is not appropriate."%str(self)
1771          else:
1772             arg=self.getSubstitutedArguments(argvals)[0]
1773             return atan(arg)
1774    
1775       def diff(self,arg):
1776          """
1777          differential of this object
1778    
1779          @param arg: the derivative is calculated with respect to arg
1780          @type arg: L{escript.Symbol}
1781          @return: derivative with respect to C{arg}
1782          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1783          """
1784          if arg==self:
1785             return identity(self.getShape())
1786          else:
1787             myarg=self.getArgument()[0]
1788             val=matchShape(1./(1+myarg**2),self.getDifferentiatedArguments(arg)[0])
1789             return val[0]*val[1]
1790    
1791    def sinh(arg):
1792       """
1793       returns hyperbolic sine of argument arg
1794    
1795       @param arg: argument
1796       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1797       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1798       @raises TypeError: if the type of the argument is not expected.
1799       """
1800       if isinstance(arg,numarray.NumArray):
1801          return numarray.sinh(arg)
1802       elif isinstance(arg,escript.Data):
1803          return arg._sinh()
1804       elif isinstance(arg,float):
1805          return math.sinh(arg)
1806       elif isinstance(arg,int):
1807          return math.sinh(arg)
1808       elif isinstance(arg,Symbol):
1809          return Sinh_Symbol(arg)
1810       else:
1811          raise TypeError,"sinh: Unknown argument type."
1812    
1813  class Tan_Symbol(Symbol):  class Sinh_Symbol(DependendSymbol):
1814     """symbol representing tan of the argument"""     """
1815       L{Symbol} representing the result of the hyperbolic sine function
1816       """
1817     def __init__(self,arg):     def __init__(self,arg):
1818         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
1819     def __str__(self):        initialization of sinh L{Symbol} with argument arg
1820        return "tan(%s)"%str(self.getArgument(0))        @param arg: argument of function
1821     def eval(self,argval):        @type arg: typically L{Symbol}.
1822         return tan(self.getEvaluatedArguments(argval)[0])        """
1823     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1824         s=cos(self.getArgument(0))  
1825         return 1./(s*s)*self.getDifferentiatedArguments(arg)[0]     def getMyCode(self,argstrs,format="escript"):
1826          """
1827          returns a program code that can be used to evaluate the symbol.
1828    
1829          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1830          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1831          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1832          @type format: C{str}
1833          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1834          @rtype: C{str}
1835          @raise: NotImplementedError: if the requested format is not available
1836          """
1837          if isinstance(argstrs,list):
1838              argstrs=argstrs[0]
1839          if format=="escript" or format=="str"  or format=="text":
1840             return "sinh(%s)"%argstrs
1841          else:
1842             raise NotImplementedError,"Sinh_Symbol does not provide program code for format %s."%format
1843    
1844  def sign(arg):     def substitute(self,argvals):
1845      """        """
1846      @brief applies the sign function to arg        assigns new values to symbols in the definition of the symbol.
1847      @param arg (input): argument        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1848      """  
1849      if isinstance(arg,Symbol):        @param argvals: new values assigned to symbols
1850         return Sign_Symbol(arg)        @type argvals: C{dict} with keywords of type L{Symbol}.
1851      elif hasattr(arg,"sign"):        @return: result of the substitution process. Operations are executed as much as possible.
1852         return arg.sign()        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1853      else:        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1854         return numarray.greater(arg,numarray.zeros(arg.shape,numarray.Float))- \        """
1855                numarray.less(arg,numarray.zeros(arg.shape,numarray.Float))        if argvals.has_key(self):
1856             arg=argvals[self]
1857             if self.isAppropriateValue(arg):
1858                return arg
1859             else:
1860                raise TypeError,"%s: new value is not appropriate."%str(self)
1861          else:
1862             arg=self.getSubstitutedArguments(argvals)[0]
1863             return sinh(arg)
1864    
1865  class Sign_Symbol(Symbol):     def diff(self,arg):
1866     """symbol representing the sign of the argument"""        """
1867          differential of this object
1868    
1869          @param arg: the derivative is calculated with respect to arg
1870          @type arg: L{escript.Symbol}
1871          @return: derivative with respect to C{arg}
1872          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1873          """
1874          if arg==self:
1875             return identity(self.getShape())
1876          else:
1877             myarg=self.getArgument()[0]
1878             val=matchShape(cosh(myarg),self.getDifferentiatedArguments(arg)[0])
1879             return val[0]*val[1]
1880    
1881    def cosh(arg):
1882       """
1883       returns hyperbolic cosine of argument arg
1884    
1885       @param arg: argument
1886       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1887       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1888       @raises TypeError: if the type of the argument is not expected.
1889       """
1890       if isinstance(arg,numarray.NumArray):
1891          return numarray.cosh(arg)
1892       elif isinstance(arg,escript.Data):
1893          return arg._cosh()
1894       elif isinstance(arg,float):
1895          return math.cosh(arg)
1896       elif isinstance(arg,int):
1897          return math.cosh(arg)
1898       elif isinstance(arg,Symbol):
1899          return Cosh_Symbol(arg)
1900       else:
1901          raise TypeError,"cosh: Unknown argument type."
1902    
1903    class Cosh_Symbol(DependendSymbol):
1904       """
1905       L{Symbol} representing the result of the hyperbolic cosine function
1906       """
1907     def __init__(self,arg):     def __init__(self,arg):
1908         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
1909     def __str__(self):        initialization of cosh L{Symbol} with argument arg
1910        return "sign(%s)"%str(self.getArgument(0))        @param arg: argument of function
1911     def eval(self,argval):        @type arg: typically L{Symbol}.
1912         return sign(self.getEvaluatedArguments(argval)[0])        """
1913          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1914    
1915       def getMyCode(self,argstrs,format="escript"):
1916          """
1917          returns a program code that can be used to evaluate the symbol.
1918    
1919          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1920          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1921          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1922          @type format: C{str}
1923          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1924          @rtype: C{str}
1925          @raise: NotImplementedError: if the requested format is not available
1926          """
1927          if isinstance(argstrs,list):
1928              argstrs=argstrs[0]
1929          if format=="escript" or format=="str"  or format=="text":
1930             return "cosh(%s)"%argstrs
1931          else:
1932             raise NotImplementedError,"Cosh_Symbol does not provide program code for format %s."%format
1933    
1934  def maxval(arg):     def substitute(self,argvals):
1935      """        """
1936      @brief returns the maximum value of argument arg""        assigns new values to symbols in the definition of the symbol.
1937      @param arg (input): argument        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1938      """  
1939      if isinstance(arg,Symbol):        @param argvals: new values assigned to symbols
1940         return Max_Symbol(arg)        @type argvals: C{dict} with keywords of type L{Symbol}.
1941      elif hasattr(arg,"maxval"):        @return: result of the substitution process. Operations are executed as much as possible.
1942         return arg.maxval()        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1943      elif hasattr(arg,"max"):        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1944         return arg.max()        """
1945      else:        if argvals.has_key(self):
1946         return arg           arg=argvals[self]
1947             if self.isAppropriateValue(arg):
1948                return arg
1949             else:
1950                raise TypeError,"%s: new value is not appropriate."%str(self)
1951          else:
1952             arg=self.getSubstitutedArguments(argvals)[0]
1953             return cosh(arg)
1954    
1955       def diff(self,arg):
1956          """
1957          differential of this object
1958    
1959          @param arg: the derivative is calculated with respect to arg
1960          @type arg: L{escript.Symbol}
1961          @return: derivative with respect to C{arg}
1962          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1963          """
1964          if arg==self:
1965             return identity(self.getShape())
1966          else:
1967             myarg=self.getArgument()[0]
1968             val=matchShape(sinh(myarg),self.getDifferentiatedArguments(arg)[0])
1969             return val[0]*val[1]
1970    
1971    def tanh(arg):
1972       """
1973       returns hyperbolic tangent of argument arg
1974    
1975       @param arg: argument
1976       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1977       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1978       @raises TypeError: if the type of the argument is not expected.
1979       """
1980       if isinstance(arg,numarray.NumArray):
1981          return numarray.tanh(arg)
1982       elif isinstance(arg,escript.Data):
1983          return arg._tanh()
1984       elif isinstance(arg,float):
1985          return math.tanh(arg)
1986       elif isinstance(arg,int):
1987          return math.tanh(arg)
1988       elif isinstance(arg,Symbol):
1989          return Tanh_Symbol(arg)
1990       else:
1991          raise TypeError,"tanh: Unknown argument type."
1992    
1993  class Max_Symbol(Symbol):  class Tanh_Symbol(DependendSymbol):
1994     """symbol representing the maximum value of the argument"""     """
1995       L{Symbol} representing the result of the hyperbolic tangent function
1996       """
1997     def __init__(self,arg):     def __init__(self,arg):
1998         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
1999     def __str__(self):        initialization of tanh L{Symbol} with argument arg
2000        return "maxval(%s)"%str(self.getArgument(0))        @param arg: argument of function
2001     def eval(self,argval):        @type arg: typically L{Symbol}.
2002         return maxval(self.getEvaluatedArguments(argval)[0])        """
2003          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2004    
2005       def getMyCode(self,argstrs,format="escript"):
2006          """
2007          returns a program code that can be used to evaluate the symbol.
2008    
2009          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2010          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2011          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2012          @type format: C{str}
2013          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2014          @rtype: C{str}
2015          @raise: NotImplementedError: if the requested format is not available
2016          """
2017          if isinstance(argstrs,list):
2018              argstrs=argstrs[0]
2019          if format=="escript" or format=="str"  or format=="text":
2020             return "tanh(%s)"%argstrs
2021          else:
2022             raise NotImplementedError,"Tanh_Symbol does not provide program code for format %s."%format
2023    
2024       def substitute(self,argvals):
2025          """
2026          assigns new values to symbols in the definition of the symbol.
2027          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2028    
2029          @param argvals: new values assigned to symbols
2030          @type argvals: C{dict} with keywords of type L{Symbol}.
2031          @return: result of the substitution process. Operations are executed as much as possible.
2032          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2033          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2034          """
2035          if argvals.has_key(self):
2036             arg=argvals[self]
2037             if self.isAppropriateValue(arg):
2038                return arg
2039             else:
2040                raise TypeError,"%s: new value is not appropriate."%str(self)
2041          else:
2042             arg=self.getSubstitutedArguments(argvals)[0]
2043             return tanh(arg)
2044    
2045       def diff(self,arg):
2046          """
2047          differential of this object
2048    
2049          @param arg: the derivative is calculated with respect to arg
2050          @type arg: L{escript.Symbol}
2051          @return: derivative with respect to C{arg}
2052          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2053          """
2054          if arg==self:
2055             return identity(self.getShape())
2056          else:
2057             myarg=self.getArgument()[0]
2058             val=matchShape(1./cosh(myarg)**2,self.getDifferentiatedArguments(arg)[0])
2059             return val[0]*val[1]
2060    
2061    def asinh(arg):
2062       """
2063       returns inverse hyperbolic sine of argument arg
2064    
2065       @param arg: argument
2066       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2067       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2068       @raises TypeError: if the type of the argument is not expected.
2069       """
2070       if isinstance(arg,numarray.NumArray):
2071          return numarray.arcsinh(arg)
2072       elif isinstance(arg,escript.Data):
2073          return arg._asinh()
2074       elif isinstance(arg,float):
2075          return numarray.arcsinh(arg)
2076       elif isinstance(arg,int):
2077          return numarray.arcsinh(float(arg))
2078       elif isinstance(arg,Symbol):
2079          return Asinh_Symbol(arg)
2080       else:
2081          raise TypeError,"asinh: Unknown argument type."
2082    
2083    class Asinh_Symbol(DependendSymbol):
2084       """
2085       L{Symbol} representing the result of the inverse hyperbolic sine function
2086       """
2087       def __init__(self,arg):
2088          """
2089          initialization of asinh L{Symbol} with argument arg
2090          @param arg: argument of function
2091          @type arg: typically L{Symbol}.
2092          """
2093          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2094    
2095       def getMyCode(self,argstrs,format="escript"):
2096          """
2097          returns a program code that can be used to evaluate the symbol.
2098    
2099          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2100          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2101          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2102          @type format: C{str}
2103          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2104          @rtype: C{str}
2105          @raise: NotImplementedError: if the requested format is not available
2106          """
2107          if isinstance(argstrs,list):
2108              argstrs=argstrs[0]
2109          if format=="escript" or format=="str"  or format=="text":
2110             return "asinh(%s)"%argstrs
2111          else:
2112             raise NotImplementedError,"Asinh_Symbol does not provide program code for format %s."%format
2113    
2114       def substitute(self,argvals):
2115          """
2116          assigns new values to symbols in the definition of the symbol.
2117          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2118    
2119          @param argvals: new values assigned to symbols
2120          @type argvals: C{dict} with keywords of type L{Symbol}.
2121          @return: result of the substitution process. Operations are executed as much as possible.
2122          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2123          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2124          """
2125          if argvals.has_key(self):
2126             arg=argvals[self]
2127             if self.isAppropriateValue(arg):
2128                return arg
2129             else:
2130                raise TypeError,"%s: new value is not appropriate."%str(self)
2131          else:
2132             arg=self.getSubstitutedArguments(argvals)[0]
2133             return asinh(arg)
2134    
2135       def diff(self,arg):
2136          """
2137          differential of this object
2138    
2139          @param arg: the derivative is calculated with respect to arg
2140          @type arg: L{escript.Symbol}
2141          @return: derivative with respect to C{arg}
2142          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2143          """
2144          if arg==self:
2145             return identity(self.getShape())
2146          else:
2147             myarg=self.getArgument()[0]
2148             val=matchShape(1./sqrt(myarg**2+1),self.getDifferentiatedArguments(arg)[0])
2149             return val[0]*val[1]
2150    
2151    def acosh(arg):
2152       """
2153       returns inverse hyperolic cosine of argument arg
2154    
2155       @param arg: argument
2156       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2157       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2158       @raises TypeError: if the type of the argument is not expected.
2159       """
2160       if isinstance(arg,numarray.NumArray):
2161          return numarray.arccosh(arg)
2162       elif isinstance(arg,escript.Data):
2163          return arg._acosh()
2164       elif isinstance(arg,float):
2165          return numarray.arccosh(arg)
2166       elif isinstance(arg,int):
2167          return numarray.arccosh(float(arg))
2168       elif isinstance(arg,Symbol):
2169          return Acosh_Symbol(arg)
2170       else:
2171          raise TypeError,"acosh: Unknown argument type."
2172    
2173    class Acosh_Symbol(DependendSymbol):
2174       """
2175       L{Symbol} representing the result of the inverse hyperolic cosine function
2176       """
2177       def __init__(self,arg):
2178          """
2179          initialization of acosh L{Symbol} with argument arg
2180          @param arg: argument of function
2181          @type arg: typically L{Symbol}.
2182          """
2183          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2184    
2185       def getMyCode(self,argstrs,format="escript"):
2186          """
2187          returns a program code that can be used to evaluate the symbol.
2188    
2189          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2190          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2191          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2192          @type format: C{str}
2193          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2194          @rtype: C{str}
2195          @raise: NotImplementedError: if the requested format is not available
2196          """
2197          if isinstance(argstrs,list):
2198              argstrs=argstrs[0]
2199          if format=="escript" or format=="str"  or format=="text":
2200             return "acosh(%s)"%argstrs
2201          else:
2202             raise NotImplementedError,"Acosh_Symbol does not provide program code for format %s."%format
2203    
2204       def substitute(self,argvals):
2205          """
2206          assigns new values to symbols in the definition of the symbol.
2207          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2208    
2209          @param argvals: new values assigned to symbols
2210          @type argvals: C{dict} with keywords of type L{Symbol}.
2211          @return: result of the substitution process. Operations are executed as much as possible.
2212          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2213          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2214          """
2215          if argvals.has_key(self):
2216             arg=argvals[self]
2217             if self.isAppropriateValue(arg):
2218                return arg
2219             else:
2220                raise TypeError,"%s: new value is not appropriate."%str(self)
2221          else:
2222             arg=self.getSubstitutedArguments(argvals)[0]
2223             return acosh(arg)
2224    
2225       def diff(self,arg):
2226          """
2227          differential of this object
2228    
2229          @param arg: the derivative is calculated with respect to arg
2230          @type arg: L{escript.Symbol}
2231          @return: derivative with respect to C{arg}
2232          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2233          """
2234          if arg==self:
2235             return identity(self.getShape())
2236          else:
2237             myarg=self.getArgument()[0]
2238             val=matchShape(1./sqrt(myarg**2-1),self.getDifferentiatedArguments(arg)[0])
2239             return val[0]*val[1]
2240    
2241    def atanh(arg):
2242       """
2243       returns inverse hyperbolic tangent of argument arg
2244    
2245       @param arg: argument
2246       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2247       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2248       @raises TypeError: if the type of the argument is not expected.
2249       """
2250       if isinstance(arg,numarray.NumArray):
2251          return numarray.arctanh(arg)
2252       elif isinstance(arg,escript.Data):
2253          return arg._atanh()
2254       elif isinstance(arg,float):
2255          return numarray.arctanh(arg)
2256       elif isinstance(arg,int):
2257          return numarray.arctanh(float(arg))
2258       elif isinstance(arg,Symbol):
2259          return Atanh_Symbol(arg)
2260       else:
2261          raise TypeError,"atanh: Unknown argument type."
2262    
2263    class Atanh_Symbol(DependendSymbol):
2264       """
2265       L{Symbol} representing the result of the inverse hyperbolic tangent function
2266       """
2267       def __init__(self,arg):
2268          """
2269          initialization of atanh L{Symbol} with argument arg
2270          @param arg: argument of function
2271          @type arg: typically L{Symbol}.
2272          """
2273          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2274    
2275       def getMyCode(self,argstrs,format="escript"):
2276          """
2277          returns a program code that can be used to evaluate the symbol.
2278    
2279          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2280          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2281          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2282          @type format: C{str}
2283          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2284          @rtype: C{str}
2285          @raise: NotImplementedError: if the requested format is not available
2286          """
2287          if isinstance(argstrs,list):
2288              argstrs=argstrs[0]
2289          if format=="escript" or format=="str"  or format=="text":
2290             return "atanh(%s)"%argstrs
2291          else:
2292             raise NotImplementedError,"Atanh_Symbol does not provide program code for format %s."%format
2293    
2294       def substitute(self,argvals):
2295          """
2296          assigns new values to symbols in the definition of the symbol.
2297          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2298    
2299          @param argvals: new values assigned to symbols
2300          @type argvals: C{dict} with keywords of type L{Symbol}.
2301          @return: result of the substitution process. Operations are executed as much as possible.
2302          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2303          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2304          """
2305          if argvals.has_key(self):
2306             arg=argvals[self]
2307             if self.isAppropriateValue(arg):
2308                return arg
2309             else:
2310                raise TypeError,"%s: new value is not appropriate."%str(self)
2311          else:
2312             arg=self.getSubstitutedArguments(argvals)[0]
2313             return atanh(arg)
2314    
2315       def diff(self,arg):
2316          """
2317          differential of this object
2318    
2319          @param arg: the derivative is calculated with respect to arg
2320          @type arg: L{escript.Symbol}
2321          @return: derivative with respect to C{arg}
2322          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2323          """
2324          if arg==self:
2325             return identity(self.getShape())
2326          else:
2327             myarg=self.getArgument()[0]
2328             val=matchShape(1./(1.-myarg**2),self.getDifferentiatedArguments(arg)[0])
2329             return val[0]*val[1]
2330    
2331    def exp(arg):
2332       """
2333       returns exponential of argument arg
2334    
2335       @param arg: argument
2336       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2337       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2338       @raises TypeError: if the type of the argument is not expected.
2339       """
2340       if isinstance(arg,numarray.NumArray):
2341          return numarray.exp(arg)
2342       elif isinstance(arg,escript.Data):
2343          return arg._exp()
2344       elif isinstance(arg,float):
2345          return math.exp(arg)
2346       elif isinstance(arg,int):
2347          return math.exp(arg)
2348       elif isinstance(arg,Symbol):
2349          return Exp_Symbol(arg)
2350       else:
2351          raise TypeError,"exp: Unknown argument type."
2352    
2353    class Exp_Symbol(DependendSymbol):
2354       """
2355       L{Symbol} representing the result of the exponential function
2356       """
2357       def __init__(self,arg):
2358          """
2359          initialization of exp L{Symbol} with argument arg
2360          @param arg: argument of function
2361          @type arg: typically L{Symbol}.
2362          """
2363          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2364    
2365       def getMyCode(self,argstrs,format="escript"):
2366          """
2367          returns a program code that can be used to evaluate the symbol.
2368    
2369          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2370          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2371          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2372          @type format: C{str}
2373          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2374          @rtype: C{str}
2375          @raise: NotImplementedError: if the requested format is not available
2376          """
2377          if isinstance(argstrs,list):
2378              argstrs=argstrs[0]
2379          if format=="escript" or format=="str"  or format=="text":
2380             return "exp(%s)"%argstrs
2381          else:
2382             raise NotImplementedError,"Exp_Symbol does not provide program code for format %s."%format
2383    
2384       def substitute(self,argvals):
2385          """
2386          assigns new values to symbols in the definition of the symbol.
2387          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2388    
2389          @param argvals: new values assigned to symbols
2390          @type argvals: C{dict} with keywords of type L{Symbol}.
2391          @return: result of the substitution process. Operations are executed as much as possible.
2392          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2393          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2394          """
2395          if argvals.has_key(self):
2396             arg=argvals[self]
2397             if self.isAppropriateValue(arg):
2398                return arg
2399             else:
2400                raise TypeError,"%s: new value is not appropriate."%str(self)
2401          else:
2402             arg=self.getSubstitutedArguments(argvals)[0]
2403             return exp(arg)
2404    
2405       def diff(self,arg):
2406          """
2407          differential of this object
2408    
2409          @param arg: the derivative is calculated with respect to arg
2410          @type arg: L{escript.Symbol}
2411          @return: derivative with respect to C{arg}
2412          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2413          """
2414          if arg==self:
2415             return identity(self.getShape())
2416          else:
2417             myarg=self.getArgument()[0]
2418             val=matchShape(self,self.getDifferentiatedArguments(arg)[0])
2419             return val[0]*val[1]
2420    
2421    def sqrt(arg):
2422       """
2423       returns square root of argument arg
2424    
2425       @param arg: argument
2426       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2427       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2428       @raises TypeError: if the type of the argument is not expected.
2429       """
2430       if isinstance(arg,numarray.NumArray):
2431          return numarray.sqrt(arg)
2432       elif isinstance(arg,escript.Data):
2433          return arg._sqrt()
2434       elif isinstance(arg,float):
2435          return math.sqrt(arg)
2436       elif isinstance(arg,int):
2437          return math.sqrt(arg)
2438       elif isinstance(arg,Symbol):
2439          return Sqrt_Symbol(arg)
2440       else:
2441          raise TypeError,"sqrt: Unknown argument type."
2442    
2443    class Sqrt_Symbol(DependendSymbol):
2444       """
2445       L{Symbol} representing the result of the square root function
2446       """
2447       def __init__(self,arg):
2448          """
2449          initialization of sqrt L{Symbol} with argument arg
2450          @param arg: argument of function
2451          @type arg: typically L{Symbol}.
2452          """
2453          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2454    
2455       def getMyCode(self,argstrs,format="escript"):
2456          """
2457          returns a program code that can be used to evaluate the symbol.
2458    
2459          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2460          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2461          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2462          @type format: C{str}
2463          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2464          @rtype: C{str}
2465          @raise: NotImplementedError: if the requested format is not available
2466          """
2467          if isinstance(argstrs,list):
2468              argstrs=argstrs[0]
2469          if format=="escript" or format=="str"  or format=="text":
2470             return "sqrt(%s)"%argstrs
2471          else:
2472             raise NotImplementedError,"Sqrt_Symbol does not provide program code for format %s."%format
2473    
2474       def substitute(self,argvals):
2475          """
2476          assigns new values to symbols in the definition of the symbol.
2477          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2478    
2479          @param argvals: new values assigned to symbols
2480          @type argvals: C{dict} with keywords of type L{Symbol}.
2481          @return: result of the substitution process. Operations are executed as much as possible.
2482          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2483          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2484          """
2485          if argvals.has_key(self):
2486             arg=argvals[self]
2487             if self.isAppropriateValue(arg):
2488                return arg
2489             else:
2490                raise TypeError,"%s: new value is not appropriate."%str(self)
2491          else:
2492             arg=self.getSubstitutedArguments(argvals)[0]
2493             return sqrt(arg)
2494    
2495       def diff(self,arg):
2496          """
2497          differential of this object
2498    
2499          @param arg: the derivative is calculated with respect to arg
2500          @type arg: L{escript.Symbol}
2501          @return: derivative with respect to C{arg}
2502          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2503          """
2504          if arg==self:
2505             return identity(self.getShape())
2506          else:
2507             myarg=self.getArgument()[0]
2508             val=matchShape(0.5/self,self.getDifferentiatedArguments(arg)[0])
2509             return val[0]*val[1]
2510    
2511    def log(arg):
2512       """
2513       returns natural logarithm of argument arg
2514    
2515       @param arg: argument
2516       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2517       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2518       @raises TypeError: if the type of the argument is not expected.
2519       """
2520       if isinstance(arg,numarray.NumArray):
2521          return numarray.log(arg)
2522       elif isinstance(arg,escript.Data):
2523          return arg._log()
2524       elif isinstance(arg,float):
2525          return math.log(arg)
2526       elif isinstance(arg,int):
2527          return math.log(arg)
2528       elif isinstance(arg,Symbol):
2529          return Log_Symbol(arg)
2530       else:
2531          raise TypeError,"log: Unknown argument type."
2532    
2533    class Log_Symbol(DependendSymbol):
2534       """
2535       L{Symbol} representing the result of the natural logarithm function
2536       """
2537       def __init__(self,arg):
2538          """
2539          initialization of log L{Symbol} with argument arg
2540          @param arg: argument of function
2541          @type arg: typically L{Symbol}.
2542          """
2543          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2544    
2545       def getMyCode(self,argstrs,format="escript"):
2546          """
2547          returns a program code that can be used to evaluate the symbol.
2548    
2549          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2550          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2551          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2552          @type format: C{str}
2553          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2554          @rtype: C{str}
2555          @raise: NotImplementedError: if the requested format is not available
2556          """
2557          if isinstance(argstrs,list):
2558              argstrs=argstrs[0]
2559          if format=="escript" or format=="str"  or format=="text":
2560             return "log(%s)"%argstrs
2561          else:
2562             raise NotImplementedError,"Log_Symbol does not provide program code for format %s."%format
2563    
2564       def substitute(self,argvals):
2565          """
2566          assigns new values to symbols in the definition of the symbol.
2567          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2568    
2569          @param argvals: new values assigned to symbols
2570          @type argvals: C{dict} with keywords of type L{Symbol}.
2571          @return: result of the substitution process. Operations are executed as much as possible.
2572          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2573          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2574          """
2575          if argvals.has_key(self):
2576             arg=argvals[self]
2577             if self.isAppropriateValue(arg):
2578                return arg
2579             else:
2580                raise TypeError,"%s: new value is not appropriate."%str(self)
2581          else:
2582             arg=self.getSubstitutedArguments(argvals)[0]
2583             return log(arg)
2584    
2585       def diff(self,arg):
2586          """
2587          differential of this object
2588    
2589          @param arg: the derivative is calculated with respect to arg
2590          @type arg: L{escript.Symbol}
2591          @return: derivative with respect to C{arg}
2592          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2593          """
2594          if arg==self:
2595             return identity(self.getShape())
2596          else:
2597             myarg=self.getArgument()[0]
2598             val=matchShape(1./arg,self.getDifferentiatedArguments(arg)[0])
2599             return val[0]*val[1]
2600    
2601    def sign(arg):
2602       """
2603       returns sign of argument arg
2604    
2605       @param arg: argument
2606       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2607       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2608       @raises TypeError: if the type of the argument is not expected.
2609       """
2610       if isinstance(arg,numarray.NumArray):
2611          return wherePositive(arg)-whereNegative(arg)
2612       elif isinstance(arg,escript.Data):
2613          return arg._sign()
2614       elif isinstance(arg,float):
2615          if arg>0:
2616            return 1.
2617          elif arg<0:
2618            return -1.
2619          else:
2620            return 0.
2621       elif isinstance(arg,int):
2622          if float(arg)>0:
2623            return 1.
2624          elif float(arg)<0:
2625            return -1.
2626          else:
2627            return 0.
2628       elif isinstance(arg,Symbol):
2629          return wherePositive(arg)-whereNegative(arg)
2630       else:
2631          raise TypeError,"sign: Unknown argument type."
2632    
2633    class Abs_Symbol(DependendSymbol):
2634       """
2635       L{Symbol} representing the result of the absolute value function
2636       """
2637       def __init__(self,arg):
2638          """
2639          initialization of abs L{Symbol} with argument arg
2640          @param arg: argument of function
2641          @type arg: typically L{Symbol}.
2642          """
2643          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2644    
2645       def getMyCode(self,argstrs,format="escript"):
2646          """
2647          returns a program code that can be used to evaluate the symbol.
2648    
2649          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2650          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2651          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2652          @type format: C{str}
2653          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2654          @rtype: C{str}
2655          @raise: NotImplementedError: if the requested format is not available
2656          """
2657          if isinstance(argstrs,list):
2658              argstrs=argstrs[0]
2659          if format=="escript" or format=="str"  or format=="text":
2660             return "abs(%s)"%argstrs
2661          else:
2662             raise NotImplementedError,"Abs_Symbol does not provide program code for format %s."%format
2663    
2664       def substitute(self,argvals):
2665          """
2666          assigns new values to symbols in the definition of the symbol.
2667          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2668    
2669          @param argvals: new values assigned to symbols
2670          @type argvals: C{dict} with keywords of type L{Symbol}.
2671          @return: result of the substitution process. Operations are executed as much as possible.
2672          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2673          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2674          """
2675          if argvals.has_key(self):
2676             arg=argvals[self]
2677             if self.isAppropriateValue(arg):
2678                return arg
2679             else:
2680                raise TypeError,"%s: new value is not appropriate."%str(self)
2681          else:
2682             arg=self.getSubstitutedArguments(argvals)[0]
2683             return abs(arg)
2684    
2685       def diff(self,arg):
2686          """
2687          differential of this object
2688    
2689          @param arg: the derivative is calculated with respect to arg
2690          @type arg: L{escript.Symbol}
2691          @return: derivative with respect to C{arg}
2692          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2693          """
2694          if arg==self:
2695             return identity(self.getShape())
2696          else:
2697             myarg=self.getArgument()[0]
2698             val=matchShape(sign(myarg),self.getDifferentiatedArguments(arg)[0])
2699             return val[0]*val[1]
2700    
2701  def minval(arg):  def minval(arg):
2702      """     """
2703      @brief returns the minimum value of argument arg""     returns minimum value over all components of arg at each data point
     @param arg (input): argument  
     """  
     if isinstance(arg,Symbol):  
        return Min_Symbol(arg)  
     elif hasattr(arg,"maxval"):  
        return arg.minval()  
     elif hasattr(arg,"min"):  
        return arg.min()  
     else:  
        return arg  
2704    
2705  class Min_Symbol(Symbol):     @param arg: argument
2706     """symbol representing the minimum value of the argument"""     @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2707       @rtype:C{float}, L{escript.Data}, L{Symbol} depending on the type of arg.
2708       @raises TypeError: if the type of the argument is not expected.
2709       """
2710       if isinstance(arg,numarray.NumArray):
2711          if arg.rank==0:
2712             return float(arg)
2713          else:
2714             return arg.min()
2715       elif isinstance(arg,escript.Data):
2716          return arg._minval()
2717       elif isinstance(arg,float):
2718          return arg
2719       elif isinstance(arg,int):
2720          return float(arg)
2721       elif isinstance(arg,Symbol):
2722          return Minval_Symbol(arg)
2723       else:
2724          raise TypeError,"minval: Unknown argument type."
2725    
2726    class Minval_Symbol(DependendSymbol):
2727       """
2728       L{Symbol} representing the result of the minimum value function
2729       """
2730     def __init__(self,arg):     def __init__(self,arg):
2731         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2732     def __str__(self):        initialization of minimum value L{Symbol} with argument arg
2733        return "minval(%s)"%str(self.getArgument(0))        @param arg: argument of function
2734     def eval(self,argval):        @type arg: typically L{Symbol}.
2735         return minval(self.getEvaluatedArguments(argval)[0])        """
2736          DependendSymbol.__init__(self,args=[arg],shape=(),dim=arg.getDim())
2737    
2738       def getMyCode(self,argstrs,format="escript"):
2739          """
2740          returns a program code that can be used to evaluate the symbol.
2741    
2742          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2743          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2744          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2745          @type format: C{str}
2746          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2747          @rtype: C{str}
2748          @raise: NotImplementedError: if the requested format is not available
2749          """
2750          if isinstance(argstrs,list):
2751              argstrs=argstrs[0]
2752          if format=="escript" or format=="str"  or format=="text":
2753             return "minval(%s)"%argstrs
2754          else:
2755             raise NotImplementedError,"Minval_Symbol does not provide program code for format %s."%format
2756    
2757  def wherePositive(arg):     def substitute(self,argvals):
2758      """        """
2759      @brief returns the positive values of argument arg""        assigns new values to symbols in the definition of the symbol.
2760      @param arg (input): argument        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2761      """  
2762      if _testForZero(arg):        @param argvals: new values assigned to symbols
2763        return 0        @type argvals: C{dict} with keywords of type L{Symbol}.
2764      elif isinstance(arg,Symbol):        @return: result of the substitution process. Operations are executed as much as possible.
2765         return WherePositive_Symbol(arg)        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2766      elif hasattr(arg,"wherePositive"):        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2767         return arg.minval()        """
2768      elif hasattr(arg,"wherePositive"):        if argvals.has_key(self):
2769         numarray.greater(arg,numarray.zeros(arg.shape,numarray.Float))           arg=argvals[self]
2770      else:           if self.isAppropriateValue(arg):
2771         if arg>0:              return arg
2772            return 1.           else:
2773         else:              raise TypeError,"%s: new value is not appropriate."%str(self)
2774            return 0.        else:
2775             arg=self.getSubstitutedArguments(argvals)[0]
2776             return minval(arg)
2777    
2778    def maxval(arg):
2779       """
2780       returns maximum value over all components of arg at each data point
2781    
2782  class WherePositive_Symbol(Symbol):     @param arg: argument
2783     """symbol representing the wherePositive function"""     @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2784       @rtype:C{float}, L{escript.Data}, L{Symbol} depending on the type of arg.
2785       @raises TypeError: if the type of the argument is not expected.
2786       """
2787       if isinstance(arg,numarray.NumArray):
2788          if arg.rank==0:
2789             return float(arg)
2790          else:
2791             return arg.max()
2792       elif isinstance(arg,escript.Data):
2793          return arg._maxval()
2794       elif isinstance(arg,float):
2795          return arg
2796       elif isinstance(arg,int):
2797          return float(arg)
2798       elif isinstance(arg,Symbol):
2799          return Maxval_Symbol(arg)
2800       else:
2801          raise TypeError,"maxval: Unknown argument type."
2802    
2803    class Maxval_Symbol(DependendSymbol):
2804       """
2805       L{Symbol} representing the result of the maximum value function
2806       """
2807     def __init__(self,arg):     def __init__(self,arg):
2808         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2809     def __str__(self):        initialization of maximum value L{Symbol} with argument arg
2810        return "wherePositive(%s)"%str(self.getArgument(0))        @param arg: argument of function
2811     def eval(self,argval):        @type arg: typically L{Symbol}.
2812         return wherePositive(self.getEvaluatedArguments(argval)[0])        """
2813          DependendSymbol.__init__(self,args=[arg],shape=(),dim=arg.getDim())
2814    
2815       def getMyCode(self,argstrs,format="escript"):
2816          """
2817          returns a program code that can be used to evaluate the symbol.
2818    
2819          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2820          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2821          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2822          @type format: C{str}
2823          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2824          @rtype: C{str}
2825          @raise: NotImplementedError: if the requested format is not available
2826          """
2827          if isinstance(argstrs,list):
2828              argstrs=argstrs[0]
2829          if format=="escript" or format=="str"  or format=="text":
2830             return "maxval(%s)"%argstrs
2831          else:
2832             raise NotImplementedError,"Maxval_Symbol does not provide program code for format %s."%format
2833    
2834  def whereNegative(arg):     def substitute(self,argvals):
2835          """
2836          assigns new values to symbols in the definition of the symbol.
2837          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2838    
2839          @param argvals: new values assigned to symbols
2840          @type argvals: C{dict} with keywords of type L{Symbol}.
2841          @return: result of the substitution process. Operations are executed as much as possible.
2842          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2843          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2844          """
2845          if argvals.has_key(self):
2846             arg=argvals[self]
2847             if self.isAppropriateValue(arg):
2848                return arg
2849             else:
2850                raise TypeError,"%s: new value is not appropriate."%str(self)
2851          else:
2852             arg=self.getSubstitutedArguments(argvals)[0]
2853             return maxval(arg)
2854    
2855    def length(arg):
2856       """
2857       returns length/Euclidean norm of argument arg at each data point
2858    
2859       @param arg: argument
2860       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2861       @rtype:C{float}, L{escript.Data}, L{Symbol} depending on the type of arg.
2862       """
2863       return sqrt(inner(arg,arg))
2864    
2865    #=======================================================
2866    #  Binary operations:
2867    #=======================================================
2868    def add(arg0,arg1):
2869           """
2870           adds arg0 and arg1 together.
2871    
2872           @param arg0: first term
2873           @type arg0: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
2874           @param arg1: second term
2875           @type arg1: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
2876           @return: the some of arg0 and arg1
2877           @rtype: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
2878           @note: The shape of both arguments is matched according to the rules in used in L{matchShape}
2879           """
2880           args=matchShape(arg0,arg1)
2881           if testForZero(args[0]):
2882              return args[1]
2883           elif testForZero(args[1]):
2884              return args[0]
2885           else:
2886              if isinstance(args[0],Symbol) or isinstance(args[1],Symbol) :
2887                  return Add_Symbol(args[0],args[1])
2888              elif isinstance(args[0],numarray.NumArray):
2889                  return args[1]+args[0]
2890              else:
2891                  return args[0]+args[1]
2892    
2893    class Add_Symbol(DependendSymbol):
2894       """
2895       Symbol representing the sum of two arguments.
2896       """
2897       def __init__(self,arg0,arg1):
2898           """
2899           initialization of the L{Symbol} representing the sum of two arguments
2900    
2901           @param arg0: first term in the sum
2902           @type arg0: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
2903           @param arg1: second term in the sum
2904           @type arg1: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
2905           @raise ValueError: if both arguments do not have the same shape.
2906           @note: if both arguments have a spatial dimension, they must equal.
2907           """
2908           sh0=pokeShape(arg0)
2909           sh1=pokeShape(arg1)
2910           if not sh0==sh1:
2911              raise ValueError,"Add_Symbol: shape of arguments must match"
2912           DependendSymbol.__init__(self,dim=commonDim(arg0,arg1),shape=sh0,args=[arg0,arg1])
2913    
2914       def getMyCode(self,argstrs,format="escript"):
2915          """
2916          returns a program code that can be used to evaluate the symbol.
2917    
2918          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2919          @type argstrs: C{list} of length 2 of C{str}.
2920          @param format: specifies the format to be used. At the moment only "escript", "str" and "text" are supported.
2921          @type format: C{str}
2922          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2923          @rtype: C{str}
2924          @raise: NotImplementedError: if the requested format is not available
2925          """
2926          if format=="str" or format=="text":
2927             return "(%s)+(%s)"%(argstrs[0],argstrs[1])
2928          elif format=="escript":
2929             return "add(%s,%s)"%(argstrs[0],argstrs[1])
2930          else:
2931             raise NotImplementedError,"%s does not provide program code for format %s."%(str(self),format)
2932    
2933       def substitute(self,argvals):
2934          """
2935          assigns new values to symbols in the definition of the symbol.
2936          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2937    
2938          @param argvals: new values assigned to symbols
2939          @type argvals: C{dict} with keywords of type L{Symbol}.
2940          @return: result of the substitution process. Operations are executed as much as possible.
2941          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2942          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2943          """
2944          if argvals.has_key(self):
2945             arg=argvals[self]
2946             if self.isAppropriateValue(arg):
2947                return arg
2948             else:
2949                raise TypeError,"%s: new value is not appropriate."%str(self)
2950          else:
2951             args=self.getSubstitutedArguments(argvals)
2952             return add(args[0],args[1])
2953    
2954       def diff(self,arg):
2955          """
2956          differential of this object
2957    
2958          @param arg: the derivative is calculated with respect to arg
2959          @type arg: L{escript.Symbol}
2960          @return: derivative with respect to C{arg}
2961          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2962          """
2963          if arg==self:
2964             return identity(self.getShape())
2965          else:
2966             dargs=self.getDifferentiatedArguments(arg)
2967             return add(dargs[0],dargs[1])
2968    
2969    def mult(arg0,arg1):
2970           """
2971           product of arg0 and arg1
2972    
2973           @param arg0: first term
2974           @type arg0: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
2975           @param arg1: second term
2976           @type arg1: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
2977           @return: the some of arg0 and arg1
2978           @rtype: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
2979           @note: The shape of both arguments is matched according to the rules in used in L{matchShape}
2980           """
2981           args=matchShape(arg0,arg1)
2982           if testForZero(args[0]) or testForZero(args[1]):
2983              return numarray.zeros(pokeShape(args[0]),numarray.Float)
2984           else:
2985              if isinstance(args[0],Symbol) or isinstance(args[1],Symbol) :
2986                  return Mult_Symbol(args[0],args[1])
2987              elif isinstance(args[0],numarray.NumArray):
2988                  return args[1]*args[0]
2989              else:
2990                  return args[0]*args[1]
2991    
2992    class Mult_Symbol(DependendSymbol):
2993       """
2994       Symbol representing the product of two arguments.
2995       """
2996       def __init__(self,arg0,arg1):
2997           """
2998           initialization of the L{Symbol} representing the product of two arguments
2999    
3000           @param arg0: first factor
3001           @type arg0: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
3002           @param arg1: second factor
3003           @type arg1: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
3004           @raise ValueError: if both arguments do not have the same shape.
3005           @note: if both arguments have a spatial dimension, they must equal.
3006           """
3007           sh0=pokeShape(arg0)
3008           sh1=pokeShape(arg1)
3009           if not sh0==sh1:
3010              raise ValueError,"Mult_Symbol: shape of arguments must match"
3011           DependendSymbol.__init__(self,dim=commonDim(arg0,arg1),shape=sh0,args=[arg0,arg1])
3012    
3013       def getMyCode(self,argstrs,format="escript"):
3014          """
3015          returns a program code that can be used to evaluate the symbol.
3016    
3017          @param argstrs: gives for each argument a string representing the argument for the evaluation.
3018          @type argstrs: C{list} of length 2 of C{str}.
3019          @param format: specifies the format to be used. At the moment only "escript", "str" and "text" are supported.
3020          @type format: C{str}
3021          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
3022          @rtype: C{str}
3023          @raise: NotImplementedError: if the requested format is not available
3024          """
3025          if format=="str" or format=="text":
3026             return "(%s)*(%s)"%(argstrs[0],argstrs[1])
3027          elif format=="escript":
3028             return "mult(%s,%s)"%(argstrs[0],argstrs[1])
3029          else:
3030             raise NotImplementedError,"%s does not provide program code for format %s."%(str(self),format)
3031    
3032       def substitute(self,argvals):
3033          """
3034          assigns new values to symbols in the definition of the symbol.
3035          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
3036    
3037          @param argvals: new values assigned to symbols
3038          @type argvals: C{dict} with keywords of type L{Symbol}.
3039          @return: result of the substitution process. Operations are executed as much as possible.
3040          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
3041          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
3042          """
3043          if argvals.has_key(self):
3044             arg=argvals[self]
3045             if self.isAppropriateValue(arg):
3046                return arg
3047             else:
3048                raise TypeError,"%s: new value is not appropriate."%str(self)
3049          else:
3050             args=self.getSubstitutedArguments(argvals)
3051             return mult(args[0],args[1])
3052    
3053       def diff(self,arg):
3054          """
3055          differential of this object
3056    
3057          @param arg: the derivative is calculated with respect to arg
3058          @type arg: L{escript.Symbol}
3059          @return: derivative with respect to C{arg}
3060          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
3061          """
3062          if arg==self:
3063             return identity(self.getShape())
3064          else:
3065             myargs=self.getArgument()
3066             dargs=self.getDifferentiatedArguments(arg)
3067             return add(mult(myargs[0],dargs[1]),mult(myargs[1],dargs[0]))
3068    
3069    def quotient(arg0,arg1):
3070           """
3071           quotient of arg0 and arg1
3072    
3073           @param arg0: numerator
3074           @type arg0: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
3075           @param arg1: denominator
3076           @type arg1: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
3077           @return: the some of arg0 and arg1
3078           @rtype: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
3079           @note: The shape of both arguments is matched according to the rules in used in L{matchShape}
3080           """
3081           args=matchShape(arg0,arg1)
3082           if testForZero(args[0]):
3083              return numarray.zeros(pokeShape(args[0]),numarray.Float)
3084           elif isinstance(args[0],Symbol):
3085              if isinstance(args[1],Symbol):
3086                 return Quotient_Symbol(args[0],args[1])
3087              else:
3088                 return mult(args[0],1./args[1])
3089           else:
3090              if isinstance(args[1],Symbol):
3091                 return Quotient_Symbol(args[0],args[1])
3092              elif isinstance(args[0],numarray.NumArray) and not isinstance(args[1],numarray.NumArray):
3093                 return 1./args[1]*args[0]
3094              else:
3095                 return args[0]/args[1]
3096    
3097    class Quotient_Symbol(DependendSymbol):
3098       """
3099       Symbol representing the quotient of two arguments.
3100       """
3101       def __init__(self,arg0,arg1):
3102           """
3103           initialization of L{Symbol} representing the quotient of two arguments
3104    
3105           @param arg0: numerator
3106           @type arg0: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
3107           @param arg1: denominator
3108           @type arg1: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
3109           @raise ValueError: if both arguments do not have the same shape.
3110           @note: if both arguments have a spatial dimension, they must equal.
3111           """
3112           sh0=pokeShape(arg0)
3113           sh1=pokeShape(arg1)
3114           if not sh0==sh1:
3115              raise ValueError,"Quotient_Symbol: shape of arguments must match"
3116           DependendSymbol.__init__(self,dim=commonDim(arg0,arg1),shape=sh0,args=[arg0,arg1])
3117    
3118       def getMyCode(self,argstrs,format="escript"):
3119          """
3120          returns a program code that can be used to evaluate the symbol.
3121    
3122          @param argstrs: gives for each argument a string representing the argument for the evaluation.
3123          @type argstrs: C{list} of length 2 of C{str}.
3124          @param format: specifies the format to be used. At the moment only "escript", "str" and "text" are supported.
3125          @type format: C{str}
3126          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
3127          @rtype: C{str}
3128          @raise: NotImplementedError: if the requested format is not available
3129          """
3130          if format=="str" or format=="text":
3131             return "(%s)/(%s)"%(argstrs[0],argstrs[1])
3132          if format=="escript":
3133             return "quotient(%s,%s)"%(argstrs[0],argstrs[1])
3134          else:
3135             raise NotImplementedError,"%s does not provide program code for format %s."%(str(self),format)
3136    
3137       def substitute(self,argvals):
3138          """
3139          assigns new values to symbols in the definition of the symbol.
3140          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
3141    
3142          @param argvals: new values assigned to symbols
3143          @type argvals: C{dict} with keywords of type L{Symbol}.
3144          @return: result of the substitution process. Operations are executed as much as possible.
3145          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
3146          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
3147          """
3148          if argvals.has_key(self):
3149             arg=argvals[self]
3150             if self.isAppropriateValue(arg):
3151                return arg
3152             else:
3153                raise TypeError,"%s: new value is not appropriate."%str(self)
3154          else:
3155             args=self.getSubstitutedArguments(argvals)
3156             return quotient(args[0],args[1])
3157    
3158       def diff(self,arg):
3159          """
3160          differential of this object
3161    
3162          @param arg: the derivative is calculated with respect to arg
3163          @type arg: L{escript.Symbol}
3164          @return: derivative with respect to C{arg}
3165          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
3166          """
3167          if arg==self:
3168             return identity(self.getShape())
3169          else:
3170             myargs=self.getArgument()
3171             dargs=self.getDifferentiatedArguments(arg)
3172             return quotient(add(mult(myargs[1],dargs[0]),mult(-myargs[0],dargs[1])),myargs[1]*myargs[1])
3173    
3174    
3175    def power(arg0,arg1):
3176           """
3177           raises arg0 to the power of arg1
3178    
3179           @param arg0: basis
3180           @type arg0: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
3181           @param arg1: exponent
3182           @type arg1: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
3183           @return: of arg0 and arg1
3184           @rtype: L{escript.Symbol}, C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
3185           @note: The shape of both arguments is matched according to the rules in used in L{matchShape}
3186           """
3187           args=matchShape(arg0,arg1)
3188           if testForZero(args[0]):
3189              return numarray.zeros(args[0],numarray.Float)
3190           elif testForZero(args[1]):
3191              return n