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

revision 784 by ksteube, Mon Jul 10 04:00:08 2006 UTC revision 785 by gross, Tue Jul 25 03:48:10 2006 UTC
# Line 2939  def trace(arg,axis_offset=0): Line 2939  def trace(arg,axis_offset=0):
2939     if isinstance(arg,numarray.NumArray):     if isinstance(arg,numarray.NumArray):
2940        sh=arg.shape        sh=arg.shape
2941        if len(sh)<2:        if len(sh)<2:
2942          raise ValueError,"trace: rank of argument must be greater than 1"          raise ValueError,"rank of argument must be greater than 1"
2943        if axis_offset<0 or axis_offset>len(sh)-2:        if axis_offset<0 or axis_offset>len(sh)-2:
2944          raise ValueError,"trace: axis_offset must be between 0 and %s"%len(sh)-2          raise ValueError,"axis_offset must be between 0 and %s"%len(sh)-2
2945        s1=1        s1=1
2946        for i in range(axis_offset): s1*=sh[i]        for i in range(axis_offset): s1*=sh[i]
2947        s2=1        s2=1
2948        for i in range(axis_offset+2,len(sh)): s2*=sh[i]        for i in range(axis_offset+2,len(sh)): s2*=sh[i]
2949        if not sh[axis_offset] == sh[axis_offset+1]:        if not sh[axis_offset] == sh[axis_offset+1]:
2950          raise ValueError,"trace: dimensions of component %s and %s must match."%(axis_offset.axis_offset+1)          raise ValueError,"dimensions of component %s and %s must match."%(axis_offset.axis_offset+1)
2951        arg_reshaped=numarray.reshape(arg,(s1,sh[axis_offset],sh[axis_offset],s2))        arg_reshaped=numarray.reshape(arg,(s1,sh[axis_offset],sh[axis_offset],s2))
2952        out=numarray.zeros([s1,s2],numarray.Float64)        out=numarray.zeros([s1,s2],numarray.Float64)
2953        for i1 in range(s1):        for i1 in range(s1):
# Line 2956  def trace(arg,axis_offset=0): Line 2956  def trace(arg,axis_offset=0):
2956        out.resize(sh[:axis_offset]+sh[axis_offset+2:])        out.resize(sh[:axis_offset]+sh[axis_offset+2:])
2957        return out        return out
2958     elif isinstance(arg,escript.Data):     elif isinstance(arg,escript.Data):
2959        return escript_trace(arg,axis_offset)        if arg.getRank()<2:
2960            raise ValueError,"rank of argument must be greater than 1"
2961          if axis_offset<0 or axis_offset>arg.getRank()-2:
2962            raise ValueError,"axis_offset must be between 0 and %s"%arg.getRank()-2
2963          s=list(arg.getShape())
2964          if not s[axis_offset] == s[axis_offset+1]:
2965            raise ValueError,"dimensions of component %s and %s must match."%(axis_offset.axis_offset+1)
2966          return arg._matrixtrace(axis_offset)
2967     elif isinstance(arg,float):     elif isinstance(arg,float):
2968        raise TypeError,"trace: illegal argument type float."        raise TypeError,"illegal argument type float."
2969     elif isinstance(arg,int):     elif isinstance(arg,int):
2970        raise TypeError,"trace: illegal argument type int."        raise TypeError,"illegal argument type int."
2971     elif isinstance(arg,Symbol):     elif isinstance(arg,Symbol):
2972        return Trace_Symbol(arg,axis_offset)        return Trace_Symbol(arg,axis_offset)
2973     else:     else:
2974        raise TypeError,"trace: Unknown argument type."        raise TypeError,"Unknown argument type."
2975
def escript_trace(arg,axis_offset):
"arg is a Data object"
if arg.getRank()<2:
raise ValueError,"escript_trace: rank of argument must be greater than 1"
if axis_offset<0 or axis_offset>arg.getRank()-2:
raise ValueError,"escript_trace: axis_offset must be between 0 and %s"%arg.getRank()-2
s=list(arg.getShape())
if not s[axis_offset] == s[axis_offset+1]:
raise ValueError,"escript_trace: dimensions of component %s and %s must match."%(axis_offset.axis_offset+1)
out=arg._matrixtrace(axis_offset)
return out
2976  class Trace_Symbol(DependendSymbol):  class Trace_Symbol(DependendSymbol):
2977     """     """
2978     L{Symbol} representing the result of the trace function     L{Symbol} representing the result of the trace function
# Line 2991  class Trace_Symbol(DependendSymbol): Line 2987  class Trace_Symbol(DependendSymbol):
2987        @type axis_offset: C{int}        @type axis_offset: C{int}
2988        """        """
2989        if arg.getRank()<2:        if arg.getRank()<2:
2990          raise ValueError,"Trace_Symbol: rank of argument must be greater than 1"          raise ValueError,"rank of argument must be greater than 1"
2991        if axis_offset<0 or axis_offset>arg.getRank()-2:        if axis_offset<0 or axis_offset>arg.getRank()-2:
2992          raise ValueError,"Trace_Symbol: axis_offset must be between 0 and %s"%arg.getRank()-2          raise ValueError,"axis_offset must be between 0 and %s"%arg.getRank()-2
2993        s=list(arg.getShape())                s=list(arg.getShape())
2994        if not s[axis_offset] == s[axis_offset+1]:        if not s[axis_offset] == s[axis_offset+1]:
2995          raise ValueError,"Trace_Symbol: dimensions of component %s and %s must match."%(axis_offset.axis_offset+1)          raise ValueError,"dimensions of component %s and %s must match."%(axis_offset.axis_offset+1)
2996        super(Trace_Symbol,self).__init__(args=[arg,axis_offset],shape=tuple(s[0:axis_offset]+s[axis_offset+2:]),dim=arg.getDim())        super(Trace_Symbol,self).__init__(args=[arg,axis_offset],shape=tuple(s[0:axis_offset]+s[axis_offset+2:]),dim=arg.getDim())
2997
2998     def getMyCode(self,argstrs,format="escript"):     def getMyCode(self,argstrs,format="escript"):
# Line 3067  def transpose(arg,axis_offset=None): Line 3063  def transpose(arg,axis_offset=None):
3063        if axis_offset==None: axis_offset=int(arg.rank/2)        if axis_offset==None: axis_offset=int(arg.rank/2)
3064        return numarray.transpose(arg,axes=range(axis_offset,arg.rank)+range(0,axis_offset))        return numarray.transpose(arg,axes=range(axis_offset,arg.rank)+range(0,axis_offset))
3065     elif isinstance(arg,escript.Data):     elif isinstance(arg,escript.Data):
3066        if axis_offset==None: axis_offset=int(arg.getRank()/2)        r=arg.getRank()
3067        return escript_transpose(arg,axis_offset)        if axis_offset==None: axis_offset=int(r/2)
3068          if axis_offset<0 or axis_offset>r:
3069            raise ValueError,"axis_offset must be between 0 and %s"%r
3070          return arg._transpose(axis_offset)
3071     elif isinstance(arg,float):     elif isinstance(arg,float):
3072        if not ( axis_offset==0 or axis_offset==None):        if not ( axis_offset==0 or axis_offset==None):
3073          raise ValueError,"transpose: axis_offset must be 0 for float argument"          raise ValueError,"axis_offset must be 0 for float argument"
3074        return arg        return arg
3075     elif isinstance(arg,int):     elif isinstance(arg,int):
3076        if not ( axis_offset==0 or axis_offset==None):        if not ( axis_offset==0 or axis_offset==None):
3077          raise ValueError,"transpose: axis_offset must be 0 for int argument"          raise ValueError,"axis_offset must be 0 for int argument"
3078        return float(arg)        return float(arg)
3079     elif isinstance(arg,Symbol):     elif isinstance(arg,Symbol):
3080        if axis_offset==None: axis_offset=int(arg.getRank()/2)        if axis_offset==None: axis_offset=int(arg.getRank()/2)
3081        return Transpose_Symbol(arg,axis_offset)        return Transpose_Symbol(arg,axis_offset)
3082     else:     else:
3083        raise TypeError,"transpose: Unknown argument type."        raise TypeError,"Unknown argument type."
3084
def escript_transpose(arg,axis_offset):
"arg is a Data object"
r=arg.getRank()
if axis_offset<0 or axis_offset>r:
raise ValueError,"escript_transpose: axis_offset must be between 0 and %s"%r
out=arg._transpose(axis_offset)
return out
3085  class Transpose_Symbol(DependendSymbol):  class Transpose_Symbol(DependendSymbol):
3086     """     """
3087     L{Symbol} representing the result of the transpose function     L{Symbol} representing the result of the transpose function
# Line 3106  class Transpose_Symbol(DependendSymbol): Line 3098  class Transpose_Symbol(DependendSymbol):
3098        """        """
3099        if axis_offset==None: axis_offset=int(arg.getRank()/2)        if axis_offset==None: axis_offset=int(arg.getRank()/2)
3100        if axis_offset<0 or axis_offset>arg.getRank():        if axis_offset<0 or axis_offset>arg.getRank():
3101          raise ValueError,"escript_transpose: axis_offset must be between 0 and %s"%r          raise ValueError,"axis_offset must be between 0 and %s"%r
3102        s=arg.getShape()        s=arg.getShape()
3103        super(Transpose_Symbol,self).__init__(args=[arg,axis_offset],shape=s[axis_offset:]+s[:axis_offset],dim=arg.getDim())        super(Transpose_Symbol,self).__init__(args=[arg,axis_offset],shape=s[axis_offset:]+s[:axis_offset],dim=arg.getDim())
3104
# Line 3173  def symmetric(arg): Line 3165  def symmetric(arg):
3165      if isinstance(arg,numarray.NumArray):      if isinstance(arg,numarray.NumArray):
3166        if arg.rank==2:        if arg.rank==2:
3167          if not (arg.shape[0]==arg.shape[1]):          if not (arg.shape[0]==arg.shape[1]):
3168             raise ValueError,"symmetric: argument must be square."             raise ValueError,"argument must be square."
3169        elif arg.rank==4:        elif arg.rank==4:
3170          if not (arg.shape[0]==arg.shape[2] and arg.shape[1]==arg.shape[3]):          if not (arg.shape[0]==arg.shape[2] and arg.shape[1]==arg.shape[3]):
3171             raise ValueError,"symmetric: argument must be square."             raise ValueError,"argument must be square."
3172        else:        else:
3173          raise ValueError,"symmetric: rank 2 or 4 is required."          raise ValueError,"rank 2 or 4 is required."
3174        return (arg+transpose(arg))/2        return (arg+transpose(arg))/2
3175      elif isinstance(arg,escript.Data):      elif isinstance(arg,escript.Data):
3176        return escript_symmetric(arg)        if arg.getRank()==2:
3177            if not (arg.getShape()[0]==arg.getShape()[1]):
3178               raise ValueError,"argument must be square."
3179            return arg._symmetric()
3180          elif arg.getRank()==4:
3181            if not (arg.getShape()[0]==arg.getShape()[2] and arg.getShape()[1]==arg.getShape()[3]):
3182               raise ValueError,"argument must be square."
3183            return arg._symmetric()
3184          else:
3185            raise ValueError,"rank 2 or 4 is required."
3186      elif isinstance(arg,float):      elif isinstance(arg,float):
3187        return arg        return arg
3188      elif isinstance(arg,int):      elif isinstance(arg,int):
# Line 3189  def symmetric(arg): Line 3190  def symmetric(arg):
3190      elif isinstance(arg,Symbol):      elif isinstance(arg,Symbol):
3191        if arg.getRank()==2:        if arg.getRank()==2:
3192          if not (arg.getShape()[0]==arg.getShape()[1]):          if not (arg.getShape()[0]==arg.getShape()[1]):
3193             raise ValueError,"symmetric: argument must be square."             raise ValueError,"argument must be square."
3194        elif arg.getRank()==4:        elif arg.getRank()==4:
3195          if not (arg.getShape()[0]==arg.getShape()[2] and arg.getShape()[1]==arg.getShape()[3]):          if not (arg.getShape()[0]==arg.getShape()[2] and arg.getShape()[1]==arg.getShape()[3]):
3196             raise ValueError,"symmetric: argument must be square."             raise ValueError,"argument must be square."
3197        else:        else:
3198          raise ValueError,"symmetric: rank 2 or 4 is required."          raise ValueError,"rank 2 or 4 is required."
3199        return (arg+transpose(arg))/2        return (arg+transpose(arg))/2
3200      else:      else:
3201        raise TypeError,"symmetric: Unknown argument type."        raise TypeError,"symmetric: Unknown argument type."
3202
def escript_symmetric(arg):
if arg.getRank()==2:
if not (arg.getShape()[0]==arg.getShape()[1]):
raise ValueError,"escript_symmetric: argument must be square."
out=arg._symmetric()
elif arg.getRank()==4:
if not (arg.getShape()[0]==arg.getShape()[2] and arg.getShape()[1]==arg.getShape()[3]):
raise ValueError,"escript_symmetric: argument must be square."
out=arg._symmetric()
else:
raise ValueError,"escript_symmetric: rank 2 or 4 is required."
return out

