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

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

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

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