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