3203  def nonsymmetric(arg):  def nonsymmetric(arg):
3204      """      """
3205      returns the nonsymmetric part of the square matrix arg. This is (arg-transpose(arg))/2      returns the nonsymmetric part of the square matrix arg. This is (arg-transpose(arg))/2
# Line 3232  def nonsymmetric(arg): Line 3220  def nonsymmetric(arg):
3220          raise ValueError,"nonsymmetric: rank 2 or 4 is required."          raise ValueError,"nonsymmetric: rank 2 or 4 is required."
3221        return (arg-transpose(arg))/2        return (arg-transpose(arg))/2
3222      elif isinstance(arg,escript.Data):      elif isinstance(arg,escript.Data):
3223        return escript_nonsymmetric(arg)        if arg.getRank()==2:
3224            if not (arg.getShape()[0]==arg.getShape()[1]):
3225               raise ValueError,"argument must be square."
3226            return arg._nonsymmetric()
3227          elif arg.getRank()==4:
3228            if not (arg.getShape()[0]==arg.getShape()[2] and arg.getShape()[1]==arg.getShape()[3]):
3229               raise ValueError,"argument must be square."
3230            return arg._nonsymmetric()
3231          else:
3232            raise ValueError,"rank 2 or 4 is required."
3233      elif isinstance(arg,float):      elif isinstance(arg,float):
3234        return arg        return arg
3235      elif isinstance(arg,int):      elif isinstance(arg,int):
# Line 3250  def nonsymmetric(arg): Line 3247  def nonsymmetric(arg):
3247      else:      else:
3248        raise TypeError,"nonsymmetric: Unknown argument type."        raise TypeError,"nonsymmetric: Unknown argument type."
3249
def escript_nonsymmetric(arg): # this should be implemented in c++
if arg.getRank()==2:
if not (arg.getShape()[0]==arg.getShape()[1]):
raise ValueError,"escript_nonsymmetric: argument must be square."
out=arg._nonsymmetric()
elif arg.getRank()==4:
if not (arg.getShape()[0]==arg.getShape()[2] and arg.getShape()[1]==arg.getShape()[3]):
raise ValueError,"escript_nonsymmetric: argument must be square."
out=arg._nonsymmetric()
else:
raise ValueError,"escript_nonsymmetric: rank 2 or 4 is required."
return out

