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

1 from fractions import Fraction

2 from typing import Any

3

4 import numpy as np

5 from numpy.typing import ArrayLike

6

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

8

9

10 def 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

39 def 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

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

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

70

71

72 def 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

79 def 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))