mapFolding 0.7.1__tar.gz → 0.8.1__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.
- {mapfolding-0.7.1 → mapfolding-0.8.1}/PKG-INFO +51 -46
- {mapfolding-0.7.1 → mapfolding-0.8.1}/README.md +41 -38
- mapfolding-0.8.1/mapFolding/__init__.py +38 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/basecamp.py +14 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/beDRY.py +93 -82
- mapfolding-0.8.1/mapFolding/filesystem.py +129 -0
- mapfolding-0.8.1/mapFolding/noHomeYet.py +32 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/oeis.py +18 -3
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/reference/flattened.py +46 -45
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/reference/hunterNumba.py +4 -4
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/reference/irvineJavaPort.py +1 -1
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/reference/lunnanNumpy.py +3 -4
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/reference/lunnanWhile.py +5 -7
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/reference/rotatedEntryPoint.py +2 -3
- mapfolding-0.8.1/mapFolding/someAssemblyRequired/__init__.py +46 -0
- mapfolding-0.8.1/mapFolding/someAssemblyRequired/getLLVMforNoReason.py +38 -0
- mapfolding-0.8.1/mapFolding/someAssemblyRequired/ingredientsNumba.py +206 -0
- mapfolding-0.8.1/mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +196 -0
- mapfolding-0.7.1/mapFolding/someAssemblyRequired/synthesizeNumbaJob.py → mapfolding-0.8.1/mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py +19 -23
- mapfolding-0.8.1/mapFolding/someAssemblyRequired/transformDataStructures.py +162 -0
- mapfolding-0.8.1/mapFolding/someAssemblyRequired/transformationTools.py +780 -0
- mapfolding-0.8.1/mapFolding/syntheticModules/numbaCount_doTheNeedful.py +198 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/theDao.py +37 -16
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/theSSOT.py +47 -44
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding.egg-info/PKG-INFO +51 -46
- mapfolding-0.8.1/mapFolding.egg-info/SOURCES.txt +42 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding.egg-info/requires.txt +1 -2
- {mapfolding-0.7.1 → mapfolding-0.8.1}/pyproject.toml +23 -16
- {mapfolding-0.7.1 → mapfolding-0.8.1}/tests/conftest.py +2 -3
- {mapfolding-0.7.1 → mapfolding-0.8.1}/tests/test_filesystem.py +0 -2
- {mapfolding-0.7.1 → mapfolding-0.8.1}/tests/test_other.py +2 -3
- {mapfolding-0.7.1 → mapfolding-0.8.1}/tests/test_tasks.py +0 -4
- mapfolding-0.7.1/mapFolding/__init__.py +0 -9
- mapfolding-0.7.1/mapFolding/filesystem.py +0 -95
- mapfolding-0.7.1/mapFolding/noHomeYet.py +0 -20
- mapfolding-0.7.1/mapFolding/reference/lunnan.py +0 -153
- mapfolding-0.7.1/mapFolding/someAssemblyRequired/Z0Z_workbench.py +0 -33
- mapfolding-0.7.1/mapFolding/someAssemblyRequired/__init__.py +0 -16
- mapfolding-0.7.1/mapFolding/someAssemblyRequired/getLLVMforNoReason.py +0 -21
- mapfolding-0.7.1/mapFolding/someAssemblyRequired/ingredientsNumba.py +0 -100
- mapfolding-0.7.1/mapFolding/someAssemblyRequired/synthesizeCountingFunctions.py +0 -7
- mapfolding-0.7.1/mapFolding/someAssemblyRequired/synthesizeDataConverters.py +0 -135
- mapfolding-0.7.1/mapFolding/someAssemblyRequired/synthesizeNumba.py +0 -91
- mapfolding-0.7.1/mapFolding/someAssemblyRequired/synthesizeNumbaModules.py +0 -91
- mapfolding-0.7.1/mapFolding/someAssemblyRequired/transformationTools.py +0 -425
- mapfolding-0.7.1/mapFolding/someAssemblyRequired/whatWillBe.py +0 -357
- mapfolding-0.7.1/mapFolding/syntheticModules/dataNamespaceFlattened.py +0 -30
- mapfolding-0.7.1/mapFolding/syntheticModules/multiprocessingCount_doTheNeedful.py +0 -216
- mapfolding-0.7.1/mapFolding/syntheticModules/numbaCount.py +0 -90
- mapfolding-0.7.1/mapFolding/syntheticModules/numbaCountExample.py +0 -158
- mapfolding-0.7.1/mapFolding/syntheticModules/numbaCountSequential.py +0 -111
- mapfolding-0.7.1/mapFolding/syntheticModules/numbaCount_doTheNeedful.py +0 -13
- mapfolding-0.7.1/mapFolding/syntheticModules/numba_doTheNeedful.py +0 -12
- mapfolding-0.7.1/mapFolding/syntheticModules/numba_doTheNeedfulExample.py +0 -13
- mapfolding-0.7.1/mapFolding.egg-info/SOURCES.txt +0 -99
- {mapfolding-0.7.1 → mapfolding-0.8.1}/LICENSE +0 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/py.typed +0 -0
- {mapfolding-0.7.1/mapFolding/syntheticModules → mapfolding-0.8.1/mapFolding/reference}/__init__.py +0 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/reference/jax.py +0 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding/reference/total_countPlus1vsPlusN.py +0 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding.egg-info/dependency_links.txt +0 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding.egg-info/entry_points.txt +0 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/mapFolding.egg-info/top_level.txt +0 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/setup.cfg +0 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/tests/__init__.py +0 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/tests/test_computations.py +0 -0
- {mapfolding-0.7.1 → mapfolding-0.8.1}/tests/test_oeis.py +0 -0
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: mapFolding
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.8.1
|
|
4
|
+
Summary: Map folding algorithm with code transformation framework for optimizing numerical computations
|
|
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,combinatorics,folding,map folding,OEIS,optimization,stamp folding
|
|
10
|
+
Keywords: A001415,A001416,A001417,A001418,A195646,algorithmic optimization,AST manipulation,code generation,code transformation,combinatorics,computational geometry,dataclass transformation,folding pattern enumeration,just-in-time compilation,map folding,Numba optimization,OEIS,performance optimization,source code analysis,stamp folding
|
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
|
12
12
|
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
13
14
|
Classifier: Intended Audience :: Education
|
|
14
|
-
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
-
Classifier: Intended Audience :: Other Audience
|
|
16
15
|
Classifier: Intended Audience :: Science/Research
|
|
17
16
|
Classifier: Natural Language :: English
|
|
18
17
|
Classifier: Operating System :: OS Independent
|
|
@@ -23,7 +22,10 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
24
23
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
24
|
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
26
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
26
27
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
28
|
+
Classifier: Topic :: Software Development :: Compilers
|
|
27
29
|
Classifier: Typing :: Typed
|
|
28
30
|
Requires-Python: >=3.10
|
|
29
31
|
Description-Content-Type: text/markdown
|
|
@@ -38,12 +40,12 @@ Requires-Dist: tomli
|
|
|
38
40
|
Requires-Dist: Z0Z_tools
|
|
39
41
|
Provides-Extra: testing
|
|
40
42
|
Requires-Dist: mypy; extra == "testing"
|
|
43
|
+
Requires-Dist: pytest; extra == "testing"
|
|
41
44
|
Requires-Dist: pytest-cov; extra == "testing"
|
|
42
45
|
Requires-Dist: pytest-env; extra == "testing"
|
|
43
46
|
Requires-Dist: pytest-xdist; extra == "testing"
|
|
44
|
-
Requires-Dist: pytest; extra == "testing"
|
|
45
47
|
Requires-Dist: pyupgrade; extra == "testing"
|
|
46
|
-
|
|
48
|
+
Dynamic: license-file
|
|
47
49
|
|
|
48
50
|
# mapFolding: Algorithms for enumerating distinct map/stamp folding patterns 🗺️
|
|
49
51
|
|
|
@@ -52,8 +54,6 @@ Requires-Dist: updateCitation; extra == "testing"
|
|
|
52
54
|
[](https://github.com/hunterhogan/mapFolding/actions/workflows/pythonTests.yml)
|
|
53
55
|

|
|
54
56
|
[](https://creativecommons.org/licenses/by-nc/4.0/)
|
|
55
|
-

|
|
56
|
-

|
|
57
57
|
|
|
58
58
|
---
|
|
59
59
|
|
|
@@ -101,44 +101,49 @@ Available OEIS sequences:
|
|
|
101
101
|
|
|
102
102
|
### 2. **Algorithm Zoo** 🦒
|
|
103
103
|
|
|
104
|
-
- **Lunnon
|
|
104
|
+
- **Lunnon's 1971 Algorithm**: A painstakingly debugged version of [the original typo-riddled code](https://github.com/hunterhogan/mapFolding/blob/mapFolding/reference/foldings.txt)
|
|
105
105
|
- The /reference directory.
|
|
106
106
|
- **Numba-JIT Accelerated**: Up to 1000× faster than pure Python ([benchmarks](https://github.com/hunterhogan/mapFolding/blob/mapFolding/notes/Speed%20highlights.md))
|
|
107
107
|
|
|
108
|
-
### 3. **For Researchers** 🔬
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
-
|
|
131
|
-
-
|
|
132
|
-
- Use
|
|
133
|
-
|
|
134
|
-
-
|
|
135
|
-
-
|
|
136
|
-
|
|
137
|
-
-
|
|
138
|
-
|
|
139
|
-
-
|
|
140
|
-
|
|
141
|
-
|
|
108
|
+
### 3. **For Researchers and Power Users** 🔬
|
|
109
|
+
|
|
110
|
+
This package provides a sophisticated code transformation framework that can turn readable algorithm implementations into highly-optimized computational engines:
|
|
111
|
+
|
|
112
|
+
- **Algorithmic Exploration**: Study the core algorithm in `theDao.py`, which uses a functional state-transformation approach with clear, isolated functions
|
|
113
|
+
- **Performance Optimization**: Generate specialized implementations with the `someAssemblyRequired` transformation pipeline:
|
|
114
|
+
- AST-based code analysis and manipulation
|
|
115
|
+
- Dataclass "shattering" to decompose complex state objects into primitive components
|
|
116
|
+
- Just-in-time compilation with Numba and various optimization profiles
|
|
117
|
+
- LLVM IR extraction for low-level algorithmic analysis
|
|
118
|
+
|
|
119
|
+
- **Extensible Design**: The transformation framework is abstract and generic, enabling:
|
|
120
|
+
- Creation of new optimization targets beyond the included Numba implementation
|
|
121
|
+
- Customization of compilation parameters and optimization levels
|
|
122
|
+
- Development of specialized algorithms for specific map dimensions
|
|
123
|
+
|
|
124
|
+
### 4. **Customization and Extension Guide**
|
|
125
|
+
|
|
126
|
+
The package architecture supports multiple levels of customization:
|
|
127
|
+
|
|
128
|
+
- **Basic Usage**: Work with the high-level API in `basecamp.py` for standard computations
|
|
129
|
+
- **Algorithm Modification**:
|
|
130
|
+
- Modify the core algorithm in `theDao.py` while preserving its functional approach
|
|
131
|
+
- Configure system-wide settings in `theSSOT.py` to adjust data types and performance characteristics
|
|
132
|
+
- Use utility functions in `beDRY.py` for common operations
|
|
133
|
+
|
|
134
|
+
- **Advanced Transformation**:
|
|
135
|
+
- The `someAssemblyRequired` package provides tools to transform code at the AST level:
|
|
136
|
+
- `transformationTools.py` contains utilities for AST manipulation and code generation
|
|
137
|
+
- `transformDataStructures.py` handles complex data structure transformations
|
|
138
|
+
- `ingredientsNumba.py` provides Numba-specific configuration profiles
|
|
139
|
+
- `synthesizeNumbaFlow.py` orchestrates the transformation process
|
|
140
|
+
|
|
141
|
+
- **Custom Deployment**:
|
|
142
|
+
- Generate specialized implementations for specific dimensions
|
|
143
|
+
- Create optimized modules that can be executed as standalone scripts
|
|
144
|
+
- Extract LLVM IR for further analysis or optimization
|
|
145
|
+
|
|
146
|
+
The package's multi-level design allows you to start with simple API calls and progressively delve deeper into optimization as your computational needs grow.
|
|
142
147
|
|
|
143
148
|
## Map-folding Video
|
|
144
149
|
|
|
@@ -155,4 +160,4 @@ Available OEIS sequences:
|
|
|
155
160
|
[](https://HunterThinks.com/support)
|
|
156
161
|
[](https://www.youtube.com/@HunterHogan)
|
|
157
162
|
|
|
158
|
-
[](https://creativecommons.org/licenses/by-nc/4.0/)
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
[](https://github.com/hunterhogan/mapFolding/actions/workflows/pythonTests.yml)
|
|
6
6
|

|
|
7
7
|
[](https://creativecommons.org/licenses/by-nc/4.0/)
|
|
8
|
-

|
|
9
|
-

|
|
10
8
|
|
|
11
9
|
---
|
|
12
10
|
|
|
@@ -54,44 +52,49 @@ Available OEIS sequences:
|
|
|
54
52
|
|
|
55
53
|
### 2. **Algorithm Zoo** 🦒
|
|
56
54
|
|
|
57
|
-
- **Lunnon
|
|
55
|
+
- **Lunnon's 1971 Algorithm**: A painstakingly debugged version of [the original typo-riddled code](https://github.com/hunterhogan/mapFolding/blob/mapFolding/reference/foldings.txt)
|
|
58
56
|
- The /reference directory.
|
|
59
57
|
- **Numba-JIT Accelerated**: Up to 1000× faster than pure Python ([benchmarks](https://github.com/hunterhogan/mapFolding/blob/mapFolding/notes/Speed%20highlights.md))
|
|
60
58
|
|
|
61
|
-
### 3. **For Researchers** 🔬
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
- Use
|
|
86
|
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
|
|
90
|
-
-
|
|
91
|
-
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
-
|
|
59
|
+
### 3. **For Researchers and Power Users** 🔬
|
|
60
|
+
|
|
61
|
+
This package provides a sophisticated code transformation framework that can turn readable algorithm implementations into highly-optimized computational engines:
|
|
62
|
+
|
|
63
|
+
- **Algorithmic Exploration**: Study the core algorithm in `theDao.py`, which uses a functional state-transformation approach with clear, isolated functions
|
|
64
|
+
- **Performance Optimization**: Generate specialized implementations with the `someAssemblyRequired` transformation pipeline:
|
|
65
|
+
- AST-based code analysis and manipulation
|
|
66
|
+
- Dataclass "shattering" to decompose complex state objects into primitive components
|
|
67
|
+
- Just-in-time compilation with Numba and various optimization profiles
|
|
68
|
+
- LLVM IR extraction for low-level algorithmic analysis
|
|
69
|
+
|
|
70
|
+
- **Extensible Design**: The transformation framework is abstract and generic, enabling:
|
|
71
|
+
- Creation of new optimization targets beyond the included Numba implementation
|
|
72
|
+
- Customization of compilation parameters and optimization levels
|
|
73
|
+
- Development of specialized algorithms for specific map dimensions
|
|
74
|
+
|
|
75
|
+
### 4. **Customization and Extension Guide**
|
|
76
|
+
|
|
77
|
+
The package architecture supports multiple levels of customization:
|
|
78
|
+
|
|
79
|
+
- **Basic Usage**: Work with the high-level API in `basecamp.py` for standard computations
|
|
80
|
+
- **Algorithm Modification**:
|
|
81
|
+
- Modify the core algorithm in `theDao.py` while preserving its functional approach
|
|
82
|
+
- Configure system-wide settings in `theSSOT.py` to adjust data types and performance characteristics
|
|
83
|
+
- Use utility functions in `beDRY.py` for common operations
|
|
84
|
+
|
|
85
|
+
- **Advanced Transformation**:
|
|
86
|
+
- The `someAssemblyRequired` package provides tools to transform code at the AST level:
|
|
87
|
+
- `transformationTools.py` contains utilities for AST manipulation and code generation
|
|
88
|
+
- `transformDataStructures.py` handles complex data structure transformations
|
|
89
|
+
- `ingredientsNumba.py` provides Numba-specific configuration profiles
|
|
90
|
+
- `synthesizeNumbaFlow.py` orchestrates the transformation process
|
|
91
|
+
|
|
92
|
+
- **Custom Deployment**:
|
|
93
|
+
- Generate specialized implementations for specific dimensions
|
|
94
|
+
- Create optimized modules that can be executed as standalone scripts
|
|
95
|
+
- Extract LLVM IR for further analysis or optimization
|
|
96
|
+
|
|
97
|
+
The package's multi-level design allows you to start with simple API calls and progressively delve deeper into optimization as your computational needs grow.
|
|
95
98
|
|
|
96
99
|
## Map-folding Video
|
|
97
100
|
|
|
@@ -108,4 +111,4 @@ Available OEIS sequences:
|
|
|
108
111
|
[](https://HunterThinks.com/support)
|
|
109
112
|
[](https://www.youtube.com/@HunterHogan)
|
|
110
113
|
|
|
111
|
-
[](https://creativecommons.org/licenses/by-nc/4.0/)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Map folding enumeration and counting algorithms with optimization capabilities.
|
|
3
|
+
|
|
4
|
+
This package implements algorithms to count and enumerate the various ways
|
|
5
|
+
a rectangular map can be folded, based on the mathematical problem described
|
|
6
|
+
in Lunnon's 1971 paper. It provides multiple layers of functionality, from
|
|
7
|
+
high-level user interfaces to low-level algorithmic optimizations and code
|
|
8
|
+
transformation tools.
|
|
9
|
+
|
|
10
|
+
Core modules:
|
|
11
|
+
- basecamp: Public API with simplified interfaces for end users
|
|
12
|
+
- theDao: Core computational algorithm using a functional state-transformation approach
|
|
13
|
+
- beDRY: Utility functions for common operations and parameter management
|
|
14
|
+
- theSSOT: Single Source of Truth for configuration, types, and state management
|
|
15
|
+
- oeis: Interface to the Online Encyclopedia of Integer Sequences for known results
|
|
16
|
+
|
|
17
|
+
Extended functionality:
|
|
18
|
+
- someAssemblyRequired: Code transformation framework that optimizes the core algorithm
|
|
19
|
+
through AST manipulation, dataclass transformation, and compilation techniques
|
|
20
|
+
|
|
21
|
+
Special directories:
|
|
22
|
+
- .cache/: Stores cached data from external sources like OEIS to improve performance
|
|
23
|
+
- syntheticModules/: Contains dynamically generated, optimized implementations of the
|
|
24
|
+
core algorithm created by the code transformation framework
|
|
25
|
+
|
|
26
|
+
This package strives to balance algorithm readability and understandability with
|
|
27
|
+
high-performance computation capabilities, allowing users to compute map folding
|
|
28
|
+
totals for larger dimensions than previously feasible.
|
|
29
|
+
"""
|
|
30
|
+
from mapFolding.basecamp import countFolds as countFolds
|
|
31
|
+
from mapFolding.oeis import clearOEIScache, getOEISids, OEIS_for_n
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
'clearOEIScache',
|
|
35
|
+
'countFolds',
|
|
36
|
+
'getOEISids',
|
|
37
|
+
'OEIS_for_n',
|
|
38
|
+
]
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Public API for the map folding algorithm with simplified interface.
|
|
3
|
+
|
|
4
|
+
This module provides the main entry point for users of the mapFolding package,
|
|
5
|
+
abstracting away the complexities of the computational algorithm. It offers
|
|
6
|
+
a high-level interface to count the total number of possible ways to fold
|
|
7
|
+
a rectangular map of specified dimensions, with options for customizing the
|
|
8
|
+
computation process and saving results.
|
|
9
|
+
|
|
10
|
+
The primary function is countFolds, which handles parameter validation,
|
|
11
|
+
computation state management, dispatching to the appropriate algorithm
|
|
12
|
+
implementation, and optional persistence of results.
|
|
13
|
+
"""
|
|
14
|
+
|
|
1
15
|
from collections.abc import Sequence
|
|
2
16
|
from mapFolding.beDRY import outfitCountFolds, setCPUlimit, validateListDimensions
|
|
3
17
|
from mapFolding.filesystem import getPathFilenameFoldsTotal, saveFoldsTotal
|
|
@@ -1,30 +1,26 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
"""
|
|
2
|
+
Utility functions for maintaining DRY (Don't Repeat Yourself) principles in the mapFolding package.
|
|
3
|
+
|
|
4
|
+
This module provides a collection of helper functions that abstract common operations needed
|
|
5
|
+
throughout the package, preventing code duplication and ensuring consistency. The functions
|
|
6
|
+
manage core aspects of the computation process, including:
|
|
7
|
+
|
|
8
|
+
1. Resource allocation and system limits management
|
|
9
|
+
2. Data structure initialization and manipulation
|
|
10
|
+
3. Parameter validation and interpretation
|
|
11
|
+
4. Construction of specialized arrays and matrices for the folding algorithm
|
|
12
|
+
|
|
13
|
+
The functions in this module serve as a relatively stable API for other modules to use,
|
|
14
|
+
particularly for initializing computation state, validating inputs, and creating data
|
|
15
|
+
structures needed by the folding algorithms.
|
|
16
|
+
"""
|
|
8
17
|
from collections.abc import Sequence
|
|
18
|
+
from mapFolding.theSSOT import Array3D, ComputationState, getDatatypePackage, getNumpyDtypeDefault
|
|
9
19
|
from sys import maxsize as sysMaxsize
|
|
10
20
|
from typing import Any
|
|
11
21
|
from Z0Z_tools import defineConcurrencyLimit, intInnit, oopsieKwargsie
|
|
12
22
|
import numpy
|
|
13
23
|
|
|
14
|
-
def validateListDimensions(listDimensions: Sequence[int]) -> tuple[int, ...]:
|
|
15
|
-
if not listDimensions:
|
|
16
|
-
raise ValueError("listDimensions is a required parameter.")
|
|
17
|
-
listValidated: list[int] = intInnit(listDimensions, 'listDimensions')
|
|
18
|
-
listNonNegative: list[int] = []
|
|
19
|
-
for dimension in listValidated:
|
|
20
|
-
if dimension < 0:
|
|
21
|
-
raise ValueError(f"Dimension {dimension} must be non-negative")
|
|
22
|
-
listNonNegative.append(dimension)
|
|
23
|
-
dimensionsValid = [dimension for dimension in listNonNegative if dimension > 0]
|
|
24
|
-
if len(dimensionsValid) < 2:
|
|
25
|
-
raise NotImplementedError(f"This function requires listDimensions, {listDimensions}, to have at least two dimensions greater than 0. You may want to look at https://oeis.org/.")
|
|
26
|
-
return tuple(sorted(dimensionsValid))
|
|
27
|
-
|
|
28
24
|
def getLeavesTotal(mapShape: tuple[int, ...]) -> int:
|
|
29
25
|
productDimensions = 1
|
|
30
26
|
for dimension in mapShape:
|
|
@@ -33,7 +29,59 @@ def getLeavesTotal(mapShape: tuple[int, ...]) -> int:
|
|
|
33
29
|
productDimensions *= dimension
|
|
34
30
|
return productDimensions
|
|
35
31
|
|
|
36
|
-
def
|
|
32
|
+
def getTaskDivisions(computationDivisions: int | str | None, concurrencyLimit: int, leavesTotal: int) -> int:
|
|
33
|
+
"""
|
|
34
|
+
Determines whether to divide the computation into tasks and how many divisions.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
computationDivisions (None)
|
|
39
|
+
Specifies how to divide computations:
|
|
40
|
+
- `None`: no division of the computation into tasks; sets task divisions to 0.
|
|
41
|
+
- int: direct set the number of task divisions; cannot exceed the map's total leaves.
|
|
42
|
+
- `'maximum'`: divides into `leavesTotal`-many `taskDivisions`.
|
|
43
|
+
- `'cpu'`: limits the divisions to the number of available CPUs, i.e. `concurrencyLimit`.
|
|
44
|
+
concurrencyLimit
|
|
45
|
+
Maximum number of concurrent tasks allowed.
|
|
46
|
+
CPUlimit
|
|
47
|
+
for error reporting.
|
|
48
|
+
listDimensions
|
|
49
|
+
for error reporting.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
taskDivisions
|
|
54
|
+
How many tasks must finish before the job can compute the total number of folds; `0` means no tasks, only job.
|
|
55
|
+
|
|
56
|
+
Raises
|
|
57
|
+
------
|
|
58
|
+
ValueError
|
|
59
|
+
If computationDivisions is an unsupported type or if resulting task divisions exceed total leaves.
|
|
60
|
+
|
|
61
|
+
Notes
|
|
62
|
+
-----
|
|
63
|
+
Task divisions should not exceed total leaves or the folds will be over-counted.
|
|
64
|
+
"""
|
|
65
|
+
taskDivisions = 0
|
|
66
|
+
if not computationDivisions:
|
|
67
|
+
pass
|
|
68
|
+
elif isinstance(computationDivisions, int):
|
|
69
|
+
taskDivisions = computationDivisions
|
|
70
|
+
elif isinstance(computationDivisions, str): # type: ignore
|
|
71
|
+
# 'Unnecessary isinstance call; "str" is always an instance of "str", so sayeth Pylance'. Yeah, well "User is not always an instance of "correct input" so sayeth the programmer.
|
|
72
|
+
computationDivisions = computationDivisions.lower()
|
|
73
|
+
if computationDivisions == 'maximum':
|
|
74
|
+
taskDivisions = leavesTotal
|
|
75
|
+
elif computationDivisions == 'cpu':
|
|
76
|
+
taskDivisions = min(concurrencyLimit, leavesTotal)
|
|
77
|
+
else:
|
|
78
|
+
raise ValueError(f"I received {computationDivisions} for the parameter, `computationDivisions`, but the so-called programmer didn't implement code for that.")
|
|
79
|
+
|
|
80
|
+
if taskDivisions > leavesTotal:
|
|
81
|
+
raise ValueError(f"Problem: `taskDivisions`, ({taskDivisions}), is greater than `leavesTotal`, ({leavesTotal}), which will cause duplicate counting of the folds.\n\nChallenge: you cannot directly set `taskDivisions` or `leavesTotal`. They are derived from parameters that may or may not still be named `computationDivisions`, `CPUlimit` , and `listDimensions` and from dubious-quality Python code.")
|
|
82
|
+
return int(max(0, taskDivisions))
|
|
83
|
+
|
|
84
|
+
def interpretParameter_datatype(datatype: type[numpy.signedinteger[Any]] | None = None) -> type[numpy.signedinteger[Any]]:
|
|
37
85
|
"""An imperfect way to reduce code duplication."""
|
|
38
86
|
if 'numpy' == getDatatypePackage():
|
|
39
87
|
numpyDtype = datatype or getNumpyDtypeDefault()
|
|
@@ -42,7 +90,7 @@ def getNumpyDtype(datatype: type[numpy.signedinteger[Any]] | None = None) -> typ
|
|
|
42
90
|
return numpyDtype
|
|
43
91
|
|
|
44
92
|
def makeConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int, datatype: type[numpy.signedinteger[Any]] | None = None) -> Array3D:
|
|
45
|
-
numpyDtype =
|
|
93
|
+
numpyDtype = interpretParameter_datatype(datatype)
|
|
46
94
|
dimensionsTotal = len(mapShape)
|
|
47
95
|
cumulativeProduct = numpy.multiply.accumulate([1] + list(mapShape), dtype=numpyDtype)
|
|
48
96
|
arrayDimensions = numpy.array(mapShape, dtype=numpyDtype)
|
|
@@ -69,9 +117,15 @@ def makeConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int, datatype: t
|
|
|
69
117
|
return connectionGraph
|
|
70
118
|
|
|
71
119
|
def makeDataContainer(shape: int | tuple[int, ...], datatype: type[numpy.signedinteger[Any]] | None = None) -> numpy.ndarray[Any, numpy.dtype[numpy.signedinteger[Any]]]:
|
|
72
|
-
numpyDtype =
|
|
120
|
+
numpyDtype = interpretParameter_datatype(datatype)
|
|
73
121
|
return numpy.zeros(shape, dtype=numpyDtype)
|
|
74
122
|
|
|
123
|
+
def outfitCountFolds(mapShape: tuple[int, ...], computationDivisions: int | str | None = None, concurrencyLimit: int = 1) -> ComputationState:
|
|
124
|
+
leavesTotal = getLeavesTotal(mapShape)
|
|
125
|
+
taskDivisions = getTaskDivisions(computationDivisions, concurrencyLimit, leavesTotal)
|
|
126
|
+
computationStateInitialized = ComputationState(mapShape, leavesTotal, taskDivisions, concurrencyLimit)
|
|
127
|
+
return computationStateInitialized
|
|
128
|
+
|
|
75
129
|
def setCPUlimit(CPUlimit: Any | None) -> int:
|
|
76
130
|
"""Sets CPU limit for concurrent operations.
|
|
77
131
|
|
|
@@ -106,66 +160,23 @@ def setCPUlimit(CPUlimit: Any | None) -> int:
|
|
|
106
160
|
concurrencyLimit: int = defineConcurrencyLimit(CPUlimit, get_num_threads())
|
|
107
161
|
set_num_threads(concurrencyLimit)
|
|
108
162
|
concurrencyLimit = get_num_threads()
|
|
109
|
-
elif concurrencyPackage == '
|
|
163
|
+
elif concurrencyPackage == 'multiprocessing':
|
|
110
164
|
# When to use multiprocessing.set_start_method https://github.com/hunterhogan/mapFolding/issues/6
|
|
111
|
-
concurrencyLimit
|
|
165
|
+
concurrencyLimit = defineConcurrencyLimit(CPUlimit)
|
|
112
166
|
else:
|
|
113
167
|
raise NotImplementedError(f"I received {concurrencyPackage=} but I don't know what to do with that.")
|
|
114
168
|
return concurrencyLimit
|
|
115
169
|
|
|
116
|
-
def
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
Maximum number of concurrent tasks allowed.
|
|
130
|
-
CPUlimit
|
|
131
|
-
for error reporting.
|
|
132
|
-
listDimensions
|
|
133
|
-
for error reporting.
|
|
134
|
-
|
|
135
|
-
Returns
|
|
136
|
-
-------
|
|
137
|
-
taskDivisions
|
|
138
|
-
How many tasks must finish before the job can compute the total number of folds; `0` means no tasks, only job.
|
|
139
|
-
|
|
140
|
-
Raises
|
|
141
|
-
------
|
|
142
|
-
ValueError
|
|
143
|
-
If computationDivisions is an unsupported type or if resulting task divisions exceed total leaves.
|
|
144
|
-
|
|
145
|
-
Notes
|
|
146
|
-
-----
|
|
147
|
-
Task divisions should not exceed total leaves or the folds will be over-counted.
|
|
148
|
-
"""
|
|
149
|
-
taskDivisions = 0
|
|
150
|
-
if not computationDivisions:
|
|
151
|
-
pass
|
|
152
|
-
elif isinstance(computationDivisions, int):
|
|
153
|
-
taskDivisions = computationDivisions
|
|
154
|
-
elif isinstance(computationDivisions, str): # type: ignore 'Unnecessary isinstance call; "str" is always an instance of "str", so sayeth Pylance'. Yeah, well "User is not always an instance of "correct input" so sayeth the programmer.
|
|
155
|
-
computationDivisions = computationDivisions.lower()
|
|
156
|
-
if computationDivisions == 'maximum':
|
|
157
|
-
taskDivisions = leavesTotal
|
|
158
|
-
elif computationDivisions == 'cpu':
|
|
159
|
-
taskDivisions = min(concurrencyLimit, leavesTotal)
|
|
160
|
-
else:
|
|
161
|
-
raise ValueError(f"I received {computationDivisions} for the parameter, `computationDivisions`, but the so-called programmer didn't implement code for that.")
|
|
162
|
-
|
|
163
|
-
if taskDivisions > leavesTotal:
|
|
164
|
-
raise ValueError(f"Problem: `taskDivisions`, ({taskDivisions}), is greater than `leavesTotal`, ({leavesTotal}), which will cause duplicate counting of the folds.\n\nChallenge: you cannot directly set `taskDivisions` or `leavesTotal`. They are derived from parameters that may or may not still be named `computationDivisions`, `CPUlimit` , and `listDimensions` and from dubious-quality Python code.")
|
|
165
|
-
return int(max(0, taskDivisions))
|
|
166
|
-
|
|
167
|
-
def outfitCountFolds(mapShape: tuple[int, ...], computationDivisions: int | str | None = None, concurrencyLimit: int = 1) -> ComputationState:
|
|
168
|
-
leavesTotal = getLeavesTotal(mapShape)
|
|
169
|
-
taskDivisions = getTaskDivisions(computationDivisions, concurrencyLimit, leavesTotal)
|
|
170
|
-
computationStateInitialized = ComputationState(mapShape, leavesTotal, taskDivisions, concurrencyLimit)
|
|
171
|
-
return computationStateInitialized
|
|
170
|
+
def validateListDimensions(listDimensions: Sequence[int]) -> tuple[int, ...]:
|
|
171
|
+
if not listDimensions:
|
|
172
|
+
raise ValueError("listDimensions is a required parameter.")
|
|
173
|
+
listValidated: list[int] = intInnit(listDimensions, 'listDimensions')
|
|
174
|
+
listNonNegative: list[int] = []
|
|
175
|
+
for dimension in listValidated:
|
|
176
|
+
if dimension < 0:
|
|
177
|
+
raise ValueError(f"Dimension {dimension} must be non-negative")
|
|
178
|
+
listNonNegative.append(dimension)
|
|
179
|
+
dimensionsValid = [dimension for dimension in listNonNegative if dimension > 0]
|
|
180
|
+
if len(dimensionsValid) < 2:
|
|
181
|
+
raise NotImplementedError(f"This function requires listDimensions, {listDimensions}, to have at least two dimensions greater than 0. You may want to look at https://oeis.org/.")
|
|
182
|
+
return tuple(sorted(dimensionsValid))
|