3250  def inverse(arg):  def inverse(arg):
3251      """      """
3252      returns the inverse of the square matrix arg.      returns the inverse of the square matrix arg.
# Line 3407  class Inverse_Symbol(DependendSymbol): Line 3390  class Inverse_Symbol(DependendSymbol):
3390        if arg==self:        if arg==self:
3391           return identity(self.getShape())           return identity(self.getShape())
3392        else:        else:
3393           return -matrixmult(matrixmult(self,self.getDifferentiatedArguments(arg)[0]),self)           return -matrix_mult(matrix_mult(self,self.getDifferentiatedArguments(arg)[0]),self)
3394
3395  def eigenvalues(arg):  def eigenvalues(arg):
3396      """      """
# Line 3995  def inner(arg0,arg1): Line 3978  def inner(arg0,arg1):
3978          raise ValueError,"inner: shape of arguments does not match"          raise ValueError,"inner: shape of arguments does not match"
3979      return generalTensorProduct(arg0,arg1,axis_offset=len(sh0))      return generalTensorProduct(arg0,arg1,axis_offset=len(sh0))
3980
3981  def matrixmult(arg0,arg1):  def outer(arg0,arg1):
3982        """
3983        the outer product of the two argument:
3984
3985        out[t,s]=arg0[t]*arg1[s]
3986
3987        where
3988
3989            - s runs through arg0.Shape
3990            - t runs through arg1.Shape
3991
3992        @param arg0: first argument
3993        @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}
3994        @param arg1: second argument
3995        @type arg1: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}
3996        @return: the outer product of arg0 and arg1 at each data point
3997        @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input
3998        """
3999        return generalTensorProduct(arg0,arg1,axis_offset=0)
4000
4001    def matrixmul(arg0,arg1):
4002        """
4003        see L{matrix_mult}
4004        """
4005        return matrix_mult(arg0,arg1)
4006
4007    def matrix_mult(arg0,arg1):
4008      """      """
4009      matrix-matrix or matrix-vector product of the two argument:      matrix-matrix or matrix-vector product of the two argument:
4010
# Line 4005  def matrixmult(arg0,arg1): Line 4014  def matrixmult(arg0,arg1):
4014
4015      out[s0,s1]=S{Sigma}_{r0} arg0[s0,r0]*arg1[r0,s1]      out[s0,s1]=S{Sigma}_{r0} arg0[s0,r0]*arg1[r0,s1]
4016
4017      The second dimension of arg0 and the length of arg1 must match.      The second dimension of arg0 and the first dimension of arg1 must match.
4018
4019      @param arg0: first argument of rank 2      @param arg0: first argument of rank 2
4020      @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}      @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
# Line 4023  def matrixmult(arg0,arg1): Line 4032  def matrixmult(arg0,arg1):
4032          raise ValueError,"second argument must have rank 1 or 2"          raise ValueError,"second argument must have rank 1 or 2"
4033      return generalTensorProduct(arg0,arg1,axis_offset=1)      return generalTensorProduct(arg0,arg1,axis_offset=1)
4034
4035  def outer(arg0,arg1):  def tensormult(arg0,arg1):
4036      """      """
4037      the outer product of the two argument:      use L{tensor_mult}

