flopscope 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. benchmarks/__init__.py +1 -0
  2. benchmarks/__main__.py +6 -0
  3. benchmarks/_baseline.py +171 -0
  4. benchmarks/_bitwise.py +231 -0
  5. benchmarks/_complex.py +176 -0
  6. benchmarks/_contractions.py +291 -0
  7. benchmarks/_fft.py +198 -0
  8. benchmarks/_impl_urls.py +139 -0
  9. benchmarks/_linalg.py +197 -0
  10. benchmarks/_linalg_delegates.py +407 -0
  11. benchmarks/_metadata.py +141 -0
  12. benchmarks/_misc.py +653 -0
  13. benchmarks/_perf.py +321 -0
  14. benchmarks/_perm_group_calibration.py +175 -0
  15. benchmarks/_pointwise.py +372 -0
  16. benchmarks/_polynomial.py +193 -0
  17. benchmarks/_random.py +209 -0
  18. benchmarks/_reductions.py +136 -0
  19. benchmarks/_sorting.py +289 -0
  20. benchmarks/_stats.py +137 -0
  21. benchmarks/_window.py +92 -0
  22. benchmarks/accumulation/__init__.py +0 -0
  23. benchmarks/accumulation/bench_cost_compute.py +138 -0
  24. benchmarks/dashboard.py +312 -0
  25. benchmarks/runner.py +636 -0
  26. flopscope/__init__.py +273 -0
  27. flopscope/_accumulation/__init__.py +13 -0
  28. flopscope/_accumulation/_bipartite.py +121 -0
  29. flopscope/_accumulation/_burnside.py +51 -0
  30. flopscope/_accumulation/_cache.py +146 -0
  31. flopscope/_accumulation/_components.py +153 -0
  32. flopscope/_accumulation/_cost.py +1414 -0
  33. flopscope/_accumulation/_cost_descriptions.py +63 -0
  34. flopscope/_accumulation/_detection.py +318 -0
  35. flopscope/_accumulation/_ladder.py +191 -0
  36. flopscope/_accumulation/_output_orbit.py +104 -0
  37. flopscope/_accumulation/_partition.py +290 -0
  38. flopscope/_accumulation/_path_info.py +211 -0
  39. flopscope/_accumulation/_public.py +169 -0
  40. flopscope/_accumulation/_reduction.py +310 -0
  41. flopscope/_accumulation/_regimes.py +303 -0
  42. flopscope/_accumulation/_shape.py +33 -0
  43. flopscope/_accumulation/_wreath.py +209 -0
  44. flopscope/_budget.py +1027 -0
  45. flopscope/_config.py +118 -0
  46. flopscope/_counting_ops.py +451 -0
  47. flopscope/_display.py +478 -0
  48. flopscope/_docstrings.py +59 -0
  49. flopscope/_dtypes.py +20 -0
  50. flopscope/_einsum.py +717 -0
  51. flopscope/_errstate.py +25 -0
  52. flopscope/_flops.py +282 -0
  53. flopscope/_free_ops.py +2654 -0
  54. flopscope/_ndarray.py +1126 -0
  55. flopscope/_opt_einsum/LICENSE +21 -0
  56. flopscope/_opt_einsum/NOTICE +59 -0
  57. flopscope/_opt_einsum/__init__.py +209 -0
  58. flopscope/_opt_einsum/_contract.py +1478 -0
  59. flopscope/_opt_einsum/_helpers.py +164 -0
  60. flopscope/_opt_einsum/_hsluv.py +273 -0
  61. flopscope/_opt_einsum/_path_random.py +462 -0
  62. flopscope/_opt_einsum/_paths.py +1653 -0
  63. flopscope/_opt_einsum/_subgraph_symmetry.py +544 -0
  64. flopscope/_opt_einsum/_symmetry.py +140 -0
  65. flopscope/_opt_einsum/_typing.py +37 -0
  66. flopscope/_perm_group.py +717 -0
  67. flopscope/_pointwise.py +2522 -0
  68. flopscope/_polynomial.py +278 -0
  69. flopscope/_registry.py +3216 -0
  70. flopscope/_sorting_ops.py +571 -0
  71. flopscope/_symmetric.py +812 -0
  72. flopscope/_symmetry_transport.py +510 -0
  73. flopscope/_symmetry_utils.py +669 -0
  74. flopscope/_type_info.py +12 -0
  75. flopscope/_unwrap.py +70 -0
  76. flopscope/_validation.py +83 -0
  77. flopscope/_version_check.py +46 -0
  78. flopscope/_weights.py +195 -0
  79. flopscope/_window.py +177 -0
  80. flopscope/accounting.py +565 -0
  81. flopscope/data/default_weights.json +462 -0
  82. flopscope/data/weights.csv +509 -0
  83. flopscope/errors.py +197 -0
  84. flopscope/numpy/__init__.py +878 -0
  85. flopscope/numpy/fft/__init__.py +55 -0
  86. flopscope/numpy/fft/_free.py +51 -0
  87. flopscope/numpy/fft/_transforms.py +695 -0
  88. flopscope/numpy/linalg/__init__.py +105 -0
  89. flopscope/numpy/linalg/_aliases.py +126 -0
  90. flopscope/numpy/linalg/_compound.py +161 -0
  91. flopscope/numpy/linalg/_decompositions.py +353 -0
  92. flopscope/numpy/linalg/_properties.py +533 -0
  93. flopscope/numpy/linalg/_solvers.py +444 -0
  94. flopscope/numpy/linalg/_svd.py +122 -0
  95. flopscope/numpy/random/__init__.py +684 -0
  96. flopscope/numpy/random/_cost_formulas.py +115 -0
  97. flopscope/numpy/random/_counted_classes.py +241 -0
  98. flopscope/numpy/testing/__init__.py +13 -0
  99. flopscope/numpy/typing/__init__.py +30 -0
  100. flopscope/py.typed +0 -0
  101. flopscope/stats/__init__.py +84 -0
  102. flopscope/stats/_base.py +77 -0
  103. flopscope/stats/_cauchy.py +146 -0
  104. flopscope/stats/_erf.py +190 -0
  105. flopscope/stats/_expon.py +146 -0
  106. flopscope/stats/_laplace.py +150 -0
  107. flopscope/stats/_logistic.py +148 -0
  108. flopscope/stats/_lognorm.py +160 -0
  109. flopscope/stats/_ndtri.py +133 -0
  110. flopscope/stats/_norm.py +149 -0
  111. flopscope/stats/_truncnorm.py +186 -0
  112. flopscope/stats/_uniform.py +141 -0
  113. flopscope-0.2.0.dist-info/METADATA +23 -0
  114. flopscope-0.2.0.dist-info/RECORD +115 -0
  115. flopscope-0.2.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,209 @@
