mapFolding 0.8.0__py3-none-any.whl → 0.8.2__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 (40) hide show
  1. mapFolding/__init__.py +33 -4
  2. mapFolding/basecamp.py +16 -2
  3. mapFolding/beDRY.py +40 -32
  4. mapFolding/filesystem.py +124 -90
  5. mapFolding/noHomeYet.py +12 -0
  6. mapFolding/oeis.py +18 -3
  7. mapFolding/reference/__init__.py +38 -0
  8. mapFolding/reference/flattened.py +66 -47
  9. mapFolding/reference/hunterNumba.py +28 -4
  10. mapFolding/reference/irvineJavaPort.py +13 -1
  11. mapFolding/reference/{jax.py → jaxCount.py} +46 -27
  12. mapFolding/reference/lunnanNumpy.py +19 -5
  13. mapFolding/reference/lunnanWhile.py +19 -7
  14. mapFolding/reference/rotatedEntryPoint.py +20 -3
  15. mapFolding/reference/total_countPlus1vsPlusN.py +226 -203
  16. mapFolding/someAssemblyRequired/__init__.py +29 -0
  17. mapFolding/someAssemblyRequired/getLLVMforNoReason.py +32 -14
  18. mapFolding/someAssemblyRequired/ingredientsNumba.py +22 -1
  19. mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +193 -0
  20. mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py +3 -4
  21. mapFolding/someAssemblyRequired/transformDataStructures.py +168 -0
  22. mapFolding/someAssemblyRequired/transformationTools.py +233 -225
  23. mapFolding/theDao.py +19 -5
  24. mapFolding/theSSOT.py +89 -122
  25. mapfolding-0.8.2.dist-info/METADATA +187 -0
  26. mapfolding-0.8.2.dist-info/RECORD +39 -0
  27. {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info}/WHEEL +1 -1
  28. tests/conftest.py +43 -33
  29. tests/test_computations.py +7 -7
  30. tests/test_other.py +2 -2
  31. mapFolding/reference/lunnan.py +0 -153
  32. mapFolding/someAssemblyRequired/Z0Z_workbench.py +0 -350
  33. mapFolding/someAssemblyRequired/synthesizeDataConverters.py +0 -117
  34. mapFolding/syntheticModules/numbaCountHistoricalExample.py +0 -158
  35. mapFolding/syntheticModules/numba_doTheNeedfulHistoricalExample.py +0 -13
  36. mapfolding-0.8.0.dist-info/METADATA +0 -157
  37. mapfolding-0.8.0.dist-info/RECORD +0 -41
  38. {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info}/entry_points.txt +0 -0
  39. {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info/licenses}/LICENSE +0 -0
  40. {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info}/top_level.txt +0 -0
mapFolding/theDao.py CHANGED
@@ -1,14 +1,28 @@
1
- from concurrent.futures import Future as ConcurrentFuture, ProcessPoolExecutor
2
- from copy import deepcopy
3
- from mapFolding.theSSOT import ComputationState
4
- from multiprocessing import set_start_method as multiprocessing_set_start_method
5
-
6
1
  """
2
+ Core computational algorithm for map folding counting and enumeration.
3
+
4
+ This module implements the core algorithms for enumerating and counting the various ways
5
+ a rectangular map can be folded. It uses a functional state-transformation approach, where
6
+ each function performs a specific state mutation and returns the updated state. The module
7
+ provides three main counting algorithms:
8
+
9
+ 1. countInitialize: Sets up the initial state for computation
10
+ 2. countSequential: Processes the folding computation sequentially
11
+ 3. countParallel: Distributes the computation across multiple processes
12
+
13
+ All algorithms operate on a ComputationState object that tracks the folding process, including:
7
14
  - A "leaf" is a unit square in the map
8
15
  - A "gap" is a potential position where a new leaf can be folded
9
16
  - Connections track how leaves can connect above/below each other
10
17
  - Leaves are enumerated starting from 1, not 0; hence, leaf1ndex not leafIndex
18
+
19
+ The doTheNeedful function is the main entry point that orchestrates the computation strategy
20
+ based on task divisions and concurrency parameters.
11
21
  """
22
+ from concurrent.futures import Future as ConcurrentFuture, ProcessPoolExecutor
23
+ from copy import deepcopy
24
+ from mapFolding.theSSOT import ComputationState
25
+ from multiprocessing import set_start_method as multiprocessing_set_start_method
12
26
 
13
27
  # When to use multiprocessing.set_start_method https://github.com/hunterhogan/mapFolding/issues/6
14
28
  if __name__ == '__main__':
mapFolding/theSSOT.py CHANGED
@@ -1,114 +1,103 @@
1
+ """
2
+ Single Source of Truth module for configuration, types, and computational state management.
3
+
4
+ This module defines the core data structures, type definitions, and configuration settings
5
+ used throughout the mapFolding package. It implements the Single Source of Truth (SSOT)
6
+ principle to ensure consistency across the package's components.
7
+
8
+ Key features:
9
+ 1. The ComputationState dataclass, which encapsulates the state of the folding computation
10
+ 2. Unified type definitions for integers and arrays used in the computation
11
+ 3. Configuration settings for synthetic module generation and dispatching
12
+ 4. Path resolution and management for package resources and job output
13
+ 5. Dynamic dispatch functionality for algorithm implementations
14
+
15
+ The module differentiates between "the" identifiers (package defaults) and other identifiers
16
+ to avoid namespace collisions when transforming algorithms.
17
+ """
18
+
1
19
  from collections.abc import Callable
