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

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

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

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