/[escript]/trunk-mpi-branch/escript/py_src/util.py
ViewVC logotype

Diff of /trunk-mpi-branch/escript/py_src/util.py

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

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