mapFolding 0.4.0__tar.gz → 0.4.2__tar.gz

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 (49) hide show
  1. {mapfolding-0.4.0 → mapfolding-0.4.2}/PKG-INFO +40 -8
  2. {mapfolding-0.4.0 → mapfolding-0.4.2}/README.md +29 -0
  3. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/__init__.py +1 -1
  4. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/beDRY.py +69 -84
  5. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/oeis.py +6 -6
  6. mapfolding-0.4.2/mapFolding/someAssemblyRequired/__init__.py +5 -0
  7. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/someAssemblyRequired/makeJob.py +2 -8
  8. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/someAssemblyRequired/synthesizeNumba.py +8 -7
  9. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/someAssemblyRequired/synthesizeNumbaGeneralized.py +2 -48
  10. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +29 -6
  11. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/someAssemblyRequired/synthesizeNumbaModules.py +5 -3
  12. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/syntheticModules/numba_countInitialize.py +3 -3
  13. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/syntheticModules/numba_countParallel.py +5 -5
  14. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/syntheticModules/numba_countSequential.py +6 -6
  15. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/syntheticModules/numba_doTheNeedful.py +4 -4
  16. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/theDao.py +16 -13
  17. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/theSSOT.py +2 -2
  18. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/theSSOTnumba.py +0 -7
  19. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding.egg-info/PKG-INFO +40 -8
  20. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding.egg-info/SOURCES.txt +1 -0
  21. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding.egg-info/requires.txt +2 -6
  22. mapfolding-0.4.2/pyproject.toml +77 -0
  23. {mapfolding-0.4.0 → mapfolding-0.4.2}/tests/conftest.py +27 -43
  24. mapfolding-0.4.2/tests/test_computations.py +79 -0
  25. {mapfolding-0.4.0 → mapfolding-0.4.2}/tests/test_oeis.py +0 -9
  26. {mapfolding-0.4.0 → mapfolding-0.4.2}/tests/test_other.py +0 -1
  27. {mapfolding-0.4.0 → mapfolding-0.4.2}/tests/test_tasks.py +0 -4
  28. mapfolding-0.4.0/mapFolding/someAssemblyRequired/__init__.py +0 -2
  29. mapfolding-0.4.0/pyproject.toml +0 -95
  30. {mapfolding-0.4.0 → mapfolding-0.4.2}/LICENSE +0 -0
  31. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/basecamp.py +0 -0
  32. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/reference/flattened.py +0 -0
  33. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/reference/hunterNumba.py +0 -0
  34. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/reference/irvineJavaPort.py +0 -0
  35. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/reference/jax.py +0 -0
  36. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/reference/lunnan.py +0 -0
  37. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/reference/lunnanNumpy.py +0 -0
  38. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/reference/lunnanWhile.py +0 -0
  39. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/reference/rotatedEntryPoint.py +0 -0
  40. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/reference/total_countPlus1vsPlusN.py +0 -0
  41. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/someAssemblyRequired/getLLVMforNoReason.py +0 -0
  42. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/someAssemblyRequired/synthesizeModuleJAX.py +0 -0
  43. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding/syntheticModules/__init__.py +0 -0
  44. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding.egg-info/dependency_links.txt +0 -0
  45. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding.egg-info/entry_points.txt +0 -0
  46. {mapfolding-0.4.0 → mapfolding-0.4.2}/mapFolding.egg-info/top_level.txt +0 -0
  47. {mapfolding-0.4.0 → mapfolding-0.4.2}/setup.cfg +0 -0
  48. {mapfolding-0.4.0 → mapfolding-0.4.2}/tests/__init__.py +0 -0
  49. {mapfolding-0.4.0 → mapfolding-0.4.2}/tests/test_types.py +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: mapFolding
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: Count distinct ways to fold a map (or a strip of stamps)
5
5
  Author-email: Hunter Hogan <HunterHogan@pm.me>
6
6
  License: CC-BY-NC-4.0
7
7
  Project-URL: Donate, https://www.patreon.com/integrated
8
8
  Project-URL: Homepage, https://github.com/hunterhogan/mapFolding
9
9
  Project-URL: Repository, https://github.com/hunterhogan/mapFolding.git
10
- Keywords: A001415,A001416,A001417,A001418,A195646,folding,map folding,OEIS,stamp folding
10
+ Keywords: A001415,A001416,A001417,A001418,A195646,combinatorics,folding,map folding,OEIS,optimization,stamp folding
11
11
  Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Environment :: Console
13
13
  Classifier: Intended Audience :: Education
@@ -16,8 +16,14 @@ Classifier: Intended Audience :: Other Audience
16
16
  Classifier: Intended Audience :: Science/Research
17
17
  Classifier: Natural Language :: English
18
18
  Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3
19
24
  Classifier: Programming Language :: Python
20
25
  Classifier: Topic :: Scientific/Engineering :: Mathematics
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
27
  Classifier: Typing :: Typed
22
28
  Requires-Python: >=3.10
23
29
  Description-Content-Type: text/markdown
@@ -25,17 +31,14 @@ License-File: LICENSE
25
31
  Requires-Dist: numba
26
32
  Requires-Dist: numpy
27
33
  Requires-Dist: Z0Z_tools
28
- Provides-Extra: synthesizemodules
29
- Requires-Dist: autoflake; extra == "synthesizemodules"
30
- Requires-Dist: more_itertools; extra == "synthesizemodules"
31
- Requires-Dist: python_minifier; extra == "synthesizemodules"
32
34
  Provides-Extra: testing
33
- Requires-Dist: mypy; extra == "testing"
35
+ Requires-Dist: autoflake; extra == "testing"
36
+ Requires-Dist: more_itertools; extra == "testing"
34
37
  Requires-Dist: pytest-cov; extra == "testing"
