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

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

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

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