out[t,s]=arg0[t]*arg1[s]

where

- s runs through arg0.Shape
- t runs through arg1.Shape

@param arg0: first argument
@type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}
@param arg1: second argument
@type arg1: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}
@return: the outer product of arg0 and arg1 at each data point
@rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input
4038      """      """
4039      return generalTensorProduct(arg0,arg1,axis_offset=0)      return tensor_mult(arg0,arg1)

4040
4041  def tensormult(arg0,arg1):  def tensor_mult(arg0,arg1):
4042      """      """
4043      the tensor product of the two argument:      the tensor product of the two argument:
4044
# Line 4069  def tensormult(arg0,arg1): Line 4063  def tensormult(arg0,arg1):
4063
4064      out[s0,s1]=S{Sigma}_{r0,r1} arg0[s0,s1,r0,r1]*arg1[r0,r1]      out[s0,s1]=S{Sigma}_{r0,r1} arg0[s0,s1,r0,r1]*arg1[r0,r1]
4065
4066      In the first case the the second dimension of arg0 and the length of arg1 must match and        In the first case the the second dimension of arg0 and the last dimension of arg1 must match and
4067      in the second case the two last dimensions of arg0 must match the shape of arg1.      in the second case the two last dimensions of arg0 must match the two first dimensions of arg1.
4068
4069      @param arg0: first argument of rank 2 or 4      @param arg0: first argument of rank 2 or 4
4070      @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}      @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
# Line 4086  def tensormult(arg0,arg1): Line 4080  def tensormult(arg0,arg1):
4080      elif len(sh0)==4 and (len(sh1)==2 or len(sh1)==3 or len(sh1)==4):      elif len(sh0)==4 and (len(sh1)==2 or len(sh1)==3 or len(sh1)==4):
4081         return generalTensorProduct(arg0,arg1,axis_offset=2)         return generalTensorProduct(arg0,arg1,axis_offset=2)
4082      else:      else:
4083          raise ValueError,"tensormult: first argument must have rank 2 or 4"          raise ValueError,"tensor_mult: first argument must have rank 2 or 4"
4084
4085  def generalTensorProduct(arg0,arg1,axis_offset=0):  def generalTensorProduct(arg0,arg1,axis_offset=0):
4086      """      """
# Line 4100  def generalTensorProduct(arg0,arg1,axis_ Line 4094  def generalTensorProduct(arg0,arg1,axis_
4094          - r runs trough arg0.Shape[:axis_offset]          - r runs trough arg0.Shape[:axis_offset]
4095          - t runs through arg1.Shape[axis_offset:]          - t runs through arg1.Shape[axis_offset:]
4096
In the first case the the second dimension of arg0 and the length of arg1 must match and
in the second case the two last dimensions of arg0 must match the shape of arg1.

