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

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

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

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