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