/[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

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