2
20
  from importlib import import_module as importlib_import_module
3
21
  from inspect import getfile as inspect_getfile
4
- from numpy import dtype, int64 as numpy_int64, int16 as numpy_int16, ndarray, signedinteger
22
+ from numpy import dtype, int64 as numpy_int64, int16 as numpy_int16, ndarray
5
23
  from pathlib import Path
6
24
  from sys import modules as sysModules
7
25
  from tomli import load as tomli_load
8
26
  from types import ModuleType
9
- from typing import Any, Final, TypeAlias
27
+ from typing import TypeAlias
10
28
  import dataclasses
11
29
 
12
- """
13
- 2025 March 11
14
- Note to self: fundamental concept in Python:
15
- Identifiers: scope and resolution, LEGB (Local, Enclosing, Global, Builtin)
16
- - Local: Inside the function
17
- - Enclosing: Inside enclosing functions
18
- - Global: At the uppermost level
19
- - Builtin: Python's built-in names
20
- """
21
-
22
- # I _think_, in theSSOT, I have abstracted the flow settings to only these couple of lines:
23
30
  # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
31
+ # I _think_, in theSSOT, I have abstracted the flow settings to only these couple of lines:
24
32
  packageFlowSynthetic = 'numba'
25
33
  # Z0Z_packageFlow = 'algorithm'
26
34
  Z0Z_packageFlow = packageFlowSynthetic
27
35
  Z0Z_concurrencyPackage = 'multiprocessing'
28
- # =============================================================================
29
- # The Wrong Way The Wrong Way The Wrong Way The Wrong Way The Wrong Way
30
- # Evaluate When Packaging Evaluate When Packaging Evaluate When Packaging
31
36
 
32
- sourceAlgorithmPACKAGING: str = 'theDao'
33
- datatypePackagePACKAGING: Final[str] = 'numpy'
34
- dispatcherCallablePACKAGING: str = 'doTheNeedful'
35
- moduleOfSyntheticModulesPACKAGING: Final[str] = 'syntheticModules'
36
-
37
- dataclassModulePACKAGING: str = 'theSSOT'
38
- dataclassIdentifierPACKAGING: str = 'ComputationState'
39
- dataclassInstancePACKAGING: str = 'state'
40
- dataclassInstanceTaskDistributionPACKAGING = dataclassInstancePACKAGING + 'Parallel'
41
-
42
- sourceInitializeCallablePACKAGING = 'countInitialize'
43
- sourceSequentialCallablePACKAGING = 'countSequential'
44
- sourceParallelCallablePACKAGING = 'countParallel'
37
+ # =============================================================================
38
+ # The Wrong Way: Evaluate When Packaging
45
39
 
46
40
  try:
47
- thePackageNamePACKAGING: str = tomli_load(Path("../pyproject.toml").open('rb'))["project"]["name"]
41
+ packageNamePACKAGING: str = tomli_load(Path("../pyproject.toml").open('rb'))["project"]["name"]
48
42
  except Exception:
49
- thePackageNamePACKAGING = "mapFolding"
43
+ packageNamePACKAGING = "mapFolding"
50
44
 
51
- # =============================================================================
52
- # The Wrong Way The Wrong Way The Wrong Way The Wrong Way The Wrong Way
53
- # Evaluate When Installing Evaluate When Installing Evaluate When Installing
54
-
55
- fileExtensionINSTALLING: str = '.py'
45
+ # The Wrong Way: Evaluate When Installing
56
46
 
57
47
  def getPathPackageINSTALLING() -> Path:
58
- pathPackage: Path = Path(inspect_getfile(importlib_import_module(thePackageNamePACKAGING)))
48
+ pathPackage: Path = Path(inspect_getfile(importlib_import_module(packageNamePACKAGING)))
59
49
  if pathPackage.is_file():
60
50
  pathPackage = pathPackage.parent
61
51
  return pathPackage
62
52
 
