Coverage for src\pqlattice\_utils.py: 21%

94 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-01-10 12:32 +0100

1from fractions import Fraction 

2from typing import Any 

3 

4import numpy as np 

5from numpy.typing import ArrayLike 

6 

7from .typing import Array, Matrix, Vector, is_integer, is_Matrix, is_rational, is_Vector, validate_aliases 

8 

9 

10def as_integer(obj: ArrayLike) -> Array: 

11 """ 

12 Helper function that converts given obj to numpy's array of python's ints allowing arbitrary large elements 

13 

14 Parameters 

15 ---------- 

16 obj : ArrayLike 

17 object to be converted to numpy's array 

18 

19 Returns 

20 ------- 

21 Array 

22 numpy's array with dtype=object and elements converted to int 

23 

24 Examples 

25 -------- 

26 >>> import pqlattice as pq 

27 >>> pq.as_integer([3**100, 2**100, 5**50]) 

28 array([515377520732011331036461129765621272702107522001, 

29 1267650600228229401496703205376, 

30 88817841970012523233890533447265625], dtype=object) 

31 """ 

32 arr = np.array(obj, dtype=object) 

33 if arr.size == 0: 

34 return arr 

35 else: 

36 return (np.vectorize(int)(arr.flat).reshape(arr.shape)).astype(object) 

37 

38 

39def as_rational(obj: ArrayLike) -> Array: 

40 """ 

41 Helper function that converts given obj to numpy's array of python's fractions.Fraction allowing arbitrary big rational elements 

42 

43 Parameters 

44 ---------- 

45 obj : ArrayLike 

46 object to be converted to numpy's array 

47 

48 Returns 

49 ------- 

50 Array 

51 numpy's array with dtype=object and elements converted to fractions.Fraction 

52 

53 Examples 

54 -------- 

55 >>> import pqlattice as pq 

56 >>> pq.as_rational([3**100, 2**100, 5**50]) 

57 array([Fraction(515377520732011331036461129765621272702107522001, 1), 

58 Fraction(1267650600228229401496703205376, 1), 

59 Fraction(88817841970012523233890533447265625, 1)], dtype=object) 

60 """ 

61 arr = np.array(obj, dtype=object) 

62 if arr.size == 0: 

63 return arr 

64 else: 

65 return (np.vectorize(Fraction)(arr.flat).reshape(arr.shape)).astype(object) 

66 

67 

68def zeros_vec(n: int) -> Vector: 

69 return as_integer(np.zeros((n,))) 

70 

71 

72def zeros_mat(rows: int, cols: int | None = None) -> Matrix: 

73 if cols is None: 

74 cols = rows 

75 return as_integer(np.zeros((rows, cols))) 

76 

77 

78@validate_aliases 

79def show(a: Array, max_rows: int = 10, max_cols: int = 10, val_width: int = 15): 

80 """ 

81 Helper function that prints the numpy's array in a human redable format 

82 

83 Parameters 

84 ---------- 

85 a : Array 

86 The array to print 

87 max_rows : int, optional 

88 Max number of rows to display before truncating, by default 10 

89 max_cols : int, optional 

90 Max number of columns to display before truncating, by default 10 

91 val_width : int, optional 

92 Max characters per cell, by default 15. If a string representation of element is longer, it is truncated e.g 1234...5678 

93 

94 Examples 

95 -------- 

96 >>> import pqlattice as pq 

97 >>> M = pq.random.distribution.Uniform(0, 2**50, seed=0).sample_matrix(7, 5) 

98 >>> pq.show(M) 

99 Matrix of integers with shape: 7 x 5 

100 ==================================== 

101 [0] [1] [2] [3] [4] 

102 [0] 867496826243021 91162487198805 109421..4040930 806253307773444 491889324856851 

103 [1] 313616384600182 314680579360371 213540430176889 330931104930059 222394738660569 

104 [2] 166055160201467 743539086037546 796665326308852 712012953150114 460445890320316 

105 [3] 996855368208390 140240390954947 210028256050344 750154124310314 141827853726696 

106 [4] 499232256057935 320872572303314 205400145011268 110177..2031755 678794279728913 

107 [5] 655478801553847 281048514639229 749289460799082 457570956347073 647748016542327 

108 [6] 206336435080453 713924001980837 545175556185458 414036094290124 74247901643189 

109 """ 