1
+ """Direct enumerator for the wreath product ∏_i (H_i ≀ S_{m_i}).
2
+
3
+ `i` indexes identical-operand groups (operands sharing the same name).
4
+ `H_i` is each operand's declared axis symmetry on its own axes.
5
+ `m_i` is the number of copies of operand i.
6
+
7
+ Each wreath element is a row permutation σ on the U-vertices, paired with
8
+ factorization metadata that names the (outer-S_{m_i}, base-H_i) decomposition
9
+ for diagnostic display.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import itertools
15
+ from collections.abc import Iterator, Sequence
16
+ from dataclasses import dataclass
17
+ from typing import Any
18
+
19
+ from flopscope._perm_group import SymmetryGroup, _dimino
20
+ from flopscope._perm_group import _Permutation as Permutation
21
+
22
+
23
+ @dataclass(frozen=True)
24
+ class WreathElement:
25
+ """One element of ∏_i (H_i ≀ S_{m_i}). Carries the row permutation and provenance."""
26
+
27
+ row_perm: Permutation
28
+ factorization: dict[str, Any]
29
+
30
+
31
+ def enumerate_h(sym: Any, rank: int) -> Iterator[Permutation]:
32
+ """Enumerate every element of the rank-`rank` group described by `sym`.
33
+
34
+ `sym` may be:
35
+ - None or 'none' → identity only
36
+ - 'symmetric' → S_rank
37
+ - 'cyclic' → C_rank
38
+ - 'dihedral' → D_rank
39
+ - a SymmetryGroup object → use its elements directly
40
+ - a dict with {'type': 'custom', 'generators': [...]} → custom group
41
+
42
+ Returns rank-`rank` permutations (operate on positions 0..rank-1).
43
+ """
44
+ identity = Permutation.identity(rank)
45
+ if sym is None or sym == "none":
46
+ yield identity
47
+ return
48
+
49
+ if isinstance(sym, SymmetryGroup):
50
+ axes = getattr(sym, "axes", None)
51
+ for el in sym.elements():
52
+ arr = list(range(rank))
53
+ if axes is not None:
54
+ # elements() yields permutations on positions 0..len(axes)-1;
55
+ # map them to the actual tensor axis positions via sym.axes.
56
+ for local_i, local_j in enumerate(el.array_form):
57
+ if local_i < len(axes) and local_j < len(axes):
58
+ from_axis = axes[local_i]
59
+ to_axis = axes[local_j]
60
+ if from_axis < rank and to_axis < rank:
61
+ arr[from_axis] = to_axis
62
+ else:
63
+ # No axes annotation; embed at zero offset (legacy path).
64
+ for i, j in enumerate(el.array_form):
65
+ if i < rank:
66
+ arr[i] = j if j < rank else i
67
+ yield Permutation(arr)
68
+ return
69
+
70
+ if sym == "symmetric" or (isinstance(sym, dict) and sym.get("type") == "symmetric"):
71
+ gens = []
72
+ for k in range(rank - 1):
73
+ arr = list(range(rank))
74
+ arr[k], arr[k + 1] = arr[k + 1], arr[k]
75
+ gens.append(Permutation(arr))
76
+ if not gens:
77
+ yield identity
78
+ return
79
+ for el in _dimino(tuple(gens)):
80
+ yield el
81
+ return
82
+
83
+ if sym == "cyclic" or (isinstance(sym, dict) and sym.get("type") == "cyclic"):
84
+ if rank <= 1:
85
+ yield identity
86
+ return
87
+ rotation = list(range(1, rank)) + [0]
88
+ for el in _dimino((Permutation(rotation),)):
89
+ yield el
90
+ return
91
+
92
+ if sym == "dihedral" or (isinstance(sym, dict) and sym.get("type") == "dihedral"):
93
+ if rank <= 2:
94
+ for el in enumerate_h("symmetric", rank):
95
+ yield el
96
+ return
97
+ rot = list(range(1, rank)) + [0]
98
+ ref = list(range(rank))
99
+ for k in range(rank // 2):
100
+ ref[k], ref[rank - 1 - k] = ref[rank - 1 - k], ref[k]
101
+ for el in _dimino((Permutation(rot), Permutation(ref))):
102
+ yield el
103
+ return
104
+
105
+ raise ValueError(f"unsupported symmetry declaration: {sym!r}")
106
+
107
+
108
+ def _outer_permutations(m: int) -> Iterator[list[int]]:
109
+ """Yield every permutation array of length m (S_m). Used for the outer factor."""
110
+ for perm_tuple in itertools.permutations(range(m)):
111
+ yield list(perm_tuple)
112
+
113
+
114
+ def _flatten_factor_to_row_perm(
115
+ group: Sequence[int],
116
+ base_tuple: Sequence[Permutation],
117
+ top_perm: Sequence[int],
118
+ u_offsets: Sequence[int],
119
+ axis_ranks: Sequence[int],
120
+ n_u: int,
121
+ ) -> list[int]:
122
+ """Build row-perm contribution for one identical-group factor.
123
+
124
+ Mirrors JS flattenFactorToRowPerm: arr[to] = from (inverse representation
125
+ consistent with the JS engine).
126
+ top_perm[j] = new position of copy j within the group.
127
+ base_tuple[j] = axis permutation applied to copy j's axes before relocation.
128
+ """
129
+ arr = list(range(n_u))
130
+ for j in range(len(group)):
131
+ p = group[j]
132
+ rank = axis_ranks[p]
133
+ new_j = top_perm[j]
134
+ new_p = group[new_j]
135
+ h = base_tuple[j]
136
+ for a in range(rank):
137
+ from_idx = u_offsets[p] + a
138
+ to_idx = u_offsets[new_p] + h.array_form[a]
139
+ arr[to_idx] = from_idx
140
+ return arr
141
+
142
+
143
+ def enumerate_wreath(
144
+ *,
145
+ identical_groups: Sequence[Sequence[int]],
146
+ per_op_symmetry: Sequence[Any],
147
+ axis_ranks: Sequence[int],
148
+ u_offsets: Sequence[int],
149
+ ) -> Iterator[WreathElement]:
150
+ """Iterate ∏_i (H_i ≀ S_{m_i}) and yield row permutations on the U-vertices.
151
+
152
+ `identical_groups`: tuple of operand-index tuples, each grouping copies of
153
+ the same operand.
154
+ `per_op_symmetry`: parallel to operand index — declared H_i for each operand.
155
+ `axis_ranks`: parallel — number of axes per operand.
156
+ `u_offsets`: parallel — starting U-vertex index for each operand.
157
+ """
158
+ total_u = sum(axis_ranks)
159
+
160
+ # For each identical-group, build a list of (arr, factor_meta) pairs.
161
+ per_group_options: list[list[tuple[list[int], dict]]] = []
162
+ for grp in identical_groups:
163
+ m = len(grp)
164
+ # Base H_i — all copies in the group share the same declared symmetry.
165
+ base_sym = per_op_symmetry[grp[0]]
166
+ base_rank = axis_ranks[grp[0]]
167
+ h_elements = list(enumerate_h(base_sym, base_rank))
168
+
169
+ group_options: list[tuple[list[int], dict]] = []
170
+ for top_perm in _outer_permutations(m):
171
+ for base_tuple in itertools.product(h_elements, repeat=m):
172
+ arr = _flatten_factor_to_row_perm(
173
+ grp, base_tuple, top_perm, u_offsets, axis_ranks, total_u
174
+ )
175
+ group_options.append(
176
+ (
177
+ arr,
178
+ {
179
+ "group": tuple(grp),
180
+ "outer": tuple(top_perm),
181
+ "base_arrs": tuple(tuple(h.array_form) for h in base_tuple),
182
+ },
183
+ )
184
+ )
185
+ per_group_options.append(group_options)
186
+
187
+ if not per_group_options:
188
+ # No operands: just identity.
189
+ yield WreathElement(
190
+ row_perm=Permutation.identity(total_u),
191
+ factorization={"groups": ()},
192
+ )
193
+ return
194
+
195
+ # Cartesian product across groups: merge contributions into a single row perm.
196
+ # Different groups touch disjoint U-vertex ranges, so merge = overwrite non-identity.
197
+ for combo in itertools.product(*per_group_options):
198
+ row_perm_arr = list(range(total_u))
199
+ for arr, _factor in combo:
200
+ for i in range(total_u):
201
+ if arr[i] != i:
202
+ row_perm_arr[i] = arr[i]
203
+ factorization = {
204
+ "groups": tuple(factor for _, factor in combo),
205
+ }
206
+ yield WreathElement(
207
+ row_perm=Permutation(row_perm_arr),
208
+ factorization=factorization,
209
+ )