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