63
- # =============================================================================
64
- # The right way, perhaps.
65
-
66
- # Create enduring identifiers from the hopefully transient identifiers above.
67
- thePackageName: Final[str] = thePackageNamePACKAGING
68
- thePathPackage: Path = getPathPackageINSTALLING()
69
-
70
- """
71
- NOTE on semiotics: `theIdentifier` vs `identifier`
72
-
73
- - This package has a typical, "hardcoded" algorithm for counting map folds.
74
- - This package has logic for transforming that algorithm into other forms.
75
- - The transformation logic can transform other algorithms if 1) they are similar enough to the "hardcoded" algorithm and 2) I have written the transformation logic well enough to handle the differences.
76
- - To avoid confusion and namespace collisions, I differentiate between, for example, `theSourceAlgorithm` of the package and any other `sourceAlgorithm` being transformed by the package.
77
- """
78
-
79
- theSourceAlgorithm: str = sourceAlgorithmPACKAGING
80
- theSourceInitializeCallable = sourceInitializeCallablePACKAGING
81
- theSourceSequentialCallable = sourceSequentialCallablePACKAGING
82
- theSourceParallelCallable = sourceParallelCallablePACKAGING
83
- theDatatypePackage: Final[str] = datatypePackagePACKAGING
84
-
85
- theDispatcherCallable: str = dispatcherCallablePACKAGING
86
-
87
- theDataclassModule: str = dataclassModulePACKAGING
88
- theDataclassIdentifier: str = dataclassIdentifierPACKAGING
89
- theDataclassInstance: str = dataclassInstancePACKAGING
90
- theDataclassInstanceTaskDistribution: str = dataclassInstanceTaskDistributionPACKAGING
91
-
92
- theFileExtension: str = fileExtensionINSTALLING
93
-
94
- theModuleOfSyntheticModules: Final[str] = moduleOfSyntheticModulesPACKAGING
53
+ # The following is an improvement, but it is not the full solution.
54
+ # I hope that the standardized markers, `metadata={'evaluateWhen': 'packaging'}` will help to automate
55
+ # whatever needs to happen so that the following is well implemented.
56
+ @dataclasses.dataclass(frozen=True)
57
+ class PackageSettings:
58
+ concurrencyPackage = Z0Z_concurrencyPackage
59
+ dataclassIdentifier: str = dataclasses.field(default='ComputationState', metadata={'evaluateWhen': 'packaging'})
60
+ dataclassInstance: str = dataclasses.field(default='state', metadata={'evaluateWhen': 'packaging'})
61
+ dataclassInstanceTaskDistributionSuffix: str = dataclasses.field(default='Parallel', metadata={'evaluateWhen': 'packaging'})
62
+ dataclassModule: str = dataclasses.field(default='theSSOT', metadata={'evaluateWhen': 'packaging'})
63
+ datatypePackage: str = dataclasses.field(default='numpy', metadata={'evaluateWhen': 'packaging'})
64
+ dispatcherCallable: str = dataclasses.field(default='doTheNeedful', metadata={'evaluateWhen': 'packaging'})
65
+ fileExtension: str = dataclasses.field(default='.py', metadata={'evaluateWhen': 'installing'})
66
+ moduleOfSyntheticModules: str = dataclasses.field(default='syntheticModules', metadata={'evaluateWhen': 'packaging'})
67
+ packageName: str = dataclasses.field(default = packageNamePACKAGING, metadata={'evaluateWhen': 'packaging'})
68
+ pathPackage: Path = dataclasses.field(default_factory=getPathPackageINSTALLING, init=False, metadata={'evaluateWhen': 'installing'})
69
+ sourceAlgorithm: str = dataclasses.field(default='theDao', metadata={'evaluateWhen': 'packaging'})
70
+ sourceConcurrencyManagerIdentifier: str = dataclasses.field(default='submit', metadata={'evaluateWhen': 'packaging'})
71
+ sourceConcurrencyManagerNamespace: str = dataclasses.field(default='concurrencyManager', metadata={'evaluateWhen': 'packaging'})
72
+ sourceInitializeCallable: str = dataclasses.field(default='countInitialize', metadata={'evaluateWhen': 'packaging'})
73
+ sourceParallelCallable: str = dataclasses.field(default='countParallel', metadata={'evaluateWhen': 'packaging'})
74
+ sourceSequentialCallable: str = dataclasses.field(default='countSequential', metadata={'evaluateWhen': 'packaging'})
75
+
76
+ @property # These are not fields, and that annoys me.
77
+ def dataclassInstanceTaskDistribution(self) -> str:
78
+ """ Compute the task distribution identifier by concatenating dataclassInstance and dataclassInstanceTaskDistributionSuffix. """
79
+ # it follows that `metadata={'evaluateWhen': 'packaging'}`
80
+ return self.dataclassInstance + self.dataclassInstanceTaskDistributionSuffix
81
+
82
+ @property # These are not fields, and that annoys me.
83
+ def logicalPathModuleSourceAlgorithm(self) -> str:
84
+ """ Compute the logical path module for the source algorithm by joining packageName and sourceAlgorithm. """
85
+ # it follows that `metadata={'evaluateWhen': 'packaging'}`
86
+ return '.'.join([self.packageName, self.sourceAlgorithm])
87
+
88
+ @property # These are not fields, and that annoys me.
89
+ def logicalPathModuleDataclass(self) -> str:
90
+ """ Compute the logical path module for the dataclass by joining packageName and dataclassModule. """
91
+ # it follows that `metadata={'evaluateWhen': 'packaging'}`
92
+ return '.'.join([self.packageName, self.dataclassModule])
93
+
94
+ The = PackageSettings()
95
95
 
96
96
  # =============================================================================
