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