Coverage for /usr/lib/python3/dist-packages/sympy/tensor/functions.py: 35%

55 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1from collections.abc import Iterable 

2from functools import singledispatch 

3 

4from sympy.core.expr import Expr 

5from sympy.core.mul import Mul 

6from sympy.core.singleton import S 

7from sympy.core.sympify import sympify 

8from sympy.core.parameters import global_parameters 

9 

10 

11class TensorProduct(Expr): 

12 """ 

13 Generic class for tensor products. 

14 """ 

15 is_number = False 

16 

17 def __new__(cls, *args, **kwargs): 

18 from sympy.tensor.array import NDimArray, tensorproduct, Array 

19 from sympy.matrices.expressions.matexpr import MatrixExpr 

20 from sympy.matrices.matrices import MatrixBase 

21 from sympy.strategies import flatten 

22 

23 args = [sympify(arg) for arg in args] 

24 evaluate = kwargs.get("evaluate", global_parameters.evaluate) 

25 

26 if not evaluate: 

27 obj = Expr.__new__(cls, *args) 

28 return obj 

29 

30 arrays = [] 

31 other = [] 

32 scalar = S.One 

33 for arg in args: 

34 if isinstance(arg, (Iterable, MatrixBase, NDimArray)): 

35 arrays.append(Array(arg)) 

36 elif isinstance(arg, (MatrixExpr,)): 

37 other.append(arg) 

38 else: 

39 scalar *= arg 

40 

41 coeff = scalar*tensorproduct(*arrays) 

42 if len(other) == 0: 

43 return coeff 

44 if coeff != 1: 

45 newargs = [coeff] + other 

46 else: 

47 newargs = other 

48 obj = Expr.__new__(cls, *newargs, **kwargs) 

49 return flatten(obj) 

50 

51 def rank(self): 

52 return len(self.shape) 

53 

54 def _get_args_shapes(self): 

55 from sympy.tensor.array import Array 

56 return [i.shape if hasattr(i, "shape") else Array(i).shape for i in self.args] 

57 

58 @property 

59 def shape(self): 

60 shape_list = self._get_args_shapes() 

61 return sum(shape_list, ()) 

62 

63 def __getitem__(self, index): 

64 index = iter(index) 

65 return Mul.fromiter( 

66 arg.__getitem__(tuple(next(index) for i in shp)) 

67 for arg, shp in zip(self.args, self._get_args_shapes()) 

68 ) 

69 

70 

71@singledispatch 

72def shape(expr): 

73 """ 

74 Return the shape of the *expr* as a tuple. *expr* should represent 

75 suitable object such as matrix or array. 

76 

77 Parameters 

78 ========== 

79 

80 expr : SymPy object having ``MatrixKind`` or ``ArrayKind``. 

81 

82 Raises 

83 ====== 

84 

85 NoShapeError : Raised when object with wrong kind is passed. 

86 

87 Examples 

88 ======== 

89 

90 This function returns the shape of any object representing matrix or array. 

91 

92 >>> from sympy import shape, Array, ImmutableDenseMatrix, Integral 

93 >>> from sympy.abc import x 

94 >>> A = Array([1, 2]) 

95 >>> shape(A) 

96 (2,) 

97 >>> shape(Integral(A, x)) 

98 (2,) 

99 >>> M = ImmutableDenseMatrix([1, 2]) 

100 >>> shape(M) 

101 (2, 1) 

102 >>> shape(Integral(M, x)) 

103 (2, 1) 

104 

105 You can support new type by dispatching. 

106 

107 >>> from sympy import Expr 

108 >>> class NewExpr(Expr): 

109 ... pass 

110 >>> @shape.register(NewExpr) 

111 ... def _(expr): 

112 ... return shape(expr.args[0]) 

113 >>> shape(NewExpr(M)) 

114 (2, 1) 

115 

116 If unsuitable expression is passed, ``NoShapeError()`` will be raised. 

117 

118 >>> shape(Integral(x, x)) 

119 Traceback (most recent call last): 

120 ... 

121 sympy.tensor.functions.NoShapeError: shape() called on non-array object: Integral(x, x) 

122 

123 Notes 

124 ===== 

125 

126 Array-like classes (such as ``Matrix`` or ``NDimArray``) has ``shape`` 

127 property which returns its shape, but it cannot be used for non-array 

128 classes containing array. This function returns the shape of any 

129 registered object representing array. 

130 

131 """ 

132 if hasattr(expr, "shape"): 

133 return expr.shape 

134 raise NoShapeError( 

135 "%s does not have shape, or its type is not registered to shape()." % expr) 

136 

137 

138class NoShapeError(Exception): 

139 """ 

140 Raised when ``shape()`` is called on non-array object. 

141 

142 This error can be imported from ``sympy.tensor.functions``. 

143 

144 Examples 

145 ======== 

146 

147 >>> from sympy import shape 

148 >>> from sympy.abc import x 

149 >>> shape(x) 

150 Traceback (most recent call last): 

151 ... 

152 sympy.tensor.functions.NoShapeError: shape() called on non-array object: x 

153 """ 

154 pass