110 

111 def format_val(val: Any) -> str: 

112 s = str(val) 

113 if len(s) > val_width: 

114 mid = (val_width - 2) // 2 

115 remainder = (val_width - 2) % 2 

116 return f"{s[:mid]}..{s[-(mid + remainder) :]}" 

117 return s 

118 

119 element_type: str = f"{a.dtype}" 

120 if is_integer(a): 

121 element_type = "integers" 

122 if is_rational(a): 

123 element_type = "rationals" 

124 

125 info_header = f"numpy array of {element_type} with shape: {a.shape}" 

126 

127 is_v = False 

128 if is_Matrix(a): 

129 rows, cols = a.shape 

130 info_header = f"Matrix of {element_type} with shape: {rows} x {cols}" 

131 elif is_Vector(a): 

132 dim = a.shape[0] 

133 info_header = f"Vector of {element_type} with shape: {dim}" 

134 is_v = True 

135 rows, cols = 1, dim 

136 else: 

137 print(info_header) 

138 print("=" * len(info_header)) 

139 print(f"{a}") 

140 return 

141 

142 print(info_header) 

143 print("=" * len(info_header)) 

144 

145 ellipsis_col_idx: int | None = None 

146 ellipsis_row_idx: int | None = None 

147 if rows <= max_rows: 

148 row_indices = list(range(rows)) 

149 show_row_ellipsis = False 

150 else: 

151 # Top half and bottom half 

152 r_cut = max_rows // 2 

153 row_indices = list(range(r_cut)) + list(range(rows - r_cut, rows)) 

154 show_row_ellipsis = True 

155 ellipsis_row_idx = r_cut 

156 

157 if cols <= max_cols: 

158 col_indices = list(range(cols)) 

159 show_col_ellipsis = False 

160 else: 

161 c_cut = max_cols // 2 

162 col_indices = list(range(c_cut)) + list(range(cols - c_cut, cols)) 

163 show_col_ellipsis = True 

164 ellipsis_col_idx = c_cut 

165 

166 header = [""] 

167 for i, c_idx in enumerate(col_indices): 

168 if show_col_ellipsis and i == ellipsis_col_idx: 

169 header.append("...") 

170 header.append(f"[{c_idx}]") 

171 

172 table_data = [header] 

173 

174 for i, r_idx in enumerate(row_indices): 

175 if show_row_ellipsis and i == ellipsis_row_idx: 

176 ellipsis_row = ["..."] + ["..."] * (len(header) - 1) 

177 table_data.append(ellipsis_row) 

178 

179 row_str = [f"[{r_idx}]"] 

180 

181 for j, c_idx in enumerate(col_indices): 

182 if show_col_ellipsis and j == ellipsis_col_idx: 

183 row_str.append("...") 

184 

185 val = a[c_idx] if is_v else a[r_idx, c_idx] 

186 row_str.append(format_val(val)) 

187 

188 table_data.append(row_str) 

189 

190 num_display_cols = len(table_data[0]) 

191 col_widths = [0] * num_display_cols 

192 

193 for row in table_data: 

194 for idx, cell in enumerate(row): 

195 col_widths[idx] = max(col_widths[idx], len(cell)) 

196 

197 for row in table_data: 

198 formatted_row: list[str] = [] 

199 for idx, cell in enumerate(row): 

200 formatted_row.append(cell.rjust(col_widths[idx])) 

201 print(" ".join(formatted_row))