35
38
  Requires-Dist: pytest-env; extra == "testing"
36
- Requires-Dist: pytest-mypy; extra == "testing"
37
39
  Requires-Dist: pytest-xdist; extra == "testing"
38
40
  Requires-Dist: pytest; extra == "testing"
41
+ Requires-Dist: python_minifier; extra == "testing"
39
42
  Requires-Dist: updateCitation; extra == "testing"
40
43
 
41
44
  # mapFolding: Algorithms for enumerating distinct map/stamp folding patterns 🗺️
@@ -104,6 +107,35 @@ Available OEIS sequences:
104
107
  - Transform the algorithm using AST
105
108
  - Create hyper-optimized modules to compute a specific map.
106
109
 
110
+ ### 4. **Customizing your algorithm**
111
+
112
+ - mapFolding\someAssemblyRequired\synthesizeNumbaJob.py (and/or synthesizeNumba____.py, as applicable)
113
+ - Synthesize a Numba-optimized module for a specific mapShape
114
+ - Synthesize _from_ a module in mapFolding\syntheticModules or from any source you select
115
+ - Use the existing transformation options
116
+ - Or create new ways of transforming the algorithm from its source to a specific job
117
+ - mapFolding\someAssemblyRequired\makeJob.py
118
+ - Initialize data for a specific mapShape
119
+ - mapFolding\someAssemblyRequired\synthesizeNumbaModules.py (and/or synthesizeNumba____.py, as applicable)
120
+ - Synthesize one or more Numba-optimized modules for parallel or sequential computation
121
+ - Overwrite the modules in mapFolding\syntheticModules or save the module(s) to a custom path
122
+ - Synthesize _from_ the algorithm(s) in mapFolding\theDao.py or from any source you select
123
+ - Use the existing transformation options
124
+ - Or create new ways of transforming the algorithm from its source to a new module
125
+ - Use your new module in synthesizeNumbaJob.py, above, as the source to create a mapShape-specific job module
126
+ - mapFolding\theDao.py
127
+ - Modify the algorithms for initializing values, parallel computation, and/or sequential computation
128
+ - Use the modified algorithm(s) in synthesizeNumbaModules.py, above, to create Numba-optimized version(s)
129
+ - Then use a Numba-optimized version in synthesizeNumbaJob.py, above, to create a hyper-optimized version for a specific mapShape
130
+ - mapFolding\theSSOT.py (and/or theSSOTnumba.py and/ or theSSOT____.py, if they exist)
131
+ - Modify broad settings or find functions to modify broad settings, such as data structures and their data types
132
+ - Create new settings or groups of settings
133
+ - mapFolding\beDRY.py
134
+ - Functions to handle common tasks, such as parsing parameters or creating the `connectionGraph` for a mapShape (a Cartesian product decomposition)
135
+ - mapFolding\someAssemblyRequired
136
+ - Create new transformations to optimize the algorithm, such as for JAX, CuPy, or CUDA
137
+ - (mapFolding\reference\jax.py has a once-functional JAX implementation, and synthesizeModuleJAX.py might be a useful starting point)
138
+
107
139
  ## Map-folding Video
108
140
 
109
141
  ~~This caused my neurosis:~~ I enjoyed the following video, which is what introduced me to map folding.
@@ -64,6 +64,35 @@ Available OEIS sequences:
64
64
  - Transform the algorithm using AST
65
65
  - Create hyper-optimized modules to compute a specific map.
66
66
 
67
+ ### 4. **Customizing your algorithm**
68
+
69
+ - mapFolding\someAssemblyRequired\synthesizeNumbaJob.py (and/or synthesizeNumba____.py, as applicable)
70
+ - Synthesize a Numba-optimized module for a specific mapShape
71
+ - Synthesize _from_ a module in mapFolding\syntheticModules or from any source you select
72
+ - Use the existing transformation options
73
+ - Or create new ways of transforming the algorithm from its source to a specific job
74
+ - mapFolding\someAssemblyRequired\makeJob.py
75
+ - Initialize data for a specific mapShape
76
+ - mapFolding\someAssemblyRequired\synthesizeNumbaModules.py (and/or synthesizeNumba____.py, as applicable)
77
+ - Synthesize one or more Numba-optimized modules for parallel or sequential computation
78
+ - Overwrite the modules in mapFolding\syntheticModules or save the module(s) to a custom path
79
+ - Synthesize _from_ the algorithm(s) in mapFolding\theDao.py or from any source you select
80
+ - Use the existing transformation options
81
+ - Or create new ways of transforming the algorithm from its source to a new module
82
+ - Use your new module in synthesizeNumbaJob.py, above, as the source to create a mapShape-specific job module
83
+ - mapFolding\theDao.py
84
+ - Modify the algorithms for initializing values, parallel computation, and/or sequential computation
85
+ - Use the modified algorithm(s) in synthesizeNumbaModules.py, above, to create Numba-optimized version(s)
86
+ - Then use a Numba-optimized version in synthesizeNumbaJob.py, above, to create a hyper-optimized version for a specific mapShape
87
+ - mapFolding\theSSOT.py (and/or theSSOTnumba.py and/ or theSSOT____.py, if they exist)
88
+ - Modify broad settings or find functions to modify broad settings, such as data structures and their data types
89
+ - Create new settings or groups of settings
90
+ - mapFolding\beDRY.py
91
+ - Functions to handle common tasks, such as parsing parameters or creating the `connectionGraph` for a mapShape (a Cartesian product decomposition)
92
+ - mapFolding\someAssemblyRequired
93
+ - Create new transformations to optimize the algorithm, such as for JAX, CuPy, or CUDA
94
+ - (mapFolding\reference\jax.py has a once-functional JAX implementation, and synthesizeModuleJAX.py might be a useful starting point)
95
+
67
96
  ## Map-folding Video