97
-
98
- # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
99
- concurrencyPackage: str = Z0Z_packageFlow
100
- concurrencyPackage = Z0Z_concurrencyPackage
101
-
102
- # =============================================================================
103
- # The relatively flexible type system needs a different paradigm, but I don't
104
- # know what it should be. The system needs to 1) help optimize computation, 2)
105
- # make it possible to change the basic type of the package (e.g., from numpy
106
- # to superTypePy), 3) make it possible to synthesize the optimized flow of used
107
- # by the package, and 4) make it possible to synthesize arbitrary modules with
108
- # different type systems.
97
+ # Flexible Data Structure System Needs Enhanced Paradigm https://github.com/hunterhogan/mapFolding/issues/9
109
98
 
110
99
  DatatypeLeavesTotal: TypeAlias = int
111
- # this would be uint8, but mapShape (2,2,2,2, 2,2,2,2) has 256 leaves, so generic containers accommodate
100
+ # this would be uint8, but mapShape (2,2,2,2, 2,2,2,2) has 256 leaves, so generic containers must accommodate at least 256 leaves
112
101
  numpyLeavesTotal: TypeAlias = numpy_int16
113
102
 
114
103
  DatatypeElephino: TypeAlias = int
@@ -116,18 +105,12 @@ numpyElephino: TypeAlias = numpy_int16
116
105
 
117
106
  DatatypeFoldsTotal: TypeAlias = int
118
107
  numpyFoldsTotal: TypeAlias = numpy_int64
119
- numpyDtypeDefault = numpyFoldsTotal
120
108
 
121
109
  Array3D: TypeAlias = ndarray[tuple[int, int, int], dtype[numpyLeavesTotal]]
122
110
  Array1DLeavesTotal: TypeAlias = ndarray[tuple[int], dtype[numpyLeavesTotal]]
123
111
  Array1DElephino: TypeAlias = ndarray[tuple[int], dtype[numpyElephino]]
124
112
  Array1DFoldsTotal: TypeAlias = ndarray[tuple[int], dtype[numpyFoldsTotal]]
125
113
 
126
- # =============================================================================
127
- # The right way.
128
- # (The dataclass, not the typing of the dataclass.)
129
- # (Also, my noobplementation of the dataclass certainly needs improvement.)
130
-
131
114
  @dataclasses.dataclass
132
115
  class ComputationState:
133
116
  mapShape: tuple[DatatypeLeavesTotal, ...]
@@ -149,7 +132,7 @@ class ComputationState:
149
132
  foldsTotal: DatatypeFoldsTotal = DatatypeFoldsTotal(0)
150
133
  gap1ndex: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
151
134
  gap1ndexCeiling: DatatypeElephino = DatatypeElephino(0)
152
- groupsOfFolds: DatatypeFoldsTotal = DatatypeFoldsTotal(0)
135
+ groupsOfFolds: DatatypeFoldsTotal = dataclasses.field(default=DatatypeFoldsTotal(0), metadata={'theCountingIdentifier': True})
153
136
  indexDimension: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
154
137
  indexLeaf: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
155
138
  indexMiniGap: DatatypeElephino = DatatypeElephino(0)
@@ -173,9 +156,9 @@ class ComputationState:
173
156
  leavesTotalAsInt = int(self.leavesTotal)
174
157
 
175
158
  if self.countDimensionsGapped is None:
176
- self.countDimensionsGapped = makeDataContainer(leavesTotalAsInt + 1, numpyElephino)
159
+ self.countDimensionsGapped = makeDataContainer(leavesTotalAsInt + 1, numpyLeavesTotal)
177
160
  if self.gapRangeStart is None:
178
- self.gapRangeStart = makeDataContainer(leavesTotalAsInt + 1, numpyLeavesTotal)
161
+ self.gapRangeStart = makeDataContainer(leavesTotalAsInt + 1, numpyElephino)
179
162
  if self.gapsWhere is None:
180
163
  self.gapsWhere = makeDataContainer(leavesTotalAsInt * leavesTotalAsInt + 1, numpyLeavesTotal)
181
164
  if self.leafAbove is None:
@@ -187,75 +170,50 @@ class ComputationState:
187
170
  self.foldsTotal = DatatypeFoldsTotal(self.foldGroups[0:-1].sum() * self.leavesTotal)
188
171
 
189
172
  # =============================================================================
190
- # The most right way I know how to implement.
191
-
192
- theLogicalPathModuleSourceAlgorithm: str = '.'.join([thePackageName, theSourceAlgorithm])
193
- theLogicalPathModuleDispatcher: str = theLogicalPathModuleSourceAlgorithm
194
- theLogicalPathModuleDataclass: str = '.'.join([thePackageName, theDataclassModule])
195
-
196
- def getSourceAlgorithm() -> ModuleType:
197
- moduleImported: ModuleType = importlib_import_module(theLogicalPathModuleSourceAlgorithm)
198
- return moduleImported
199
-
200
- def getAlgorithmDispatcher() -> Callable[[ComputationState], ComputationState]:
201
- moduleImported: ModuleType = getSourceAlgorithm()
202
- dispatcherCallable = getattr(moduleImported, theDispatcherCallable)
203
- return dispatcherCallable
204
-
205
- def getPathSyntheticModules() -> Path:
206
- return thePathPackage / theModuleOfSyntheticModules
207
173
 