4097      @param arg0: first argument      @param arg0: first argument
4098      @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}      @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}
4099      @param arg1: second argument of shape greater of 1 or 2 depending on rank of arg0      @param arg1: second argument
4100      @type arg1: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}      @type arg1: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}
4101      @return: the general tensor product of arg0 and arg1 at each data point.      @return: the general tensor product of arg0 and arg1 at each data point.
4102      @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input      @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input
# Line 4118  def generalTensorProduct(arg0,arg1,axis_ Line 4109  def generalTensorProduct(arg0,arg1,axis_
4109             return GeneralTensorProduct_Symbol(arg0,arg1,axis_offset)             return GeneralTensorProduct_Symbol(arg0,arg1,axis_offset)
4110         else:         else:
4111             if not arg0.shape[arg0.rank-axis_offset:]==arg1.shape[:axis_offset]:             if not arg0.shape[arg0.rank-axis_offset:]==arg1.shape[:axis_offset]:
4112                 raise ValueError,"generalTensorProduct: dimensions of last %s components in left argument don't match the first %s components in the right argument."%(axis_offset,axis_offset)                 raise ValueError,"dimensions of last %s components in left argument don't match the first %s components in the right argument."%(axis_offset,axis_offset)
4113             arg0_c=arg0.copy()             arg0_c=arg0.copy()
4114             arg1_c=arg1.copy()             arg1_c=arg1.copy()
4115             sh0,sh1=arg0.shape,arg1.shape             sh0,sh1=arg0.shape,arg1.shape
# Line 4144  def generalTensorProduct(arg0,arg1,axis_ Line 4135  def generalTensorProduct(arg0,arg1,axis_
4135
4136  class GeneralTensorProduct_Symbol(DependendSymbol):  class GeneralTensorProduct_Symbol(DependendSymbol):
4137     """     """
4138     Symbol representing the quotient of two arguments.     Symbol representing the general tensor product of two arguments
4139     """     """
4140     def __init__(self,arg0,arg1,axis_offset=0):     def __init__(self,arg0,arg1,axis_offset=0):
4141         """         """
4142         initialization of L{Symbol} representing the quotient of two arguments         initialization of L{Symbol} representing the general tensor product of two arguments.
4143
4144         @param arg0: numerator         @param arg0: first argument
4145         @type arg0: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.         @type arg0: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
4146         @param arg1: denominator         @param arg1: second argument
4147         @type arg1: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.         @type arg1: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
4148         @raise ValueError: if both arguments do not have the same shape.         @raise ValueError: illegal dimension
4149         @note: if both arguments have a spatial dimension, they must equal.         @note: if both arguments have a spatial dimension, they must equal.
4150         """         """
4151         sh_arg0=pokeShape(arg0)         sh_arg0=pokeShape(arg0)
# Line 4247  def escript_generalTensorProduct(arg0,ar Line 4238  def escript_generalTensorProduct(arg0,ar
4238           out.__setitem__(tuple(i0+i1),s)           out.__setitem__(tuple(i0+i1),s)
4239      return out      return out
4240
4241
4242    def transposed_matrix_mult(arg0,arg1):
4243        """
4244        transposed(matrix)-matrix or transposed(matrix)-vector product of the two argument:
4245
4246        out[s0]=S{Sigma}_{r0} arg0[r0,s0]*arg1[r0]
4247
4248        or
4249
4250        out[s0,s1]=S{Sigma}_{r0} arg0[r0,s0]*arg1[r0,s1]
4251
4252        The function call transposed_matrix_mult(arg0,arg1) is equivalent to matrix_mult(transpose(arg0),arg1).
4253
4254        The first dimension of arg0 and arg1 must match.
4255
4256        @param arg0: first argument of rank 2
4257        @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
4258        @param arg1: second argument of at least rank 1
4259        @type arg1: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
4260        @return: the product of the transposed of arg0 and arg1 at each data point
4261        @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input
4262        @raise ValueError: if the shapes of the arguments are not appropriate
4263        """
4264        sh0=pokeShape(arg0)
4265        sh1=pokeShape(arg1)
4266        if not len(sh0)==2 :
4267            raise ValueError,"first argument must have rank 2"
4268        if not len(sh1)==2 and not len(sh1)==1:
4269            raise ValueError,"second argument must have rank 1 or 2"
4270        return generalTransposedTensorProduct(arg0,arg1,axis_offset=1)
4271
4272    def transposed_tensor_mult(arg0,arg1):
4273        """
4274        the tensor product of the transposed of the first and the second argument
4275
4276        for arg0 of rank 2 this is
4277
4278        out[s0]=S{Sigma}_{r0} arg0[r0,s0]*arg1[r0]
4279
4280        or
4281
4282        out[s0,s1]=S{Sigma}_{r0} arg0[r0,s0]*arg1[r0,s1]
4283
4284
4285        and for arg0 of rank 4 this is
4286
4287        out[s0,s1,s2,s3]=S{Sigma}_{r0,r1} arg0[r0,r1,s0,s1]*arg1[r0,r1,s2,s3]
4288
4289        or
4290
4291        out[s0,s1,s2]=S{Sigma}_{r0,r1} arg0[r0,r1,s0,s1]*arg1[r0,r1,s2]
4292
4293        or
4294
4295        out[s0,s1]=S{Sigma}_{r0,r1} arg0[r0,r1,s0,s1]*arg1[r0,r1]
4296
4297        In the first case the the first dimension of arg0 and the first dimension of arg1 must match and
4298        in the second case the two first dimensions of arg0 must match the two first dimension of arg1.
4299
4300        The function call transposed_tensor_mult(arg0,arg1) is equivalent to tensor_mult(transpose(arg0),arg1).
4301
4302        @param arg0: first argument of rank 2 or 4
4303        @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
4304        @param arg1: second argument of shape greater of 1 or 2 depending on rank of arg0
4305        @type arg1: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
4306        @return: the tensor product of tarnsposed of arg0 and arg1 at each data point
4307        @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input
4308        """
4309        sh0=pokeShape(arg0)
4310        sh1=pokeShape(arg1)
4311        if len(sh0)==2 and ( len(sh1)==2 or len(sh1)==1 ):
4312           return generalTransposedTensorProduct(arg0,arg1,axis_offset=1)
4313        elif len(sh0)==4 and (len(sh1)==2 or len(sh1)==3 or len(sh1)==4):
4314           return generalTransposedTensorProduct(arg0,arg1,axis_offset=2)
4315        else:
4316            raise ValueError,"first argument must have rank 2 or 4"
4317
4318    def generalTransposedTensorProduct(arg0,arg1,axis_offset=0):
4319        """
4320        generalized tensor product of transposed of arg0 and arg1:
4321
4322        out[s,t]=S{Sigma}_r arg0[r,s]*arg1[r,t]
4323
4324        where
4325
4326            - s runs through arg0.Shape[axis_offset:]
4327            - r runs trough arg0.Shape[:axis_offset]
4328            - t runs through arg1.Shape[axis_offset:]
4329
4330        The function call generalTransposedTensorProduct(arg0,arg1,axis_offset) is equivalent
4331        to generalTensorProduct(transpose(arg0,arg0.rank-axis_offset),arg1,axis_offset).
4332
4333        @param arg0: first argument
4334        @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}
4335        @param arg1: second argument
4336        @type arg1: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}
4337        @return: the general tensor product of transposed(arg0) and arg1 at each data point.
4338        @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input
4339        """
4340        if isinstance(arg0,float) and isinstance(arg1,float): return arg1*arg0
4341        arg0,arg1=matchType(arg0,arg1)
4342        # at this stage arg0 and arg0 are both numarray.NumArray or escript.Data or Symbols
4343        if isinstance(arg0,numarray.NumArray):
4344           if isinstance(arg1,Symbol):
4345               return GeneralTransposedTensorProduct_Symbol(arg0,arg1,axis_offset)
4346           else:
4347               if not arg0.shape[:axis_offset]==arg1.shape[:axis_offset]:
4348                   raise ValueError,"dimensions of last %s components in left argument don't match the first %s components in the right argument."%(axis_offset,axis_offset)
4349               arg0_c=arg0.copy()
4350               arg1_c=arg1.copy()
4351               sh0,sh1=arg0.shape,arg1.shape
4352               d0,d1,d01=1,1,1
4353               for i in sh0[axis_offset:]: d0*=i
4354               for i in sh1[axis_offset:]: d1*=i
4355               for i in sh0[:axis_offset]: d01*=i
4356               arg0_c.resize((d01,d0))
4357               arg1_c.resize((d01,d1))
4358               out=numarray.zeros((d0,d1),numarray.Float64)
4359               for i0 in range(d0):
4360                        for i1 in range(d1):
4361                             out[i0,i1]=numarray.sum(arg0_c[:,i0]*arg1_c[:,i1])
4362               out.resize(sh0[axis_offset:]+sh1[axis_offset:])
4363               return out
4364        elif isinstance(arg0,escript.Data):
4365           if isinstance(arg1,Symbol):
4366               return GeneralTransposedTensorProduct_Symbol(arg0,arg1,axis_offset)
4367           else:
4368               return escript_generalTransposedTensorProduct(arg0,arg1,axis_offset) # this calls has to be replaced by escript._generalTensorProduct(arg0,arg1,axis_offset)
4369        else:
4370           return GeneralTransposedTensorProduct_Symbol(arg0,arg1,axis_offset)
4371
4372    class GeneralTransposedTensorProduct_Symbol(DependendSymbol):
4373       """
4374       Symbol representing the general tensor product of the transposed of arg0 and arg1
4375       """
4376       def __init__(self,arg0,arg1,axis_offset=0):
4377           """
4378           initialization of L{Symbol} representing tensor product of the transposed of arg0 and arg1
4379
4380           @param arg0: first argument
4381           @type arg0: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
4382           @param arg1: second argument
4383           @type arg1: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
4384           @raise ValueError: inconsistent dimensions of arguments.
4385           @note: if both arguments have a spatial dimension, they must equal.
4386           """
4387           sh_arg0=pokeShape(arg0)
4388           sh_arg1=pokeShape(arg1)
4389           sh01=sh_arg0[:axis_offset]
4390           sh10=sh_arg1[:axis_offset]
4391           sh0=sh_arg0[axis_offset:]
4392           sh1=sh_arg1[axis_offset:]
4393           if not sh01==sh10:
4394               raise ValueError,"dimensions of last %s components in left argument don't match the first %s components in the right argument."%(axis_offset,axis_offset)
4395           DependendSymbol.__init__(self,dim=commonDim(arg0,arg1),shape=sh0+sh1,args=[arg0,arg1,axis_offset])
4396
4397       def getMyCode(self,argstrs,format="escript"):
4398          """
4399          returns a program code that can be used to evaluate the symbol.
4400
4401          @param argstrs: gives for each argument a string representing the argument for the evaluation.
4402          @type argstrs: C{list} of length 2 of C{str}.
4403          @param format: specifies the format to be used. At the moment only "escript", "str" and "text" are supported.
4404          @type format: C{str}
4405          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
4406          @rtype: C{str}
4407          @raise NotImplementedError: if the requested format is not available
4408          """
4409          if format=="escript" or format=="str" or format=="text":
4410             return "generalTransposedTensorProduct(%s,%s,axis_offset=%s)"%(argstrs[0],argstrs[1],argstrs[2])
4411          else:
4412             raise NotImplementedError,"%s does not provide program code for format %s."%(str(self),format)
4413
4414       def substitute(self,argvals):
4415          """
4416          assigns new values to symbols in the definition of the symbol.
4417          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
4418
4419          @param argvals: new values assigned to symbols
4420          @type argvals: C{dict} with keywords of type L{Symbol}.
4421          @return: result of the substitution process. Operations are executed as much as possible.
4422          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
4423          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
4424          """
4425          if argvals.has_key(self):
4426             arg=argvals[self]
4427             if self.isAppropriateValue(arg):
4428                return arg
4429             else:
4430                raise TypeError,"%s: new value is not appropriate."%str(self)
4431          else:
4432             args=self.getSubstitutedArguments(argvals)
4433             return generalTransposedTensorProduct(args[0],args[1],args[2])
4434
4435    def escript_generalTransposedTensorProduct(arg0,arg1,axis_offset): # this should be escript._generalTransposedTensorProduct
4436        "arg0 and arg1 are both Data objects but not neccesrily on the same function space. they could be identical!!!"
4437        # calculate the return shape:
4438        shape01=arg0.getShape()[:axis_offset]
4439        shape10=arg1.getShape()[:axis_offset]
4440        shape0=arg0.getShape()[axis_offset:]
4441        shape1=arg1.getShape()[axis_offset:]
4442        if not shape01==shape10:
4443            raise ValueError,"dimensions of first %s components in left argument don't match the first %s components in the right argument."%(axis_offset,axis_offset)
4444
4445        # whatr function space should be used? (this here is not good!)
4446        fs=(escript.Scalar(0.,arg0.getFunctionSpace())+escript.Scalar(0.,arg1.getFunctionSpace())).getFunctionSpace()
4447        # create return value:
4448        out=escript.Data(0.,tuple(shape0+shape1),fs)
4449        #
4450        s0=[[]]
4451        for k in shape0:
4452              s=[]
4453              for j in s0:
4454                    for i in range(k): s.append(j+[slice(i,i)])
4455              s0=s
4456        s1=[[]]
4457        for k in shape1:
4458              s=[]
4459              for j in s1:
4460                    for i in range(k): s.append(j+[slice(i,i)])
4461              s1=s
4462        s01=[[]]
4463        for k in shape01:
4464              s=[]
4465              for j in s01:
4466                    for i in range(k): s.append(j+[slice(i,i)])
4467              s01=s
4468
4469        for i0 in s0:
4470           for i1 in s1:
4471             s=escript.Scalar(0.,fs)
4472             for i01 in s01:
4473                s+=arg0.__getitem__(tuple(i01+i0))*arg1.__getitem__(tuple(i01+i1))
4474             out.__setitem__(tuple(i0+i1),s)
4475        return out
4476
4477
4478    def matrix_transposed_mult(arg0,arg1):
4479        """
4480        matrix-transposed(matrix) product of the two argument:
4481
4482        out[s0,s1]=S{Sigma}_{r0} arg0[s0,r0]*arg1[s1,r0]
4483
4484        The function call matrix_transposed_mult(arg0,arg1) is equivalent to matrix_mult(arg0,transpose(arg1)).
4485
4486        The last dimensions of arg0 and arg1 must match.
4487
4488        @param arg0: first argument of rank 2
4489        @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
4490        @param arg1: second argument of rank 2
4491        @type arg1: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
4492        @return: the product of arg0 and the transposed of arg1 at each data point
4493        @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input
4494        @raise ValueError: if the shapes of the arguments are not appropriate
4495        """
4496        sh0=pokeShape(arg0)
4497        sh1=pokeShape(arg1)
4498        if not len(sh0)==2 :
4499            raise ValueError,"first argument must have rank 2"
4500        if not len(sh1)==2 and not len(sh1)==1:
4501            raise ValueError,"second argument must have rank 1 or 2"
4502        return generalTensorTransposedProduct(arg0,arg1,axis_offset=1)
4503
4504    def tensor_transposed_mult(arg0,arg1):
4505        """
4506        the tensor product of the first and the transpose of the second argument
4507
4508        for arg0 of rank 2 this is
4509
4510        out[s0,s1]=S{Sigma}_{r0} arg0[s0,r0]*arg1[s1,r0]
4511
4512        and for arg0 of rank 4 this is
4513
4514        out[s0,s1,s2,s3]=S{Sigma}_{r0,r1} arg0[s0,s1,r0,r1]*arg1[s2,s3,r0,r1]
4515
4516        or
4517
4518        out[s0,s1,s2]=S{Sigma}_{r0,r1} arg0[s0,s1,r0,r1]*arg1[s2,r0,r1]
4519
4520        In the first case the the second dimension of arg0 and arg1 must match and
4521        in the second case the two last dimensions of arg0 must match the two last dimension of arg1.
4522
4523        The function call tensor_transpose_mult(arg0,arg1) is equivalent to tensor_mult(arg0,transpose(arg1)).
4524
4525        @param arg0: first argument of rank 2 or 4
4526        @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
4527        @param arg1: second argument of shape greater of 1 or 2 depending on rank of arg0
4528        @type arg1: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
4529        @return: the tensor product of tarnsposed of arg0 and arg1 at each data point
4530        @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input
4531        """
4532        sh0=pokeShape(arg0)
4533        sh1=pokeShape(arg1)
4534        if len(sh0)==2 and ( len(sh1)==2 or len(sh1)==1 ):
4535           return generalTensorTransposedProduct(arg0,arg1,axis_offset=1)
4536        elif len(sh0)==4 and (len(sh1)==2 or len(sh1)==3 or len(sh1)==4):
4537           return generalTensorTransposedProduct(arg0,arg1,axis_offset=2)
4538        else:
4539            raise ValueError,"first argument must have rank 2 or 4"
4540
4541    def generalTensorTransposedProduct(arg0,arg1,axis_offset=0):
4542        """
4543        generalized tensor product of transposed of arg0 and arg1:
4544
4545        out[s,t]=S{Sigma}_r arg0[s,r]*arg1[t,r]
4546
4547        where
4548
4549            - s runs through arg0.Shape[:arg0.Rank-axis_offset]
4550            - r runs trough arg0.Shape[arg1.Rank-axis_offset:]
4551            - t runs through arg1.Shape[arg1.Rank-axis_offset:]
4552
4553        The function call generalTensorTransposedProduct(arg0,arg1,axis_offset) is equivalent
4554        to generalTensorProduct(arg0,transpose(arg1,arg1.Rank-axis_offset),axis_offset).
4555
4556        @param arg0: first argument
4557        @type arg0: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}
4558        @param arg1: second argument
4559        @type arg1: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{float}, C{int}
4560        @return: the general tensor product of transposed(arg0) and arg1 at each data point.
4561        @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input
4562        """
4563        if isinstance(arg0,float) and isinstance(arg1,float): return arg1*arg0
4564        arg0,arg1=matchType(arg0,arg1)
4565        # at this stage arg0 and arg0 are both numarray.NumArray or escript.Data or Symbols
4566        if isinstance(arg0,numarray.NumArray):
4567           if isinstance(arg1,Symbol):
4568               return GeneralTensorTransposedProduct_Symbol(arg0,arg1,axis_offset)
4569           else:
4570               if not arg0.shape[arg0.rank-axis_offset:]==arg1.shape[arg1.rank-axis_offset:]:
4571                   raise ValueError,"dimensions of last %s components in left argument don't match the first %s components in the right argument."%(axis_offset,axis_offset)
4572               arg0_c=arg0.copy()
4573               arg1_c=arg1.copy()
4574               sh0,sh1=arg0.shape,arg1.shape
4575               d0,d1,d01=1,1,1
4576               for i in sh0[:arg0.rank-axis_offset]: d0*=i
4577               for i in sh1[:arg1.rank-axis_offset]: d1*=i
4578               for i in sh1[arg1.rank-axis_offset:]: d01*=i
4579               arg0_c.resize((d0,d01))
4580               arg1_c.resize((d1,d01))
4581               out=numarray.zeros((d0,d1),numarray.Float64)
4582               for i0 in range(d0):
4583                        for i1 in range(d1):
4584                             out[i0,i1]=numarray.sum(arg0_c[i0,:]*arg1_c[i1,:])
4585               out.resize(sh0[:arg0.rank-axis_offset]+sh1[:arg1.rank-axis_offset])
4586               return out
4587        elif isinstance(arg0,escript.Data):
4588           if isinstance(arg1,Symbol):
4589               return GeneralTensorTransposedProduct_Symbol(arg0,arg1,axis_offset)
4590           else:
4591               return escript_generalTensorTransposedProduct(arg0,arg1,axis_offset) # this calls has to be replaced by escript._generalTensorProduct(arg0,arg1,axis_offset)
4592        else:
4593           return GeneralTensorTransposedProduct_Symbol(arg0,arg1,axis_offset)
4594
4595    class GeneralTensorTransposedProduct_Symbol(DependendSymbol):
4596       """
4597       Symbol representing the general tensor product of arg0 and the transpose of arg1
4598       """
4599       def __init__(self,arg0,arg1,axis_offset=0):
4600           """
4601           initialization of L{Symbol} representing the general tensor product of arg0 and the transpose of arg1
4602
4603           @param arg0: first argument
4604           @type arg0: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
4605           @param arg1: second argument
4606           @type arg1: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
4607           @raise ValueError: inconsistent dimensions of arguments.
4608           @note: if both arguments have a spatial dimension, they must equal.
4609           """
4610           sh_arg0=pokeShape(arg0)
4611           sh_arg1=pokeShape(arg1)
4612           sh0=sh_arg0[:len(sh_arg0)-axis_offset]
4613           sh01=sh_arg0[len(sh_arg0)-axis_offset:]
4614           sh10=sh_arg1[len(sh_arg1)-axis_offset:]
4615           sh1=sh_arg1[:len(sh_arg1)-axis_offset]
4616           if not sh01==sh10:
4617               raise ValueError,"dimensions of last %s components in left argument don't match the last %s components in the right argument."%(axis_offset,axis_offset)
4618           DependendSymbol.__init__(self,dim=commonDim(arg0,arg1),shape=sh0+sh1,args=[arg0,arg1,axis_offset])
4619
4620       def getMyCode(self,argstrs,format="escript"):
4621          """
4622          returns a program code that can be used to evaluate the symbol.
4623
4624          @param argstrs: gives for each argument a string representing the argument for the evaluation.
4625          @type argstrs: C{list} of length 2 of C{str}.
4626          @param format: specifies the format to be used. At the moment only "escript", "str" and "text" are supported.
4627          @type format: C{str}
4628          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
4629          @rtype: C{str}
4630          @raise NotImplementedError: if the requested format is not available
4631          """
4632          if format=="escript" or format=="str" or format=="text":
4633             return "generalTensorTransposedProduct(%s,%s,axis_offset=%s)"%(argstrs[0],argstrs[1],argstrs[2])
4634          else:
4635             raise NotImplementedError,"%s does not provide program code for format %s."%(str(self),format)
4636
4637       def substitute(self,argvals):
4638          """
4639          assigns new values to symbols in the definition of the symbol.
4640          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
4641
4642          @param argvals: new values assigned to symbols
4643          @type argvals: C{dict} with keywords of type L{Symbol}.
4644          @return: result of the substitution process. Operations are executed as much as possible.
4645          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
4646          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
4647          """
4648          if argvals.has_key(self):
4649             arg=argvals[self]
4650             if self.isAppropriateValue(arg):
4651                return arg
4652             else:
4653                raise TypeError,"%s: new value is not appropriate."%str(self)
4654          else:
4655             args=self.getSubstitutedArguments(argvals)
4656             return generalTensorTransposedProduct(args[0],args[1],args[2])
4657
4658    def escript_generalTensorTransposedProduct(arg0,arg1,axis_offset): # this should be escript._generalTensorTransposedProduct
4659        "arg0 and arg1 are both Data objects but not neccesrily on the same function space. they could be identical!!!"
4660        # calculate the return shape:
4661        shape01=arg0.getShape()[arg0.getRank()-axis_offset:]
4662        shape0=arg0.getShape()[:arg0.getRank()-axis_offset]
4663        shape10=arg1.getShape()[arg1.getRank()-axis_offset:]
4664        shape1=arg1.getShape()[:arg1.getRank()-axis_offset]
4665        if not shape01==shape10:
4666            raise ValueError,"dimensions of first %s components in left argument don't match the first %s components in the right argument."%(axis_offset,axis_offset)
4667
4668        # whatr function space should be used? (this here is not good!)
4669        fs=(escript.Scalar(0.,arg0.getFunctionSpace())+escript.Scalar(0.,arg1.getFunctionSpace())).getFunctionSpace()
4670        # create return value:
4671        out=escript.Data(0.,tuple(shape0+shape1),fs)
4672        #
4673        s0=[[]]
4674        for k in shape0:
4675              s=[]
4676              for j in s0:
4677                    for i in range(k): s.append(j+[slice(i,i)])
4678              s0=s
4679        s1=[[]]
4680        for k in shape1:
4681              s=[]
4682              for j in s1:
4683                    for i in range(k): s.append(j+[slice(i,i)])
4684              s1=s
4685        s01=[[]]
4686        for k in shape01:
4687              s=[]
4688              for j in s01:
4689                    for i in range(k): s.append(j+[slice(i,i)])
4690              s01=s
4691
4692        for i0 in s0:
4693           for i1 in s1:
4694             s=escript.Scalar(0.,fs)
4695             for i01 in s01:
4696                s+=arg0.__getitem__(tuple(i0+i01))*arg1.__getitem__(tuple(i1+i01))
4697             out.__setitem__(tuple(i0+i1),s)
4698        return out
4699
4700
4701  #=========================================================  #=========================================================
4702  #  functions dealing with spatial dependency  #  functions dealing with spatial dependency

Legend:
 Removed from v.784 changed lines Added in v.785