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