/[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 108 by jgs, Thu Jan 27 06:21:59 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    @remark:  This module is under construction and is still tested!!!
16    
17    @var __author__: name of author
18    @var __licence__: licence agreement
19    @var __url__: url entry point on documentation
20    @var __version__: version
21    @var __date__: date of the version
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  #   escript constants (have to be consistent witj utilC.h  # slicing: get
61  #  #          set
 UNKNOWN=-1  
 EPSILON=1.e-15  
 Pi=numarray.pi  
 # some solver options:  
 NO_REORDERING=0  
 MINIMUM_FILL_IN=1  
 NESTED_DISSECTION=2  
 # solver methods  
 DEFAULT_METHOD=0  
 DIRECT=1  
 CHOLEVSKY=2  
 PCG=3  
 CR=4  
 CGS=5  
 BICGSTAB=6  
 SSOR=7  
 ILU0=8  
 ILUT=9  
 JACOBI=10  
 GMRES=11  
 PRES20=12  
   
 METHOD_KEY="method"  
 SYMMETRY_KEY="symmetric"  
 TOLERANCE_KEY="tolerance"  
   
 # supported file formats:  
 VRML=1  
 PNG=2  
 JPEG=3  
 JPG=3  
 PS=4  
 OOGL=5  
 BMP=6  
 TIFF=7  
 OPENINVENTOR=8  
 RENDERMAN=9  
 PNM=10  
 #  
 # wrapper for various functions: if the argument has attribute the function name  
 # as an argument it calls the correspong methods. Otherwise the coresponsing numarray  
 # function is called.  
62  #  #
63  # functions involving the underlying Domain:  # and derivatives
 #  
 def grad(arg,where=None):  
     """  
     @brief returns the spatial gradient of the Data object arg  
64    
65      @param arg: Data object representing the function which gradient to be calculated.  #=========================================================
66      @param where: FunctionSpace in which the gradient will be. If None Function(dom) where dom is the  #   some helpers:
67                    domain of the Data object arg.  #=========================================================
68      """  def saveVTK(filename,domain=None,**data):
69      if isinstance(arg,escript.Data):      """
70         if where==None:      writes a L{Data} objects into a files using the the VTK XML file format.
71            return arg.grad()  
72         else:      Example:
73            return arg.grad(where)  
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:      else:
94         return arg*0.          domain.saveVTK(filename,data)
95    
96  def integrate(arg,what=None):  def saveDX(filename,domain=None,**data):
97      """      """
98      @brief return the integral if the function represented by Data object arg over its domain.      writes a L{Data} objects into a files using the the DX file format.
99    
100      @param arg      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 not what==None:      if domain==None:
117         arg2=escript.Data(arg,what)         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:      else:
122         arg2=arg          domain.saveDX(filename,data)
     if arg2.getRank()==0:  
         return arg2.integrate()[0]  
     else:  
         return arg2.integrate()  
123    
124  def interpolate(arg,where):  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      @brief interpolates the function represented by Data object arg into the FunctionSpace where.      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      @param arg: argument
210      @param where      @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      if isinstance(arg,escript.Data):      @rtype: C{float}
213         return arg.interpolate(where)      @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:      else:
224         return arg        raise TypeError,"Lsup: Unknown argument type."
225    
226  # functions returning Data objects:  def sup(arg):
   
 def transpose(arg,axis=None):  
227      """      """
228      @brief returns the transpose of the Data object arg.      returns the maximum value over all data points.
229    
230      @param arg      @param arg: argument
231      """      @type arg: C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
232      if isinstance(arg,escript.Data):      @return: maximum value of arg over all components and all data points
233         # hack for transpose      @rtype: C{float}
234         r=arg.getRank()      @raise TypeError: if type of arg cannot be processed
235         if r!=2: raise ValueError,"Tranpose only avalaible for rank 2 objects"      """
236         s=arg.getShape()      if isinstance(arg,numarray.NumArray):
237         out=escript.Data(0.,(s[1],s[0]),arg.getFunctionSpace())          return arg.max()
238         for i in range(s[0]):      elif isinstance(arg,escript.Data):
239            for j in range(s[1]):          return arg._sup()
240               out[j,i]=arg[i,j]      elif isinstance(arg,float):
241         return out          return arg
242         # end hack for transpose      elif isinstance(arg,int):
243         if axis==None: axis=arg.getRank()/2          return float(arg)
        return arg.transpose(axis)  
244      else:      else:
245         if axis==None: axis=arg.rank/2        raise TypeError,"sup: Unknown argument type."
        return numarray.transpose(arg,axis=axis)  
246    
247  def trace(arg):  def inf(arg):
248      """      """
249      @brief      returns the maximum value over all data points.
250    
251      @param arg      @param arg: argument
252      """      @type arg: C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
253      if isinstance(arg,escript.Data):      @return : minimum value of arg over all components and all data points
254         # hack for trace      @rtype: C{float}
255         r=arg.getRank()      @raise TypeError: if type of arg cannot be processed
256         if r!=2: raise ValueError,"trace only avalaible for rank 2 objects"      """
257         s=arg.getShape()      if isinstance(arg,numarray.NumArray):
258         out=escript.Scalar(0,arg.getFunctionSpace())          return arg.min()
259         for i in range(min(s)):      elif isinstance(arg,escript.Data):
260               out+=arg[i,i]          return arg._inf()
261         return out      elif isinstance(arg,float):
262         # end hack for trace          return arg
263         return arg.trace()      elif isinstance(arg,int):
264            return float(arg)
265      else:      else:
266         return numarray.trace(arg)        raise TypeError,"inf: Unknown argument type."
267    
 def exp(arg):  
     """  
     @brief  
268    
269      @param arg  #=========================================================================
270      """  #   some little helpers
271      if isinstance(arg,escript.Data):  #=========================================================================
272         return arg.exp()  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:      else:
294         return numarray.exp(arg)        raise TypeError,"pokeShape: cannot identify shape"
295    
296  def sqrt(arg):  def pokeDim(arg):
297      """      """
298      @brief      identifies the spatial dimension of its argument
299    
300      @param arg      @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):      if isinstance(arg,escript.Data):
307         return arg.sqrt()          return arg.getFunctionSpace().getDim()
308        elif isinstance(arg,Symbol):
309            return arg.getDim()
310      else:      else:
311         return numarray.sqrt(arg)          return None
312    
313  def sin(arg):  def commonShape(arg0,arg1):
314      """      """
315      @brief      returns a shape to which arg0 can be extendent from the right and arg1 can be extended from the left.
316    
317      @param arg      @param arg0: an object with a shape (see L{pokeShape})
318      """      @param arg1: an object with a shape (see L{pokeShape})
319      if isinstance(arg,escript.Data):      @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         return arg.sin()      @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:      else:
334         return numarray.sin(arg)         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 tan(arg):  def testForZero(arg):
359      """      """
360      @brief      test the argument for being identical to Zero
361    
362      @param arg      @param arg: a given object
363      """      @type arg: typically L{numarray.NumArray},L{escript.Data},C{float}, C{int}
364      if isinstance(arg,escript.Data):      @return : True if the argument is identical to zero.
365         return arg.tan()      @rtype : C{bool}
366        """
367        if isinstance(arg,numarray.NumArray):
368           return not Lsup(arg)>0.
369        elif isinstance(arg,escript.Data):
370           return False
371        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:      else:
378         return numarray.tan(arg)         return False
379    
380  def cos(arg):  def matchType(arg0=0.,arg1=0.):
381      """      """
382      @brief      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 arg      @param arg0: first argument
385      """      @type arg0: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, C{Symbol}
386      if isinstance(arg,escript.Data):      @param arg1: second argument
387         return arg.cos()      @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:      else:
462         return numarray.cos(arg)        raise TypeError,"function: Unknown type of first argument."    
463    
464  def maxval(arg):      return arg0,arg1
     """  
     @brief  
465    
466      @param arg  def matchShape(arg0,arg1):
467      """      """
468      if isinstance(arg,escript.Data):      
469         return arg.maxval()  
470      elif isinstance(arg,float) or isinstance(arg,int):      If shape is not given the shape "largest" shape of args is used.
471         return arg  
472      else:      @param args: a given ob
473         return arg.max()      @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
514           self.__shape=shape
515           self.__dim=dim
516    
517       def getArgument(self,i=None):
518           """
519           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):
535           """
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())
542    
543       def getShape(self):
544           """
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
551    
552       def getDim(self):
553           """
554           the spatial dimension
555    
556           @return : the spatial dimension
557           @rtype: C{int} if the dimension is defined. Otherwise C{None} is returned.
558           """
559           return self.__dim
560      
561       def __str__(self):
562           """
563           a string representation of the symbol.
564           @return: a string representation of the object
565           @rtype: C{str}
566           """
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):
594           """
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=[]
603           for a in self.getArgument():
604              if isinstance(a,Symbol):
605                 out.append(a.substitute(argvals))
606              else:
607                  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
613    
614       def isAppropriateValue(self,arg):
615          """
616          checks if the given argument arg can be used as a substitution of this object. The method checks
617          the shape of arg and, if the spatial dimension is defined, the spatial dimension of arg.    
618    
619          @param arg: a given object
620          @type arg: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, C{Symbol}
621          @return: True if arg is a suitbale object to be used for substitution. Otherwise False is returned.
622          @rtype: C{bool}
623          """
624          if isinstance(arg,numarray.NumArray):
625              return arg.shape==self.getShape()
626          elif isinstance(arg,escript.Data):
627              if self.getDim()==None:
628                  return arg.getShape()==self.getShape()
629              elif self.getDim()==arg.getFunctionSpace().getDim():
630                  return arg.getShape()==self.getShape()
631              else:
632                  return False
633          elif isinstance(arg,Symbol):
634              if self.getDim()==None:
635                  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 getMyCode(self,argstrs,format="escript"):
648           """
649           returns a program code that can be used to evaluate the symbol.
650    
651           @param argstrs: gives for each argument a string representing the argument for the evaluation.
652           @type argstrs: C{list} of C{str}.
653           @param format: specifies the format to be used. At the moment only "escript", "str" and "text" are supported.
654           @type format: C{str}
655           @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
656           @rtype: C{str}
657           @raise NotImplementedError: if no implementation for the given format is available
658           @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 diff(self,arg):
685           """
686           returns the derivative of the symbol with respect to L{Symbol} arg
687    
688           @param arg: the derivative is calculated with respect to arg
689           @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           @return: derivative with respect to C{arg}
691           @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:
697              s=self.getShape()+arg.getShape()
698              if len(s)>0:
699                 return numarray.zeros(s,numarray.Float)
700              else:
701                 return 0.
702    
703       def __neg__(self):
704           """
705           returns -self.
706    
707           @return:  a S{Symbol} representing the negative of the object
708           @rtype: L{DependendSymbol}
709           """
710           return self*(-1.)
711    
712       def __pos__(self):
713           """
714           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):
722           """
723           returns a S{Symbol} representing the absolute value of the object.
724           """
725           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):
750           """
751           subtracts another object from this object
752    
753           @param other: object to be subtracted from this object
754           @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):
761           """
762           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):
794           """
795           divides this object by other object
796    
797           @param other: object dividing this object
798           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
799           @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):
805           """
806           divides this object by other object
807    
808           @param other: object dividing this object
809           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
810           @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):
816           """
817           raises this object to the power of other
818    
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):
827           """
828           raises an object to the power of this object
829    
830           @param other: basis
831           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
832           @return: a S{Symbol} representing the power of C{other} to this object
833           @rtype: L{DependendSymbol} or 0 if C{other} is identical to zero.
834           """
835           return power(other,self)
836    
837    class DependendSymbol(Symbol):
838       """
839       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       u1=DependendSymbol(shape=(3,4),dim=2,args=[4.])
852       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       @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       """
859       def __eq__(self,other):
860          """
861          checks if other equals self
862    
863          @param other: any object
864          @return: True if other has the same class like self, and the shape, the spatial diemsnion and the arguments are equal.
865          @rtype: C{bool}
866          """
867          if isinstance(other,DependendSymbol):
868             if self.__class__==other.__class__:  
869                if self.getShape()==other.getShape():
870                  if self.getArgument()==other.getArgument():
871                     if self.getDim()==None or other.getDim()==None or self.getDim()==other.getDim():
872                        return True
873          return False
874    
875       def __ne__(self,other):
876          """
877          checks if other equals self
878    
879          @param other: any object
880          @return: Flase if other has the same class like self, and the shape, the spatial diemsnion and the arguments are equal.
881          @rtype: C{bool}
882          """
883          return not self==other
884    #=========================================================
885    #  Unary operations prserving the shape
886    #========================================================
887    def log10(arg):
888       """
889       returns base-10 logarithm of argument arg
890    
891       @param arg: argument
892       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
893       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
894       @raises TypeError: if the type of the argument is not expected.
895       """
896       if isinstance(arg,numarray.NumArray):
897          return numarray.log10(arg)
898       elif isinstance(arg,escript.Data):
899          return arg._log10()
900       elif isinstance(arg,float):
901          return math.log10(arg)
902       elif isinstance(arg,int):
903          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    def wherePositive(arg):
910       """
911       returns mask of positive values of argument arg
912    
913       @param arg: argument
914       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
915       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
916       @raises TypeError: if the type of the argument is not expected.
917       """
918       if isinstance(arg,numarray.NumArray):
919          out=numarray.greater(arg,numarray.zeros(arg.shape,numarray.Float))
920          if isinstance(out,float): out=numarray.array(out)
921          return out
922       elif isinstance(arg,escript.Data):
923          return arg._wherePositive()
924       elif isinstance(arg,float):
925          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 WherePositive_Symbol(DependendSymbol):
940       """
941       L{Symbol} representing the result of the mask of positive values function
942       """
943       def __init__(self,arg):
944          """
945          initialization of wherePositive L{Symbol} with argument arg
946          @param arg: argument of function
947          @type arg: typically L{Symbol}.
948          """
949          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
950    
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          """
972          assigns new values to symbols in the definition of the symbol.
973          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
974    
975          @param argvals: new values assigned to symbols
976          @type argvals: C{dict} with keywords of type L{Symbol}.
977          @return: result of the substitution process. Operations are executed as much as possible.
978          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
979          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
980          """
981          if argvals.has_key(self):
982             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:
1019          raise TypeError,"whereNegative: Unknown argument type."
1020    
1021    class WhereNegative_Symbol(DependendSymbol):
1022       """
1023       L{Symbol} representing the result of the mask of positive values function
1024       """
1025       def __init__(self,arg):
1026          """
1027          initialization of whereNegative L{Symbol} with argument arg
1028          @param arg: argument of function
1029          @type arg: typically L{Symbol}.
1030          """
1031          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1032    
1033       def getMyCode(self,argstrs,format="escript"):
1034          """
1035          returns a program code that can be used to evaluate the symbol.
1036    
1037          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1038          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1039          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1040          @type format: C{str}
1041          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1042          @rtype: C{str}
1043          @raise: NotImplementedError: if the requested format is not available
1044          """
1045          if isinstance(argstrs,list):
1046              argstrs=argstrs[0]
1047          if format=="escript" or format=="str"  or format=="text":
1048             return "whereNegative(%s)"%argstrs
1049          else:
1050             raise NotImplementedError,"WhereNegative_Symbol does not provide program code for format %s."%format
1051    
1052       def substitute(self,argvals):
1053          """
1054          assigns new values to symbols in the definition of the symbol.
1055          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1056    
1057          @param argvals: new values assigned to symbols
1058          @type argvals: C{dict} with keywords of type L{Symbol}.
1059          @return: result of the substitution process. Operations are executed as much as possible.
1060          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1061          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1062          """
1063          if argvals.has_key(self):
1064             arg=argvals[self]
1065             if self.isAppropriateValue(arg):
1066                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 whereNonNegative(arg):
1074       """
1075       returns mask of non-negative values of argument arg
1076    
1077       @param arg: argument
1078       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1079       @rtype:C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1080       @raises TypeError: if the type of the argument is not expected.
1081       """
1082       if isinstance(arg,numarray.NumArray):
1083          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 Sin_Symbol(DependendSymbol):
1274       """
1275       L{Symbol} representing the result of the sine function
1276       """
1277       def __init__(self,arg):
1278          """
1279          initialization of sin L{Symbol} with argument arg
1280          @param arg: argument of function
1281          @type arg: typically L{Symbol}.
1282          """
1283          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1284    
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 substitute(self,argvals):
1305          """
1306          assigns new values to symbols in the definition of the symbol.
1307          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1308    
1309          @param argvals: new values assigned to symbols
1310          @type argvals: C{dict} with keywords of type L{Symbol}.
1311          @return: result of the substitution process. Operations are executed as much as possible.
1312          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1313          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1314          """
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       def diff(self,arg):
1326          """
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):
1368          """
1369          initialization of cos L{Symbol} with argument arg
1370          @param arg: argument of function
1371          @type arg: typically L{Symbol}.
1372          """
1373          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1374    
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 substitute(self,argvals):
1395          """
1396          assigns new values to symbols in the definition of the symbol.
1397          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1398    
1399          @param argvals: new values assigned to symbols
1400          @type argvals: C{dict} with keywords of type L{Symbol}.
1401          @return: result of the substitution process. Operations are executed as much as possible.
1402          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1403          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1404          """
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       @param arg: argument
1436       @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):
1458          """
1459          initialization of tan L{Symbol} with argument arg
1460          @param arg: argument of function
1461          @type arg: typically L{Symbol}.
1462          """
1463          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1464    
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 substitute(self,argvals):
1485          """
1486          assigns new values to symbols in the definition of the symbol.
1487          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1488    
1489          @param argvals: new values assigned to symbols
1490          @type argvals: C{dict} with keywords of type L{Symbol}.
1491          @return: result of the substitution process. Operations are executed as much as possible.
1492          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1493          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1494          """
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       def diff(self,arg):
1506          """
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):
1548          """
1549          initialization of asin L{Symbol} with argument arg
1550          @param arg: argument of function
1551          @type arg: typically L{Symbol}.
1552          """
1553          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1554    
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 substitute(self,argvals):
1575          """
1576          assigns new values to symbols in the definition of the symbol.
1577          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1578    
1579          @param argvals: new values assigned to symbols
1580          @type argvals: C{dict} with keywords of type L{Symbol}.
1581          @return: result of the substitution process. Operations are executed as much as possible.
1582          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1583          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1584          """
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       def diff(self,arg):
1596          """
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):
1638          """
1639          initialization of acos L{Symbol} with argument arg
1640          @param arg: argument of function
1641          @type arg: typically L{Symbol}.
1642          """
1643          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1644    
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 substitute(self,argvals):
1665          """
1666          assigns new values to symbols in the definition of the symbol.
1667          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1668    
1669          @param argvals: new values assigned to symbols
1670          @type argvals: C{dict} with keywords of type L{Symbol}.
1671          @return: result of the substitution process. Operations are executed as much as possible.
1672          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1673          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1674          """
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       def diff(self,arg):
1686          """
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):
1728          """
1729          initialization of atan L{Symbol} with argument arg
1730          @param arg: argument of function
1731          @type arg: typically L{Symbol}.
1732          """
1733          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1734    
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 substitute(self,argvals):
1755          """
1756          assigns new values to symbols in the definition of the symbol.
1757          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1758    
1759          @param argvals: new values assigned to symbols
1760          @type argvals: C{dict} with keywords of type L{Symbol}.
1761          @return: result of the substitution process. Operations are executed as much as possible.
1762          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1763          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1764          """
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 Sinh_Symbol(DependendSymbol):
1814       """
1815       L{Symbol} representing the result of the hyperbolic sine function
1816       """
1817       def __init__(self,arg):
1818          """
1819          initialization of sinh L{Symbol} with argument arg
1820          @param arg: argument of function
1821          @type arg: typically L{Symbol}.
1822          """
1823          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1824    
1825       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 substitute(self,argvals):
1845          """
1846          assigns new values to symbols in the definition of the symbol.
1847          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1848    
1849          @param argvals: new values assigned to symbols
1850          @type argvals: C{dict} with keywords of type L{Symbol}.
1851          @return: result of the substitution process. Operations are executed as much as possible.
1852          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1853          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1854          """
1855          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       def diff(self,arg):
1866          """
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):
1908          """
1909          initialization of cosh L{Symbol} with argument arg
1910          @param arg: argument of function
1911          @type arg: typically L{Symbol}.
1912          """
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 substitute(self,argvals):
1935          """
1936          assigns new values to symbols in the definition of the symbol.
1937          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1938    
1939          @param argvals: new values assigned to symbols
1940          @type argvals: C{dict} with keywords of type L{Symbol}.
1941          @return: result of the substitution process. Operations are executed as much as possible.
1942          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1943          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1944          """
1945          if argvals.has_key(self):
1946             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 Tanh_Symbol(DependendSymbol):
1994       """
1995       L{Symbol} representing the result of the hyperbolic tangent function
1996       """
1997       def __init__(self,arg):
1998          """
1999          initialization of tanh L{Symbol} with argument arg
2000          @param arg: argument of function
2001          @type arg: typically L{Symbol}.
2002          """
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       returns minimum value over all components of arg at each data point
2704    
2705       @param arg: argument
2706       @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):
2731          """
2732          initialization of minimum value L{Symbol} with argument arg
2733          @param arg: argument of function
2734          @type arg: typically L{Symbol}.
2735          """
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 substitute(self,argvals):
2758          """
2759          assigns new values to symbols in the definition of the symbol.
2760          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2761    
2762          @param argvals: new values assigned to symbols
2763          @type argvals: C{dict} with keywords of type L{Symbol}.
2764          @return: result of the substitution process. Operations are executed as much as possible.
2765          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2766          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2767          """
2768          if argvals.has_key(self):
2769             arg=argvals[self]
2770             if self.isAppropriateValue(arg):
2771                return arg
2772             else:
2773                raise TypeError,"%s: new value is not appropriate."%str(self)
2774          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       @param arg: argument
2783       @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):
2808          """
2809          initialization of maximum value L{Symbol} with argument arg
2810          @param arg: argument of function
2811          @type arg: typically L{Symbol}.
2812          """
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 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 numarray.ones(args[0],numarray.Float)
3192           elif isinstance(args[0],Symbol) or isinstance(args[1],Symbol):
3193              return Power_Symbol(args[0],args[1])
3194           elif isinstance(args[0],numarray.NumArray) and not isinstance(args[1],numarray.NumArray):
3195              return exp(args[1]*log(args[0]))
3196           else:
3197               return args[0]**args[1]
3198    
3199    class Power_Symbol(DependendSymbol):
3200       """
3201       Symbol representing the first argument to the power of the second argument.
3202       """
3203       def __init__(self,arg0,arg1):
3204           """
3205           initialization of the L{Symbol} representing rasing the first argument to the power of the second.
3206    
3207           @param arg0: basis
3208           @type arg0: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
3209           @param arg1: exponent
3210           @type arg1: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
3211           @raise ValueError: if both arguments do not have the same shape.
3212           @note: if both arguments have a spatial dimension, they must equal.
3213           """
3214           sh0=pokeShape(arg0)
3215           sh1=pokeShape(arg1)
3216           if not sh0==sh1:
3217              raise ValueError,"Power_Symbol: shape of arguments must match"
3218           d0=pokeDim(arg0)
3219           d1=pokeDim(arg1)
3220           DependendSymbol.__init__(self,dim=commonDim(arg0,arg1),shape=sh0,args=[arg0,arg1])
3221    
3222       def getMyCode(self,argstrs,format="escript"):
3223          """
3224          returns a program code that can be used to evaluate the symbol.
3225    
3226          @param argstrs: gives for each argument a string representing the argument for the evaluation.
3227          @type argstrs: C{list} of length 2 of C{str}.
3228          @param format: specifies the format to be used. At the moment only "escript", "str" and "text" are supported.
3229          @type format: C{str}
3230          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
3231          @rtype: C{str}
3232          @raise: NotImplementedError: if the requested format is not available
3233          """
3234          if format=="escript" or format=="str" or format=="text":
3235             return "(%s)**(%s)"%(argstrs[0],argstrs[1])
3236          elif format=="escript":
3237             return "power(%s,%s)"%(argstrs[0],argstrs[1])
3238          else:
3239             raise NotImplementedError,"%s does not provide program code for format %s."%(str(self),format)
3240    
3241       def substitute(self,argvals):
3242          """
3243          assigns new values to symbols in the definition of the symbol.
3244          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
3245    
3246          @param argvals: new values assigned to symbols
3247          @type argvals: C{dict} with keywords of type L{Symbol}.
3248          @return: result of the substitution process. Operations are executed as much as possible.
3249          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
3250          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
3251          """
3252          if argvals.has_key(self):
3253             arg=argvals[self]
3254             if self.isAppropriateValue(arg):
3255                return arg
3256             else:
3257                raise TypeError,"%s: new value is not appropriate."%str(self)
3258          else:
3259             args=self.getSubstitutedArguments(argvals)
3260             return power(args[0],args[1])
3261    
3262       def diff(self,arg):
3263          """
3264          differential of this object
3265    
3266          @param arg: the derivative is calculated with respect to arg
3267          @type arg: L{escript.Symbol}
3268          @return: derivative with respect to C{arg}
3269          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
3270          """
3271          if arg==self:
3272             return identity(self.getShape())
3273          else:
3274             myargs=self.getArgument()
3275             dargs=self.getDifferentiatedArguments(arg)
3276             return mult(self,add(mult(log(myargs[0]),dargs[1]),mult(quotient(myargs[1],myargs[0]),dargs[0])))
3277    
3278    def maximum(*args):
3279        """
3280        the maximum over arguments args
3281    
3282        @param args: arguments
3283        @type args: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{int} or C{float}
3284        @return: is on object which gives at each entry the maximum of the coresponding values all args
3285        @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{int} or C{float} depending on the input
3286        """
3287        out=None
3288        for a in args:
3289           if out==None: