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