208
174
  # TODO learn how to see this from the user's perspective
209
175
  def getPathJobRootDEFAULT() -> Path:
210
176
  if 'google.colab' in sysModules:
211
177
  pathJobDEFAULT: Path = Path("/content/drive/MyDrive") / "jobs"
212
178
  else:
213
- pathJobDEFAULT = thePathPackage / "jobs"
179
+ pathJobDEFAULT = The.pathPackage / "jobs"
214
180
  return pathJobDEFAULT
215
181
 
216
182
  _datatypePackage: str = ''
217
183
  def getDatatypePackage() -> str:
218
184
  global _datatypePackage
219
185
  if not _datatypePackage:
220
- _datatypePackage = theDatatypePackage
186
+ _datatypePackage = The.datatypePackage
221
187
  return _datatypePackage
222
188
 
223
- def getNumpyDtypeDefault() -> type[signedinteger[Any]]:
224
- return numpyDtypeDefault
225
-
226
189
  # =============================================================================
227
190
  # The coping way.
228
191
 
229
192
  class raiseIfNoneGitHubIssueNumber3(Exception): pass
230
193
 
231
194
  # =============================================================================
232
- # Temporary or transient or something; probably still the wrong way
233
-
234
195
  # THIS IS A STUPID SYSTEM BUT I CAN'T FIGURE OUT AN IMPROVEMENT
235
196
  # NOTE This section for _default_ values probably has value
236
197
  # https://github.com/hunterhogan/mapFolding/issues/4
237
198
  theFormatStrModuleSynthetic = "{packageFlow}Count"
238
199
  theFormatStrModuleForCallableSynthetic = theFormatStrModuleSynthetic + "_{callableTarget}"
239
200
 
240
- theModuleDispatcherSynthetic: str = theFormatStrModuleForCallableSynthetic.format(packageFlow=packageFlowSynthetic, callableTarget=theDispatcherCallable)
241
- theLogicalPathModuleDispatcherSynthetic: str = '.'.join([thePackageName, theModuleOfSyntheticModules, theModuleDispatcherSynthetic])
201
+ theLogicalPathModuleDispatcher: str = The.logicalPathModuleSourceAlgorithm
242
202
 
243
- # =============================================================================
244
- # The most right way I know how to implement.
203
+ theModuleDispatcherSynthetic: str = theFormatStrModuleForCallableSynthetic.format(packageFlow=packageFlowSynthetic, callableTarget=The.dispatcherCallable)
204
+ theLogicalPathModuleDispatcherSynthetic: str = '.'.join([The.packageName, The.moduleOfSyntheticModules, theModuleDispatcherSynthetic])
245
205
 
246
- # https://github.com/hunterhogan/mapFolding/issues/4
247
206
  if Z0Z_packageFlow == packageFlowSynthetic: # pyright: ignore [reportUnnecessaryComparison]
248
207
  # NOTE this as a default value _might_ have value
249
208
  theLogicalPathModuleDispatcher = theLogicalPathModuleDispatcherSynthetic
250
209
 
251
- # https://github.com/hunterhogan/mapFolding/issues/4
252
210
  # dynamically set the return type https://github.com/hunterhogan/mapFolding/issues/5
253
211
  def getPackageDispatcher() -> Callable[[ComputationState], ComputationState]:
254
212
  # NOTE but this part, if the package flow is synthetic, probably needs to be delegated
255
213
  # to the authority for creating _that_ synthetic flow.
256
214
 
257
215
  moduleImported: ModuleType = importlib_import_module(theLogicalPathModuleDispatcher)
258
- dispatcherCallable = getattr(moduleImported, theDispatcherCallable)
216
+ dispatcherCallable = getattr(moduleImported, The.dispatcherCallable)
259
217
  return dispatcherCallable
260
218
 
