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

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

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

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