68
97
 
69
98
  ~~This caused my neurosis:~~ I enjoyed the following video, which is what introduced me to map folding.
@@ -22,7 +22,7 @@ from mapFolding.theSSOT import (
22
22
  # Synthesize modules
23
23
  from mapFolding.theSSOT import (
24
24
  formatModuleNameDEFAULT,
25
- getAlgorithmCallable,
25
+ getAlgorithmDispatcher,
26
26
  getAlgorithmSource,
27
27
  getPathJobRootDEFAULT,
28
28
  getPathSyntheticModules,
@@ -2,6 +2,7 @@
2
2
  from mapFolding import (
3
3
  computationState,
4
4
  getPathJobRootDEFAULT,
5
+ hackSSOTdatatype,
5
6
  hackSSOTdtype,
6
7
  indexMy,
7
8
  indexTrack,
@@ -9,9 +10,9 @@ from mapFolding import (
9
10
  setDatatypeFoldsTotal,
10
11
  setDatatypeLeavesTotal,
11
12
  )
12
- from numpy import integer
13
+ from numpy import dtype, integer, ndarray
13
14
  from numpy.typing import DTypeLike, NDArray
14
- from typing import Any, List, Optional, Sequence, Tuple, Type, Union
15
+ from typing import Any, List, Optional, Sequence, Tuple, Union
15
16
  from Z0Z_tools import defineConcurrencyLimit, intInnit, oopsieKwargsie
16
17
  import numba
17
18
  import numpy
@@ -19,7 +20,7 @@ import os
19
20
  import pathlib
20
21
  import sys
21
22
 
22
- def getFilenameFoldsTotal(mapShape: Union[Sequence[int], numpy.ndarray[Tuple[int], numpy.dtype[integer[Any]]]]) -> str:
23
+ def getFilenameFoldsTotal(mapShape: Union[Sequence[int], ndarray[Tuple[int], dtype[integer[Any]]]]) -> str:
23
24
  """Make a standardized filename for the computed value `foldsTotal`.
24
25
 
25
26
  The filename takes into account
@@ -67,30 +68,29 @@ def getLeavesTotal(listDimensions: Sequence[int]) -> int:
67
68
 
68
69
  return productDimensions
69
70
 
70
- def getPathFilenameFoldsTotal(mapShape: Union[Sequence[int], numpy.ndarray[Tuple[int], numpy.dtype[integer[Any]]]], pathLikeWriteFoldsTotal: Optional[Union[str, os.PathLike[str]]] = None) -> pathlib.Path:
71
- """Get path for folds total file.
71
+ def getPathFilenameFoldsTotal(mapShape: Union[Sequence[int], ndarray[Tuple[int], dtype[integer[Any]]]], pathLikeWriteFoldsTotal: Optional[Union[str, os.PathLike[str]]] = None) -> pathlib.Path:
72
+ """Get a standardized path and filename for the computed value `foldsTotal`.
72
73
 
73
- This function determines the file path for storing fold totals. If a path is provided,
74
- it will use that path. If the path is a directory, it will append a default filename.
75
- The function ensures the parent directory exists by creating it if necessary.
74
+ If you provide a directory, the function will append a standardized filename. If you provide a filename
75
+ or a relative path and filename, the function will prepend the default path.
76
76
 
77
77
  Parameters:
78
- mapShape (Sequence[int]): List of dimensions for the map folding problem.
79
- pathLikeWriteFoldsTotal (Union[str, os.PathLike[str]], optional): Path where to save
80
- the folds total. Can be a file path or directory path. If None, uses default path.
78
+ mapShape: List of dimensions for the map folding problem.
79
+ pathLikeWriteFoldsTotal (pathJobRootDEFAULT): Path, filename, or relative path and filename. If None, uses default path.
81
80
  Defaults to None.
82
81
 
83
82
  Returns:
84
- pathlib.Path: Complete path to the folds total file.
83
+ pathFilenameFoldsTotal: Absolute path and filename.
85
84
  """
86
- pathFilenameFoldsTotal = pathlib.Path(pathLikeWriteFoldsTotal) if pathLikeWriteFoldsTotal is not None else getPathJobRootDEFAULT()
87
- if pathFilenameFoldsTotal.is_dir():
88
- filenameFoldsTotalDEFAULT = getFilenameFoldsTotal(mapShape)
89
- pathFilenameFoldsTotal = pathFilenameFoldsTotal / filenameFoldsTotalDEFAULT
90
- elif pathlib.Path(pathLikeWriteFoldsTotal).is_absolute(): # type: ignore
91
- pathFilenameFoldsTotal = pathlib.Path(pathLikeWriteFoldsTotal) # type: ignore
85
+ pathLikeSherpa = pathlib.Path(pathLikeWriteFoldsTotal) if pathLikeWriteFoldsTotal is not None else None
86
+ if not pathLikeSherpa:
87
+ pathLikeSherpa = getPathJobRootDEFAULT()
88
+ if pathLikeSherpa.is_dir():
89
+ pathFilenameFoldsTotal = pathLikeSherpa / getFilenameFoldsTotal(mapShape)
90
+ elif pathLikeSherpa.is_absolute():
91
+ pathFilenameFoldsTotal = pathLikeSherpa
92
92
  else:
93
- pathFilenameFoldsTotal = pathlib.Path(getPathJobRootDEFAULT(), pathLikeWriteFoldsTotal) # type: ignore
93
+ pathFilenameFoldsTotal = getPathJobRootDEFAULT() / pathLikeSherpa
94
94
 
95
95
  pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
96
96
  return pathFilenameFoldsTotal
@@ -107,23 +107,23 @@ def getTaskDivisions(computationDivisions: Optional[Union[int, str]], concurrenc
107
107
  - int: direct set the number of task divisions; cannot exceed the map's total leaves
108
108
  - "maximum": divides into `leavesTotal`-many `taskDivisions`
109
109
  - "cpu": limits the divisions to the number of available CPUs, i.e. `concurrencyLimit`
110
- concurrencyLimit:
111
- Maximum number of concurrent tasks allowed
112
- CPUlimit: for error reporting
113
- listDimensions: for error reporting
110
+ concurrencyLimit:
111
+ Maximum number of concurrent tasks allowed
112
+ CPUlimit: for error reporting
113
+ listDimensions: for error reporting
114
114
 
115
115
  Returns
116
116
  -------
117
- taskDivisions:
117
+ taskDivisions:
118
118
 
119
119
  Raises
120
120
  ------
121
- ValueError
122
- If computationDivisions is an unsupported type or if resulting task divisions exceed total leaves
121
+ ValueError
122
+ If computationDivisions is an unsupported type or if resulting task divisions exceed total leaves
123
123
 
124
124
  Notes
125
125
  -----
126
- Task divisions cannot exceed total leaves to prevent duplicate counting of folds.
126
+ Task divisions should not exceed total leaves to prevent duplicate counting of folds.
127
127
  """
128
128
  taskDivisions = 0
129
129
  leavesTotal = getLeavesTotal(listDimensions)
@@ -145,7 +145,7 @@ def getTaskDivisions(computationDivisions: Optional[Union[int, str]], concurrenc
145
145
 
146
146
  return taskDivisions
147
147
 
148
- def makeConnectionGraph(listDimensions: Sequence[int], **keywordArguments: Optional[Type]) -> numpy.ndarray[Tuple[int, int, int], numpy.dtype[integer[Any]]]:
148
+ def makeConnectionGraph(listDimensions: Sequence[int], **keywordArguments: Optional[str]) -> ndarray[Tuple[int, int, int], dtype[integer[Any]]]:
149
149
  """
150
150
  Constructs a multi-dimensional connection graph representing the connections between the leaves of a map with the given dimensions.
151
151
  Also called a Cartesian product decomposition or dimensional product mapping.
@@ -157,21 +157,22 @@ def makeConnectionGraph(listDimensions: Sequence[int], **keywordArguments: Optio
157
157
  Returns
158
158
  connectionGraph: A 3D numpy array with shape of (dimensionsTotal, leavesTotal + 1, leavesTotal + 1).
159
159
  """
160
- if keywordArguments.get('datatype', None):
161
- setDatatypeLeavesTotal(keywordArguments['datatype']) # type: ignore
162
- datatype = hackSSOTdtype('connectionGraph')
160
+ ImaSetTheDatatype = keywordArguments.get('datatype', None)
161
+ if ImaSetTheDatatype:
162
+ setDatatypeLeavesTotal(ImaSetTheDatatype)
163
+ dtype = hackSSOTdtype('connectionGraph')
163
164
  mapShape = validateListDimensions(listDimensions)
164
165
  leavesTotal = getLeavesTotal(mapShape)
165
- arrayDimensions = numpy.array(mapShape, dtype=datatype)
166
+ arrayDimensions = numpy.array(mapShape, dtype=dtype)
166
167
  dimensionsTotal = len(arrayDimensions)
167
168
 
168
- cumulativeProduct = numpy.multiply.accumulate([1] + mapShape, dtype=datatype)
169
- coordinateSystem = numpy.zeros((dimensionsTotal, leavesTotal + 1), dtype=datatype)
169
+ cumulativeProduct = numpy.multiply.accumulate([1] + mapShape, dtype=dtype)
170
+ coordinateSystem = numpy.zeros((dimensionsTotal, leavesTotal + 1), dtype=dtype)
170
171
  for indexDimension in range(dimensionsTotal):
171
172
  for leaf1ndex in range(1, leavesTotal + 1):
172
173
  coordinateSystem[indexDimension, leaf1ndex] = ( ((leaf1ndex - 1) // cumulativeProduct[indexDimension]) % arrayDimensions[indexDimension] + 1 )
173
174
 
174
- connectionGraph = numpy.zeros((dimensionsTotal, leavesTotal + 1, leavesTotal + 1), dtype=datatype)
175
+ connectionGraph = numpy.zeros((dimensionsTotal, leavesTotal + 1, leavesTotal + 1), dtype=dtype)
175
176
  for indexDimension in range(dimensionsTotal):
176
177
  for activeLeaf1ndex in range(1, leavesTotal + 1):
177
178
  for connectee1ndex in range(1, activeLeaf1ndex + 1):
@@ -190,70 +191,54 @@ def makeConnectionGraph(listDimensions: Sequence[int], **keywordArguments: Optio
190
191
  return connectionGraph
191
192
 
192
193
  def makeDataContainer(shape: Union[int, Tuple[int, ...]], datatype: Optional[DTypeLike] = None) -> NDArray[integer[Any]]:
193
- """Create a zeroed-out `numpy.ndarray` with the given shape and datatype.
194
+ """Create a zeroed-out `ndarray` with the given shape and datatype.
194
195
 
195
196
  Parameters:
196
- shape (Union[int, Tuple[int, ...]]): The shape of the array. Can be an integer for 1D arrays
197
+ shape: The shape of the array. Can be an integer for 1D arrays
197
198
  or a tuple of integers for multi-dimensional arrays.
198
- datatype (Optional[DTypeLike], optional): The desired data type for the array.
199
+ datatype: The desired data type for the array.
199
200
  If None, defaults to dtypeLargeDEFAULT. Defaults to None.
200
201
 
201
202
  Returns:
202
- numpy.ndarray: A new array of given shape and type, filled with zeros.
203
+ dataContainer: A new array of given shape and type, filled with zeros.
203
204
  """
204
205
  if datatype is None:
205
206
  datatype = hackSSOTdtype('dtypeFoldsTotal')
206
207
  return numpy.zeros(shape, dtype=datatype)
207
208
 
208
- def outfitCountFolds(listDimensions: Sequence[int]
209
- , computationDivisions: Optional[Union[int, str]] = None
210
- , CPUlimit: Optional[Union[bool, float, int]] = None
211
- , **keywordArguments: Optional[Union[str, bool]]) -> computationState:
209
+ def outfitCountFolds(listDimensions: Sequence[int], computationDivisions: Optional[Union[int, str]] = None, CPUlimit: Optional[Union[bool, float, int]] = None, **keywordArguments: Optional[Union[str, bool]]) -> computationState:
212
210
  """
213
211
  Initializes and configures the computation state for map folding computations.
214
212
 
215
- Parameters
216
- ----------
217
- listDimensions:
218
- The dimensions of the map to be folded
219
- computationDivisions (None):
220
- Specifies how to divide computations:
221
- - None: no division of the computation into tasks; sets task divisions to 0
222
- - int: direct set the number of task divisions; cannot exceed the map's total leaves
223
- - "maximum": divides into `leavesTotal`-many `taskDivisions`
224
- - "cpu": limits the divisions to the number of available CPUs, i.e. `concurrencyLimit`
225
- CPUlimit (None):
226
- Whether and how to limit the CPU usage. See notes for details.
227
- **keywordArguments:
228
- Datatype management.
229
-
230
- Returns
231
- -------
232
- computationState
233
- An initialized computation state containing:
234
- - connectionGraph: Graph representing connections in the map
235
- - foldsSubTotals: Array tracking total folds
236
- - mapShape: Validated and sorted dimensions of the map
237
- - my: Array for internal state tracking
238
- - gapsWhere: Array tracking gap positions
239
- - the: Static settings and metadata
240
- - track: Array for tracking computation progress
213
+ Parameters:
214
+ listDimensions: The dimensions of the map to be folded
215
+ computationDivisions (None): see `getTaskDivisions`
216
+ CPUlimit (None): see `setCPUlimit`
217
+ **keywordArguments: Datatype management.
241
218
 
242
- Limits on CPU usage `CPUlimit`:
243
- - `False`, `None`, or `0`: No limits on CPU usage; uses all available CPUs. All other values will potentially limit CPU usage.
244
- - `True`: Yes, limit the CPU usage; limits to 1 CPU.
245
- - Integer `>= 1`: Limits usage to the specified number of CPUs.
246
- - Decimal value (`float`) between 0 and 1: Fraction of total CPUs to use.
247
- - Decimal value (`float`) between -1 and 0: Fraction of CPUs to *not* use.
248
- - Integer `<= -1`: Subtract the absolute value from total CPUs.
219
+ Returns:
220
+ stateInitialized: The initialized computation state
249
221
  """
250
- kwourGrapes = keywordArguments.get('sourGrapes', False)
251
- kwatatype = keywordArguments.get('datatypeElephino', None)
252
- if kwatatype: setDatatypeElephino(kwatatype, sourGrapes=kwourGrapes) # type: ignore
253
- kwatatype = keywordArguments.get('datatypeFoldsTotal', None)
254
- if kwatatype: setDatatypeFoldsTotal(kwatatype, sourGrapes=kwourGrapes) # type: ignore
255
- kwatatype = keywordArguments.get('datatypeLeavesTotal', None)
256
- if kwatatype: setDatatypeLeavesTotal(kwatatype, sourGrapes=kwourGrapes) # type: ignore
222
+ kwourGrapes = keywordArguments.get('sourGrapes', None)
223
+ if kwourGrapes:
224
+ sourGrapes = True
225
+ else:
226
+ sourGrapes = False
227
+
228
+ ImaSetTheDatatype = keywordArguments.get('datatypeElephino', None)
229
+ if ImaSetTheDatatype:
230
+ ImaSetTheDatatype = str(ImaSetTheDatatype)
231
+ setDatatypeElephino(ImaSetTheDatatype, sourGrapes)
232
+
233
+ ImaSetTheDatatype = keywordArguments.get('datatypeFoldsTotal', None)
234
+ if ImaSetTheDatatype:
235
+ ImaSetTheDatatype = str(ImaSetTheDatatype)
236
+ setDatatypeFoldsTotal(ImaSetTheDatatype, sourGrapes)
237
+
238
+ ImaSetTheDatatype = keywordArguments.get('datatypeLeavesTotal', None)
239
+ if ImaSetTheDatatype:
240
+ ImaSetTheDatatype = str(ImaSetTheDatatype)
241
+ setDatatypeLeavesTotal(ImaSetTheDatatype, sourGrapes)
257
242
 
258
243
  my = makeDataContainer(len(indexMy), hackSSOTdtype('my'))
259
244
 
@@ -268,7 +253,7 @@ def outfitCountFolds(listDimensions: Sequence[int]
268
253
  my[indexMy.dimensionsTotal] = len(mapShape)
269
254
  my[indexMy.leaf1ndex] = 1
270
255
  stateInitialized = computationState(
271
- connectionGraph = makeConnectionGraph(mapShape, datatype=hackSSOTdtype('connectionGraph')),
256
+ connectionGraph = makeConnectionGraph(mapShape, datatype=hackSSOTdatatype('connectionGraph')),
272
257
  foldGroups = foldGroups,
273
258
  mapShape = numpy.array(mapShape, dtype=hackSSOTdtype('mapShape')),
274
259
  my = my,
@@ -37,31 +37,31 @@ settingsOEIShardcodedValues: Dict[str, Dict[str, Any]] = {
37
37
  'getMapShape': lambda n: sorted([2, n]),
38
38
  'valuesBenchmark': [14],
39
39
  'valuesTestParallelization': [*range(3, 7)],
40
- 'valuesTestValidation': [0, 1, random.randint(2, 9)],
40
+ 'valuesTestValidation': [random.randint(2, 9)],
41
41
  },
42
42
  'A001416': {
43
43
  'getMapShape': lambda n: sorted([3, n]),
44
44
  'valuesBenchmark': [9],
45
45
  'valuesTestParallelization': [*range(3, 5)],
46
- 'valuesTestValidation': [0, 1, random.randint(2, 6)],
46
+ 'valuesTestValidation': [random.randint(2, 6)],
47
47
  },
48
48
  'A001417': {
49
49
  'getMapShape': lambda n: [2] * n,
50
50
  'valuesBenchmark': [6],
51
51
  'valuesTestParallelization': [*range(2, 4)],
52
- 'valuesTestValidation': [0, 1, random.randint(2, 4)],
52
+ 'valuesTestValidation': [random.randint(2, 4)],
53
53
  },
54
54
  'A195646': {
55
55
  'getMapShape': lambda n: [3] * n,
56
56
  'valuesBenchmark': [3],
57
57
  'valuesTestParallelization': [*range(2, 3)],
58
- 'valuesTestValidation': [0, 1, 2],
58
+ 'valuesTestValidation': [2],
59
59
  },
60
60
  'A001418': {
61
61
  'getMapShape': lambda n: [n, n],
62
62
  'valuesBenchmark': [5],
63
63
  'valuesTestParallelization': [*range(2, 4)],
64
- 'valuesTestValidation': [1, random.randint(2, 4)],
64
+ 'valuesTestValidation': [random.randint(2, 4)],
65
65
  },
66
66
  }
67
67
 
@@ -229,7 +229,7 @@ def makeSettingsOEIS() -> Dict[str, SettingsOEIS]:
229
229
  getMapShape=settingsOEIShardcodedValues[oeisID]['getMapShape'],
230
230
  valuesBenchmark=settingsOEIShardcodedValues[oeisID]['valuesBenchmark'],
231
231
  valuesTestParallelization=settingsOEIShardcodedValues[oeisID]['valuesTestParallelization'],
232
- valuesTestValidation=settingsOEIShardcodedValues[oeisID]['valuesTestValidation'],
232
+ valuesTestValidation=settingsOEIShardcodedValues[oeisID]['valuesTestValidation'] + list(range(offsetSherpa, 2)),
233
233
  valuesKnown=valuesKnownSherpa,
234
234
  valueUnknown=max(valuesKnownSherpa.keys(), default=0) + 1
235
235
  )
@@ -0,0 +1,5 @@
1
+ from mapFolding.someAssemblyRequired.getLLVMforNoReason import writeModuleLLVM
2
+ from mapFolding.someAssemblyRequired.makeJob import makeStateJob
3
+ from mapFolding.someAssemblyRequired.synthesizeNumbaGeneralized import youOughtaKnow
4
+ from mapFolding.someAssemblyRequired.synthesizeNumbaJob import writeJobNumba
5
+ from mapFolding.someAssemblyRequired.synthesizeNumbaModules import makeFlowNumbaOptimized
@@ -5,15 +5,9 @@ import pathlib
5
5
  import pickle
6
6
 
7
7
  @overload
8
- def makeStateJob(listDimensions: Sequence[int], *, writeJob: Literal[True]
9
- , **keywordArguments: Optional[str]) -> pathlib.Path:
10
- ...
11
-
8
+ def makeStateJob(listDimensions: Sequence[int], *, writeJob: Literal[True] , **keywordArguments: Optional[str]) -> pathlib.Path: ...
12
9
  @overload
13
- def makeStateJob(listDimensions: Sequence[int], *, writeJob: Literal[False]
14
- , **keywordArguments: Optional[str]) -> computationState:
15
- ...
16
-
10
+ def makeStateJob(listDimensions: Sequence[int], *, writeJob: Literal[False] , **keywordArguments: Optional[str]) -> computationState: ...
17
11
  def makeStateJob(listDimensions: Sequence[int], *, writeJob: bool = True, **keywordArguments: Optional[Any]) -> computationState | pathlib.Path:
18
12
  """
19
13
  Creates a computation state job for map folding calculations and optionally saves it to disk.
@@ -16,11 +16,11 @@ def insertArrayIn_body(FunctionDefTarget: ast.FunctionDef, identifier: str, arra
16
16
 
17
17
  def insertAssign(assignee: str, arraySlice: numpy.ndarray) -> None:
18
18
  nonlocal FunctionDefTarget
19
- onlyDataRLE = makeStrRLEcompacted(arraySlice) #NOTE
19
+ onlyDataRLE = autoDecodingRLE(arraySlice, addSpaces=True)
20
20
  astStatement = cast(ast.Expr, ast.parse(onlyDataRLE).body[0])
21
21
  dataAst = astStatement.value
22
22
 
23
- arrayCall = Then.make_astCall(name=constructorName, args=[dataAst], dictionaryKeywords={'dtype': ast.Name(id=argData_dtypeName, ctx=ast.Load())})
23
+ arrayCall = Then.make_astCall(name=constructorName, args=[dataAst], list_astKeywords=[ast.keyword(arg='dtype', value=ast.Name(id=argData_dtypeName, ctx=ast.Load()))])
24
24
 
25
25
  assignment = ast.Assign(targets=[ast.Name(id=assignee, ctx=ast.Store())], value=arrayCall)#NOTE
26
26
  FunctionDefTarget.body.insert(0, assignment)
@@ -51,15 +51,15 @@ def findAndReplaceArrayIn_body(FunctionDefTarget: ast.FunctionDef, identifier: s
51
51
  if isinstance(astSubscript.value, ast.Name) and astSubscript.value.id == identifier and isinstance(astSubscript.slice, ast.Attribute):
52
52
  indexAs_astAttribute: ast.Attribute = astSubscript.slice
53
53
  indexAsStr = ast.unparse(indexAs_astAttribute)
54
- argDataSlice = arrayTarget[eval(indexAsStr)]
54
+ arraySlice = arrayTarget[eval(indexAsStr)]
55
55
 
56
- onlyDataRLE = makeStrRLEcompacted(argDataSlice)
56
+ onlyDataRLE = autoDecodingRLE(arraySlice, addSpaces=True)
57
57
  astStatement = cast(ast.Expr, ast.parse(onlyDataRLE).body[0])
58
58
  dataAst = astStatement.value
59
59
 
60
- arrayCall = Then.make_astCall(name=constructorName, args=[dataAst], dictionaryKeywords={'dtype': ast.Name(id=argData_dtypeName, ctx=ast.Load())})
60
+ arrayCall = Then.make_astCall(name=constructorName, args=[dataAst], list_astKeywords=[ast.keyword(arg='dtype', value=ast.Name(id=argData_dtypeName, ctx=ast.Load()))])
61
61
 
62
- assignment = ast.Assign( targets=[astAssignee], value=arrayCall )
62
+ assignment = ast.Assign(targets=[astAssignee], value=arrayCall)
63
63
  FunctionDefTarget.body.insert(0, assignment)
64
64
  FunctionDefTarget.body.remove(stmt)
65
65
  return FunctionDefTarget, allImports
@@ -77,7 +77,7 @@ def findAndReplaceArraySubscriptIn_body(FunctionDefTarget: ast.FunctionDef, iden
77
77
  indexAs_astAttribute: ast.Attribute = astSubscript.slice
78
78
  indexAsStr = ast.unparse(indexAs_astAttribute)
79
79
  argDataSlice: int = arrayTarget[eval(indexAsStr)].item()
80
- astCall = ast.Call(func=ast.Name(id=argData_dtypeName, ctx=ast.Load()) , args=[ast.Constant(value=argDataSlice)], keywords=[])
80
+ astCall = ast.Call(func=ast.Name(id=argData_dtypeName, ctx=ast.Load()), args=[ast.Constant(value=argDataSlice)], keywords=[])
81
81
  assignment = ast.Assign(targets=[astAssignee], value=astCall)
82
82
  if astAssignee.id not in Z0Z_listChaff:
83
83
  FunctionDefTarget.body.insert(0, assignment)
@@ -252,6 +252,7 @@ def makeAstModuleForOneCallable(pythonSource: str, callableTarget: str, paramete
252
252
  if inlineCallables:
253
253
  dictionaryFunctionDef = {statement.name: statement for statement in astModule.body if isinstance(statement, ast.FunctionDef)}
254
254
  callableInlinerWorkhorse = RecursiveInliner(dictionaryFunctionDef)
255
+ # NOTE the inliner assumes each function is not called more than once
255
256
  FunctionDefTarget = callableInlinerWorkhorse.inlineFunctionBody(callableTarget)
256
257
  else:
257
258
  FunctionDefTarget = next((node for node in astModule.body if isinstance(node, ast.FunctionDef) and node.name == callableTarget), None)
@@ -3,6 +3,7 @@ from mapFolding import (
3
3
  EnumIndices,
4
4
  formatModuleNameDEFAULT,
5
5
  FREAKOUT,
6
+ getAlgorithmDispatcher,
6
7
  getAlgorithmSource,
7
8
  getFilenameFoldsTotal,
8
9
  getPathFilenameFoldsTotal,
@@ -35,6 +36,7 @@ from numpy import integer
35
36
  from numpy.typing import NDArray
36
37
  from types import ModuleType
37
38
  from typing import Any, Callable, cast, Dict, List, Optional, Sequence, Set, Tuple, Type, Union
39
+ from Z0Z_tools import autoDecodingRLE
38
40
  import ast
39
41
  import autoflake
40
42
  import collections
@@ -50,54 +52,6 @@ import python_minifier
50
52
 
51
53
  youOughtaKnow = collections.namedtuple('youOughtaKnow', ['callableSynthesized', 'pathFilenameForMe', 'astForCompetentProgrammers'])
52
54
 
53
- # TODO move to Z0Z_tools
54
- def makeStrRLEcompacted(arrayTarget: NDArray[integer[Any]]) -> str:
55
- """Converts a NumPy array into a compressed string representation using run-length encoding (RLE).
56
-
57
- This function takes a NumPy array and converts it into an optimized string representation by:
58
- 1. Compressing consecutive sequences of numbers into range objects
59
- 2. Minimizing repeated zeros using array multiplication syntax
60
-
61
- Parameters:
62
- arrayTarget (numpy.ndarray): The input NumPy array to be converted
63
-
64
- Returns:
65
- str: A string containing Python code that recreates the input array in compressed form.
66
- """
67
-
68
- def compressRangesNDArrayNoFlatten(arraySlice: NDArray[integer[Any]]) -> List[List[Any] | Any | NDArray[integer[Any]]] | List[Any] | Any | NDArray[integer[Any]]:
69
- if isinstance(arraySlice, numpy.ndarray) and arraySlice.ndim > 1:
70
- return [compressRangesNDArrayNoFlatten(arraySlice[index]) for index in range(arraySlice.shape[0])]
71
- elif isinstance(arraySlice, numpy.ndarray) and arraySlice.ndim == 1:
72
- listWithRanges = []
73
- for group in more_itertools.consecutive_groups(arraySlice.tolist()):
74
- ImaSerious = list(group)
75
- ImaRange = [range(ImaSerious[0], ImaSerious[-1] + 1)]
76
- spaces = True #NOTE
77
- lengthAsList = spaces*(len(ImaSerious)-1) + len(python_minifier.minify(str(ImaSerious))) # brackets are proxies for commas
78
- lengthAsRange = spaces*1 + len(str('*')) + len(python_minifier.minify(str(ImaRange))) # brackets are proxies for commas
79
- if lengthAsRange < lengthAsList:
80
- listWithRanges += ImaRange
81
- else:
82
- listWithRanges += ImaSerious
83
- return listWithRanges
84
- return arraySlice
85
-
86
- arrayAsNestedLists = compressRangesNDArrayNoFlatten(arrayTarget)
87
-
88
- arrayAsStr = python_minifier.minify(str(arrayAsNestedLists))
89
-
90
- commaIntMaximum = arrayTarget.shape[-1] - 1
91
-
92
- for X in range(1):
93
- arrayAsStr = arrayAsStr.replace(f'[{X}' + f',{X}'*commaIntMaximum + ']', f'[{X}]*'+str(commaIntMaximum+1))
94
- for countInt in range(commaIntMaximum, 2, -1):
95
- arrayAsStr = arrayAsStr.replace(f',{X}'*countInt + ']', f']+[{X}]*'+str(countInt))
96
-
97
- arrayAsStr = arrayAsStr.replace('range', '*range')
98
-
99
- return arrayAsStr
100
-
101
55
  # Generic
102
56
  class ifThis:
103
57
  """Generic AST node predicate builder."""
@@ -28,9 +28,9 @@ def doUnrollCountGaps(FunctionDefTarget: ast.FunctionDef, stateJob: computationS
28
28
  return FunctionDefTarget, allImports
29
29
 
30
30
  def writeJobNumba(mapShape: Sequence[int]
31
- , callableTarget: str
32
31
  , algorithmSource: ModuleType
33
- , parametersNumba: Optional[ParametersNumba]=None
32
+ , callableTarget: Optional[str] = None
33
+ , parametersNumba: Optional[ParametersNumba] = None
34
34
  , pathFilenameWriteJob: Optional[Union[str, os.PathLike[str]]] = None
35
35
  , unrollCountGaps: Optional[bool] = False
36
36
  , **keywordArguments: Optional[Any]
@@ -63,7 +63,15 @@ def writeJobNumba(mapShape: Sequence[int]
63
63
  stateJob = makeStateJob(mapShape, writeJob=False, **keywordArguments)
64
64
  pythonSource = inspect.getsource(algorithmSource)
65
65
  astModule = ast.parse(pythonSource)
66
- FunctionDefTarget = next((node for node in astModule.body if isinstance(node, ast.FunctionDef) and node.name == callableTarget), None)
66
+ setFunctionDef = {statement for statement in astModule.body if isinstance(statement, ast.FunctionDef)}
67
+ if not callableTarget:
68
+ if len(setFunctionDef) == 1:
69
+ FunctionDefTarget = setFunctionDef.pop()
70
+ callableTarget = FunctionDefTarget.name
71
+ else:
72
+ raise ValueError(f"I did not receive a `callableTarget` and {algorithmSource.__name__=} has more than one callable: {setFunctionDef}. Please select one.")
73
+ else:
74
+ FunctionDefTarget = setFunctionDef.pop() if callableTarget in {statement.name for statement in setFunctionDef} else None
67
75
  if not FunctionDefTarget: raise ValueError(f"I received `{callableTarget=}` and {algorithmSource.__name__=}, but I could not find that function in that source.")
68
76
 
69
77
  # NOTE `allImports` is a complementary container to `FunctionDefTarget`; the `FunctionDefTarget` cannot track its own imports very well.
@@ -116,6 +124,21 @@ def writeJobNumba(mapShape: Sequence[int]
116
124
  ast.fix_missing_locations(astModule)
117
125
  pythonSource = ast.unparse(astModule)
118
126
  pythonSource = autoflake.fix_code(pythonSource, ['mapFolding', 'numba', 'numpy'])
127
+ pythonSource = python_minifier.minify(pythonSource, remove_annotations = False,
128
+ remove_pass = False,
129
+ remove_literal_statements = False,
130
+ combine_imports = True,
131
+ hoist_literals = False,
132
+ rename_locals = False,
133
+ rename_globals = False,
134
+ remove_object_base = False,
135
+ convert_posargs_to_args = False,
136
+ preserve_shebang = True,
137
+ remove_asserts = False,
138
+ remove_debug = False,
139
+ remove_explicit_return_none = False,
140
+ remove_builtin_exception_brackets = False,
141
+ constant_folding = False)
119
142
 
120
143
  # NOTE put on disk
121
144
  if pathFilenameWriteJob is None:
@@ -132,11 +155,11 @@ def writeJobNumba(mapShape: Sequence[int]
132
155
 
133
156
  if __name__ == '__main__':
134
157
  mapShape = [5,5]
135
- callableTarget = 'countSequential'
136
-
137
158
  from mapFolding.syntheticModules import numba_countSequential
138
159
  algorithmSource: ModuleType = numba_countSequential
139
160
 
161
+ callableTarget = None
162
+
140
163
  parametersNumba = parametersNumbaDEFAULT
141
164
 
142
165
  pathFilenameWriteJob = None
@@ -147,4 +170,4 @@ if __name__ == '__main__':
147
170
  Z0Z_setDatatypeModuleScalar('numba')
148
171
  Z0Z_setDecoratorCallable('jit')
149
172
 
150
- writeJobNumba(mapShape, callableTarget, algorithmSource, parametersNumba, pathFilenameWriteJob)
173
+ writeJobNumba(mapShape, algorithmSource, callableTarget, parametersNumba, pathFilenameWriteJob)