261
219
  """Technical concepts I am likely using and likely want to use more effectively:
@@ -270,4 +228,13 @@ theSSOT and yourSSOT
270
228
  ----
271
229
  delay realization/instantiation until a concrete value is desired
272
230
  moment of truth: when the value is needed, not when the value is defined
231
+
232
+ ----
233
+ 2025 March 11
234
+ Note to self: fundamental concept in Python:
235
+ Identifiers: scope and resolution, LEGB (Local, Enclosing, Global, Builtin)
236
+ - Local: Inside the function
237
+ - Enclosing: Inside enclosing functions
238
+ - Global: At the uppermost level
239
+ - Builtin: Python's built-in names
273
240
  """
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.4
2
+ Name: mapFolding
3
+ Version: 0.8.2
4
+ Summary: Map folding algorithm with code transformation framework for optimizing numerical computations
5
+ Author-email: Hunter Hogan <HunterHogan@pm.me>
6
+ License: CC-BY-NC-4.0
7
+ Project-URL: Donate, https://www.patreon.com/integrated
8
+ Project-URL: Homepage, https://github.com/hunterhogan/mapFolding
9
+ Project-URL: Repository, https://github.com/hunterhogan/mapFolding.git
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
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Education
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Natural Language :: English
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
25
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
26
+ Classifier: Topic :: Software Development :: Code Generators
27
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
+ Classifier: Topic :: Software Development :: Compilers
29
+ Classifier: Typing :: Typed
30
+ Requires-Python: >=3.10
31
+ Description-Content-Type: text/markdown
32
+ License-File: LICENSE
33
+ Requires-Dist: autoflake
34
+ Requires-Dist: more_itertools
35
+ Requires-Dist: numba_progress
36
+ Requires-Dist: numba
37
+ Requires-Dist: numpy
38
+ Requires-Dist: python_minifier
39
+ Requires-Dist: tomli
40
+ Requires-Dist: Z0Z_tools
41
+ Provides-Extra: testing
42
+ Requires-Dist: mypy; extra == "testing"
43
+ Requires-Dist: pytest; extra == "testing"
44
+ Requires-Dist: pytest-cov; extra == "testing"
45
+ Requires-Dist: pytest-env; extra == "testing"
46
+ Requires-Dist: pytest-xdist; extra == "testing"
47
+ Requires-Dist: pyupgrade; extra == "testing"
48
+ Dynamic: license-file
49
+
50
+ # mapFolding: Algorithms for enumerating distinct map/stamp folding patterns 🗺️
51
+
52
+ [![pip install mapFolding](https://img.shields.io/badge/pip%20install-mapFolding-gray.svg?colorB=3b434b)](https://pypi.org/project/mapFolding/)
53
+ [![Static Badge](https://img.shields.io/badge/stinkin'%20badges-don't%20need-b98e5e)](https://youtu.be/g6f_miE91mk&t=4)
54
+ [![Python Tests](https://github.com/hunterhogan/mapFolding/actions/workflows/pythonTests.yml/badge.svg)](https://github.com/hunterhogan/mapFolding/actions/workflows/pythonTests.yml)
55
+ ![Static Badge](https://img.shields.io/badge/issues-I%20have%20them-brightgreen)
56
+ [![License: CC-BY-NC-4.0](https://img.shields.io/badge/License-CC_BY--NC_4.0-3b434b)](https://creativecommons.org/licenses/by-nc/4.0/)
57
+
58
+ ---
59
+
60
+ ## Quick start
61
+
62
+ ```sh
63
+ pip install mapFolding
64
+ ```
65
+
66
+ `OEIS_for_n` will run a computation from the command line.
67
+
68
+ ```cmd
69
+ (mapFolding) C:\apps\mapFolding> OEIS_for_n A001418 5
70
+ 186086600 distinct folding patterns.
71
+ Time elapsed: 1.605 seconds
72
+ ```
73
+
74
+ Use `mapFolding.oeisIDfor_n()` to compute a(n) for an OEIS ID.
75
+
76
+ ```python
77
+ from mapFolding import oeisIDfor_n
78
+ foldsTotal = oeisIDfor_n( 'A001418', 4 )
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Features
84
+
85
+ ### 1. Simple, easy usage based on OEIS IDs
86
+
87
+ `mapFolding` directly implements some IDs from [_The On-Line Encyclopedia of Integer Sequences_](https://oeis.org/) ([BibTex](https://github.com/hunterhogan/mapFolding/blob/main/citations/oeis.bibtex) citation).
88
+
89
+ Use `getOEISids` to get the most up-to-date list of available OEIS IDs.
90
+
91
+ ```cmd
92
+ (mapFolding) C:\apps\mapFolding> getOEISids
93
+
94
+ Available OEIS sequences:
95
+ A001415: Number of ways of folding a 2 X n strip of stamps.
96
+ A001416: Number of ways of folding a 3 X n strip of stamps.
97
+ A001417: Number of ways of folding a 2 X 2 X ... X 2 n-dimensional map.
98
+ A001418: Number of ways of folding an n X n sheet of stamps.
99
+ A195646: Number of ways of folding a 3 X 3 X ... X 3 n-dimensional map.
100
+ ```
101
+
102
+ ### 2. **Algorithm Zoo: A Historical and Performance Journey** 🦒
103
+
104
+ This package offers a comprehensive collection of map folding algorithm implementations that showcase its evolution from historical origins to high-performance computation:
105
+
106
+ - **Historical Implementations**:
107
+ - Carefully restored versions of Lunnon's 1971 original [algorithm](https://github.com/hunterhogan/mapFolding/blob/mapFolding/reference/foldings.txt) with corrections
108
+ - Atlas Autocode reconstruction in the `reference/foldings.AA` file
109
+
110
+ - **Direct Translations**:
111
+ - Python translations following the original control flow (`lunnanWhile.py`)
112
+ - NumPy-based vectorized implementations (`lunnanNumpy.py`)
113
+
114
+ - **Modern Implementations**:
115
+ - Java port adaptations (`irvineJavaPort.py`) providing cleaner procedural implementations
116
+ - Experimental JAX version (`jaxCount.py`) exploring GPU acceleration potential
117
+ - Semantically decomposed version (`flattened.py`) with clear function boundaries
118
+
119
+ - **Performance Optimized**:
120
+ - Numba-JIT accelerated implementations up to 1000× faster than pure Python (see [benchmarks](https://github.com/hunterhogan/mapFolding/blob/mapFolding/notes/Speed%20highlights.md))
121
+ - Algorithmic optimizations showcasing subtle yet powerful performance differences (`total_countPlus1vsPlusN.py`)
122
+
123
+ The `reference` directory serves as both a historical archive and an educational resource for understanding algorithm evolution.
124
+
125
+ ### 3. **Algorithmic Transformation: From Readability to Speed** 🔬
126
+
127
+ The package provides a sophisticated transformation framework that bridges the gap between human-readable algorithms and high-performance computation:
128
+
129
+ - **Core Algorithm Understanding**:
130
+ - Study the functional state-transformation approach in `theDao.py` with clear, isolated functions
131
+ - Explore the semantic decomposition in `reference/flattened.py` to understand algorithm sections
132
+
133
+ - **Code Transformation Pipeline**:
134
+ - **AST Manipulation**: Analyzes and transforms the algorithm's abstract syntax tree
135
+ - **Dataclass "Shattering"**: Decomposes complex state objects into primitive components
136
+ - **Optimization Applications**: Applies domain-specific optimizations for numerical computation
137
+ - **LLVM Integration**: Extracts LLVM IR for low-level algorithmic analysis
138
+
139
+ - **Performance Breakthroughs**:
140
+ - Learn why nearly identical algorithms can have dramatically different performance (`total_countPlus1vsPlusN.py`)
141
+ - See how memory layout and increment strategy impact computation speed
142
+ - Understand the batching technique that yields order-of-magnitude improvements
143
+
144
+ ### 4. **Multi-Level Architecture: From Simple API to Full Customization**
145
+
146
+ The package's architecture supports multiple levels of engagement:
147
+
148
+ - **Basic Usage**:
149
+ - Work with the high-level API in `basecamp.py` for standard computations
150
+ - Access OEIS sequence calculations with minimal code
151
+
152
+ - **Algorithm Exploration**:
153
+ - Compare different implementations in the `reference` directory to understand trade-offs
154
+ - Modify the core algorithm in `theDao.py` while preserving its functional approach
155
+ - Configure system-wide settings in `theSSOT.py` to adjust data types and performance characteristics
156
+
157
+ - **Advanced Transformation**:
158
+ - Use the `someAssemblyRequired` package to transform algorithms at the AST level
159
+ - Create optimized variants with different compilation settings using:
160
+ - `transformationTools.py` for AST manipulation
161
+ - `transformDataStructures.py` for complex data structure transformations
162
+ - `ingredientsNumba.py` for Numba-specific optimization profiles
163
+ - `synthesizeNumbaFlow.py` to orchestrate the transformation process
164
+
165
+ - **Custom Deployment**:
166
+ - Generate specialized implementations for specific dimensions
167
+ - Create optimized standalone modules for production use
168
+ - Extract LLVM IR for further analysis and optimization
169
+
170
+ The package's multi-level design allows you to start with simple API calls and progressively explore deeper optimization techniques as your computational needs grow.
171
+
172
+ ## Map-folding Video
173
+
174
+ ~~This caused my neurosis:~~ I enjoyed the following video, which is what introduced me to map folding.
175
+
176
+ "How Many Ways Can You Fold a Map?" by Physics for the Birds, 2024 November 13 ([BibTex](https://github.com/hunterhogan/mapFolding/blob/main/citations/Physics_for_the_Birds.bibtex) citation)
177
+
178
+ [![How Many Ways Can You Fold a Map?](https://i.ytimg.com/vi/sfH9uIY3ln4/hq720.jpg)](https://www.youtube.com/watch?v=sfH9uIY3ln4)
179
+
180
+ ---
181
+
182
+ ## My recovery
183
+
184
+ [![Static Badge](https://img.shields.io/badge/2011_August-Homeless_since-blue?style=flat)](https://HunterThinks.com/support)
185
+ [![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UC3Gx7kz61009NbhpRtPP7tw)](https://www.youtube.com/@HunterHogan)
186
+
187
+ [![CC-BY-NC-4.0](https://github.com/hunterhogan/mapFolding/blob/main/CC-BY-NC-4.0.svg)](https://creativecommons.org/licenses/by-nc/4.0/)
@@ -0,0 +1,39 @@
1
+ mapFolding/__init__.py,sha256=hYxPUBU6A1_XCbKEseSDamooTsb1mzN_XHqaRLPvpGk,1701
2
+ mapFolding/basecamp.py,sha256=uPwbb_fi8zqqBbVjb355qanSNUqqJ9aefcf_nrvA7qI,4510
3
+ mapFolding/beDRY.py,sha256=UhH52BryHQNRjphf_PirtMkV45rhdemdC9PmnpACq7I,9397
4
+ mapFolding/filesystem.py,sha256=-pYpWugd0p3TrAz7xf9YIJW-pn1X-iRCGtJgEAF9Rns,5923
5
+ mapFolding/noHomeYet.py,sha256=UKZeWlyn0SKlF9dhYoud7E6gWXpiSEekZOOoJp88WeI,1362
6
+ mapFolding/oeis.py,sha256=TbY8KtAGbQlT6eEsa_7HVMF7bMLN-aBFKclyTMHfqHk,12615
7
+ mapFolding/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ mapFolding/theDao.py,sha256=Blzm5j24x1BE2nvgXjdzHEeuc2na6kAH9b_eP6PcwlI,9836
9
+ mapFolding/theSSOT.py,sha256=HIU9UVKP0dXlxIO791z_tl1R7r5LiEcKnA5AI7H9SmU,12414
10
+ mapFolding/reference/__init__.py,sha256=7NYyWXyYYSdia2Q8SFJTcD0KvoUBLvvfuvTsaqcvchM,1777
11
+ mapFolding/reference/flattened.py,sha256=QK1xG9SllqCoi68e86Hyl9d9ATUAAFNpTQI-3zmcp5I,16072
12
+ mapFolding/reference/hunterNumba.py,sha256=espFiX92EPZ1Ub1YQVoBnNYvh2kFg1HR6Qa4djx8Ixg,7253
13
+ mapFolding/reference/irvineJavaPort.py,sha256=UEfIX4QbPLl5jnyfYIyX5YRR3_rYvPUikK8jLehsFko,4076
14
+ mapFolding/reference/jaxCount.py,sha256=TuDNKOnyhQfuixKmIxO9Algv7dvy7KMGhgsV3h96FGE,14853
15
+ mapFolding/reference/lunnanNumpy.py,sha256=mMgrgbrBpe4nmo72ThEI-MGH0OwEHmfMPczSXHp2qKo,4357
16
+ mapFolding/reference/lunnanWhile.py,sha256=ZL8GAQtPs5nJZSgoDl5USrLSS_zs03y98y1Z9E4jOmQ,3799
17
+ mapFolding/reference/rotatedEntryPoint.py,sha256=5ughpKUT2JQhoAKgoDUdYNjgWQYPGV8v-7dWEAdDmfE,10274
18
+ mapFolding/reference/total_countPlus1vsPlusN.py,sha256=yJZAVLVdoXqHag2_N6_6CT-Q6HXBgRro-eny93-Rlpw,9307
19
+ mapFolding/someAssemblyRequired/__init__.py,sha256=xA5a-nZjXIwcqEOig5PEZSxde4_m3JJ5Pb0CN4aiRjw,2488
20
+ mapFolding/someAssemblyRequired/getLLVMforNoReason.py,sha256=bGI8RZY-RnyR9TNF0r0OXwA6fm4TYH2cHy7WzhsnddQ,1895
21
+ mapFolding/someAssemblyRequired/ingredientsNumba.py,sha256=g6Z7t35NpoDskzm0OLwTQhHw5CYiYktVYxI2NhCQHww,8435
22
+ mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py,sha256=0179DMPoGJGP6AHs-nIac_aSfVBgpDyuaeCBVKlPRe8,10691
23
+ mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py,sha256=RBSrtr7US2P7mkY-EA-b2WIOxjs2b0WJaCln1ERxOcI,22314
24
+ mapFolding/someAssemblyRequired/transformDataStructures.py,sha256=Uth-WLzCTJTQkU15lsrBGf1ld7nqgLK42DUYM6-Q-n8,8605
25
+ mapFolding/someAssemblyRequired/transformationTools.py,sha256=n_lH9B7E871htRRRVJIDqGuT4WTmGiIgBb3ZjsY7ZjA,40689
26
+ mapFolding/syntheticModules/numbaCount_doTheNeedful.py,sha256=52RuwJVH2fROvWU2dT8wYcQvLgRuvkNZPq01kujCC_U,15725
27
+ mapfolding-0.8.2.dist-info/licenses/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
28
+ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ tests/conftest.py,sha256=hTpUTW7MtYGP5aeQnnoZMKgTEGCKdLJ8Fnmnv9d4NJw,11115
30
+ tests/test_computations.py,sha256=RHHByyuC8w-qbaag4Iqo_QNYm_7A-9BslbstMOdbZbU,3329
31
+ tests/test_filesystem.py,sha256=Kou0gj5T72oISao6umYfU6L_W5Hi7QS9_IxTv2hU0Pw,3147
32
+ tests/test_oeis.py,sha256=uxvwmgbnylSDdsVJfuAT0LuYLbIVFwSgdLxHm-xUGBM,5043
33
+ tests/test_other.py,sha256=4iF6JJ192BtDZUEZ0avbVRprCwfCUSOUC8GfCPrGS8M,4232
34
+ tests/test_tasks.py,sha256=hkZygihT8bCEO2zc-2VcxReQrZJBwgLNbYx0YP4lTDg,2853
35
+ mapfolding-0.8.2.dist-info/METADATA,sha256=8tSQtHxSLzIjIINZCw4EExiSeQV_wpLQXvf4gQ4xFNo,9143
36
+ mapfolding-0.8.2.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
37
+ mapfolding-0.8.2.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
38
+ mapfolding-0.8.2.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
39
+ mapfolding-0.8.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.1.0)
2
+ Generator: setuptools (77.0.3)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5