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