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

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

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

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