mapFolding 0.11.2__py3-none-any.whl → 0.11.3__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.
@@ -1,15 +1,13 @@
1
- mapFolding/__init__.py,sha256=COcJ0Fmrh_d2cDpDjsjEJTAI7kFOxuf2Sw3n5ozADD0,2288
2
- mapFolding/basecamp.py,sha256=77Bg9W2rRAuYxBKKVvKBw5Ea1HYrPetroSwj4kPT7Wg,8253
3
- mapFolding/beDRY.py,sha256=J4JFNvJdTz1J1P578DdniOOo5fewpxb5WERuNu19n24,22920
1
+ mapFolding/__init__.py,sha256=5aecz_WZCLtBsArV68h30OEQxrylPPm0oVfQMt0N94A,1948
2
+ mapFolding/basecamp.py,sha256=3MMWSN8eW4W_dZe_q7Vs5yqmazNFoml0VpcJNY2feho,8243
3
+ mapFolding/beDRY.py,sha256=kQrgBhJkXEy-J-Zyu4RHILK6gRm72a7cON7a1LewgwI,14004
4
4
  mapFolding/daoOfMapFolding.py,sha256=ncTIiBfTsM8SNVx9qefZ0bBcBtviWLSk4iPv3Z9nGiE,5442
5
5
  mapFolding/dataBaskets.py,sha256=crfmmYJGeJ7QLCzuYi4rtVOtzCDRoOiTNfPfHbc6Foo,5620
6
- mapFolding/datatypes.py,sha256=-TdXqAlEWEwUP_VUb9-X5pvaBBedbZOQbBuu5j1ZoTA,962
6
+ mapFolding/datatypes.py,sha256=dqOAa2RbiGcsRl9X4qo4tdMamgOoZVnewrMjY4mHXS4,773
7
7
  mapFolding/filesystemToolkit.py,sha256=O9VQ0tSXlrGUhU3qN7uWxOTAZfuQb3fcRkTrfRZrGXo,9854
8
- mapFolding/infoBooth.py,sha256=IPEzgb90p30i2mmPsdZ1VHYGmf-xPg_bpoKJDdDEn-k,5586
9
- mapFolding/oeis.py,sha256=5vNuZSq--Q-rFXtDvLMuoNhh5yLqFZugvXNxy4fs02U,17064
8
+ mapFolding/oeis.py,sha256=ifs9Uu4uqgKCd46aHuCqhyXt2JXLMcPmmWRFuXIBACg,16926
10
9
  mapFolding/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- mapFolding/theDao.py,sha256=P-a4xIGwI_40fMWp_ypHRWa6JIFchK59tdTrXiYqTHk,10017
12
- mapFolding/theSSOT.py,sha256=BVqgXki5qY-d1Kf-AnO2-KeMbMZx805Y0hh8qM7BcxE,1297
10
+ mapFolding/theSSOT.py,sha256=7CyB3FnDWyNovTuUPRvSIfF7GxQc3aZoIsIwF1-4OyE,1456
13
11
  mapFolding/reference/__init__.py,sha256=GKcSgYE49NcTISx-JZbELXyq-eRkMeTL5g4DXInWFw0,2206
14
12
  mapFolding/reference/flattened.py,sha256=QK1xG9SllqCoi68e86Hyl9d9ATUAAFNpTQI-3zmcp5I,16072
15
13
  mapFolding/reference/hunterNumba.py,sha256=iLfyqwGdAh6c5GbapnKsWhAsNsR3O-fyGGHAdohluLw,7258
@@ -22,35 +20,34 @@ mapFolding/reference/total_countPlus1vsPlusN.py,sha256=yJZAVLVdoXqHag2_N6_6CT-Q6
22
20
  mapFolding/reference/jobsCompleted/__init__.py,sha256=TU93ZGUW1xEkT6d9mQFn_rp5DvRy0ZslEB2Q6MF5ZDc,2596
23
21
  mapFolding/reference/jobsCompleted/[2x19]/p2x19.py,sha256=_tvYtfzMWVo2VtUbIAieoscb4N8FFflgTdW4-ljBUuA,19626
24
22
  mapFolding/reference/jobsCompleted/p2x19/p2x19.py,sha256=eZEw4Me4ocTt6VXoK2-Sbd5SowZtxRIbN9dZmc7OCVg,6395
25
- mapFolding/someAssemblyRequired/RecipeJob.py,sha256=niqbnxgtHk-eR-ph7FBw2S74uEQmx6Xmsh8CPx09q4o,10130
26
- mapFolding/someAssemblyRequired/Z0Z_makeSomeModules.py,sha256=8OauVDHmS05kYSMgBgvtxlq85nhXhFEtsFN2j1HLhZA,29786
27
- mapFolding/someAssemblyRequired/__init__.py,sha256=l9KaHEuPwL5WKWHhvaF8LiJshyYcu-3LZTVvWTX804U,3591
28
- mapFolding/someAssemblyRequired/_toolIfThis.py,sha256=0S0t-BEuFPLw0LDvFIRF3-5yvjgJxkBRTrbOgjSlwrk,3165
29
- mapFolding/someAssemblyRequired/_toolkitContainers.py,sha256=SSS5kieMgm-vSHRGfUOvxcAWaWGytN9uzaBb0AvF-SM,16086
23
+ mapFolding/someAssemblyRequired/RecipeJob.py,sha256=H53d1pIxh6kvEsh9Nmj7bD8agMBbpHziY2XrN808eGc,4432
24
+ mapFolding/someAssemblyRequired/Z0Z_makeAllModules.py,sha256=7REamiISEiZQ_goseQB2BJW4kMb4wRhoJnqhIRdX_zI,30262
25
+ mapFolding/someAssemblyRequired/__init__.py,sha256=Wq8rrFJzZsQV4oYQmDXSlDtAlU4TRgMc5o0EKJedvGE,2705
26
+ mapFolding/someAssemblyRequired/_toolIfThis.py,sha256=nq7brHOA4JOK9P-RWyOFae6QxzX40nV46DNDrNmkLYo,3122
27
+ mapFolding/someAssemblyRequired/_toolkitContainers.py,sha256=C-GkXSYoneWmcJWULPa5bgLidjjcIFbrEtEpnrK1m_Y,9784
30
28
  mapFolding/someAssemblyRequired/getLLVMforNoReason.py,sha256=9RPU6vK_eUg64GtVFI_nZnvUryXw8gfHJs9NyDYHIvg,2745
31
- mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py,sha256=zWPmosEMt94zl00hDMZ-1t1pkROg8yYAktw_aKvAPjA,13978
32
- mapFolding/someAssemblyRequired/synthesizeNumbaJob.py,sha256=64TZh-AfaToTU-UM_0_pz5DzsvxcnVuUl6j9C1S3zGM,15740
33
- mapFolding/someAssemblyRequired/toolkitNumba.py,sha256=LZdosArlkNzFUwy8BMhswivW5xfhREAPyx2ApNOuse8,8961
34
- mapFolding/someAssemblyRequired/transformationTools.py,sha256=hNfYXQQMPsNab_oHdx4G3E5cXYp5-vZaG4LTWtnuwFk,19073
29
+ mapFolding/someAssemblyRequired/infoBooth.py,sha256=IXzpt_YKkWfOOiaQaBh61SiEd-TnLRlHifmq_1mCow4,4249
30
+ mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py,sha256=6bKLNI9po2qS1_JsKr4wnqwY1A5eL5LQN9uLu3jTlkM,14039
31
+ mapFolding/someAssemblyRequired/toolkitNumba.py,sha256=c-rq2rY-Vr0X4asnGy2cmmKTJonv2Jh_mw3oWHT1ctI,6649
32
+ mapFolding/someAssemblyRequired/transformationTools.py,sha256=ysvZaP8XqxXjHtSHlaErNDGHI5OrRRcqVhnzs3F8UUA,8256
35
33
  mapFolding/syntheticModules/__init__.py,sha256=evVFqhCGa-WZKDiLcnQWjs-Bj34eRnfSLqz_d7dFYZY,83
36
34
  mapFolding/syntheticModules/countParallel.py,sha256=OK_IB9w4yy9MMAiGvkei5ezPm_00v2nYjPrQZ_IlELg,7733
37
35
  mapFolding/syntheticModules/daoOfMapFolding.py,sha256=cfWPABtXyCxJ0BwPI7rhfLh_2UYV_XKAL8lJ4GLNXaQ,5896
38
36
  mapFolding/syntheticModules/dataPacking.py,sha256=m_eOZ7sMXIQ9jY5EvC3qgitQTY60n6rksy0ACMJOIC8,2292
39
37
  mapFolding/syntheticModules/initializeCount.py,sha256=nWSlJMMfIM3DvZxMn6ISQusUJqRYAjKQyLF5hwLEdBQ,3119
40
- mapFolding/syntheticModules/numbaCount.py,sha256=HOuCGqykFvYwa-WPkj1qGsZOzJV3ZYxeoZZmIUFY_Wo,13503
41
38
  mapFolding/syntheticModules/theorem2.py,sha256=9jrbZNNX4BWYZW1S0JjvRY2k7RU7I1RNUMV7JdCt1ZY,3017
42
39
  mapFolding/syntheticModules/theorem2Numba.py,sha256=-cKjNyxgUMFhEyFVs0VJ7hw4LfrV0WSNK5tPYbQ1oNU,3369
43
40
  mapFolding/syntheticModules/theorem2Trimmed.py,sha256=DHW3NxBdtABQYBKm2WRvfQ5kzc2_UwGI2h4ePuYEJoM,2685
44
- mapfolding-0.11.2.dist-info/licenses/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
41
+ mapfolding-0.11.3.dist-info/licenses/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
45
42
  tests/__init__.py,sha256=5VhHf0JJ2_DSh58zJ0rR5UkpoCon-0IkdljspTCzZ04,1950
46
- tests/conftest.py,sha256=7zoNA5PLIwm8VY2dLVaZqVDwWG1HQ29IuHTQoAScRF0,14138
47
- tests/test_computations.py,sha256=ADlT9VDYHyi_QV7XIt2qrHPZkn6O8N7dZ3w4aRZDgFE,6524
43
+ tests/conftest.py,sha256=eumQRoDuWVrhsjDxWXGhW0N7lH0ZZ9XD-5q81bWFqOs,10874
44
+ tests/test_computations.py,sha256=HNpfs9Yz3rdfJInD15Jwd6DYsSR5TCwnR5EW0n7KbeI,5682
48
45
  tests/test_filesystem.py,sha256=imlcetleJc4G9pDZTgS1j8UAs7ADbRxXVuNPecJAvqc,2964
49
46
  tests/test_oeis.py,sha256=uxvwmgbnylSDdsVJfuAT0LuYLbIVFwSgdLxHm-xUGBM,5043
50
47
  tests/test_other.py,sha256=DT7YE82YCHrSjdxhpY4UJnXmZvDm1b4e1QpZV3LyzcM,3747
51
- tests/test_tasks.py,sha256=-Y6BILdUpWhfxccqiTFt1h_eBfgK8-BLluGOZdaIq8k,2778
52
- mapfolding-0.11.2.dist-info/METADATA,sha256=VEQE8TJb3nCVzn9JJI6U_0rgQtrmfdHf7YupwPTexcE,7796
53
- mapfolding-0.11.2.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
54
- mapfolding-0.11.2.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
55
- mapfolding-0.11.2.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
56
- mapfolding-0.11.2.dist-info/RECORD,,
48
+ tests/test_tasks.py,sha256=pEDukf2SVTOMEsn82JpAWKQzn1ZCTlkhLzQ5hYLg2yY,2780
49
+ mapfolding-0.11.3.dist-info/METADATA,sha256=FyB0PTluboy3BsrccAJJGrEhGpo5nUsbd3JJe6CAsXo,7712
50
+ mapfolding-0.11.3.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
51
+ mapfolding-0.11.3.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
52
+ mapfolding-0.11.3.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
53
+ mapfolding-0.11.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.1.0)
2
+ Generator: setuptools (80.3.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
tests/conftest.py CHANGED
@@ -56,14 +56,10 @@ See the examples in `test_computations.py` for guidance on adapting these fixtur
56
56
  """
57
57
 
58
58
  from collections.abc import Callable, Generator, Sequence
59
- from mapFolding import getLeavesTotal, validateListDimensions, makeDataContainer, The
59
+ from mapFolding import getLeavesTotal, validateListDimensions, makeDataContainer
60
60
  from mapFolding.oeis import oeisIDsImplemented, settingsOEIS
61
- from mapFolding.someAssemblyRequired import importLogicalPath2Callable, RecipeSynthesizeFlow
62
- from pathlib import Path, PurePosixPath
63
- from types import ModuleType
61
+ from pathlib import Path
64
62
  from typing import Any
65
- import importlib
66
- import importlib.util
67
63
  import numpy
68
64
  import pytest
69
65
  import random
@@ -238,77 +234,6 @@ def oeisID_1random() -> str:
238
234
  """Return one random valid OEIS ID."""
239
235
  return random.choice(oeisIDsImplemented)
240
236
 
241
- @pytest.fixture
242
- def useThisDispatcher() -> Generator[Callable[..., None], Any, None]:
243
- """A fixture providing a context manager for temporarily replacing the dispatcher.
244
-
245
- Returns
246
- A context manager for patching the dispatcher
247
- """
248
- import mapFolding.infoBooth as infoBooth
249
-
250
- # Store original property method
251
- original_dispatcher_property = infoBooth.PackageInformation.dispatcher
252
-
253
- def patchDispatcher(callableTarget: Callable[..., Any]) -> None:
254
- """Patch the dispatcher property to return the target callable."""
255
- # Create a new property that returns the target callable
256
- def patched_dispatcher(self: infoBooth.PackageInformation) -> Callable[..., Any]:
257
- def wrapper(state: Any) -> Any:
258
- return callableTarget(state)
259
- return wrapper
260
-
261
- # Replace the property with our patched version
262
- infoBooth.PackageInformation.dispatcher = property(patched_dispatcher) # type: ignore
263
-
264
- yield patchDispatcher
265
-
266
- # Restore the original property
267
- infoBooth.PackageInformation.dispatcher = original_dispatcher_property # type: ignore
268
-
269
- def getAlgorithmDispatcher() -> Callable[..., Any]:
270
- moduleImported: ModuleType = importlib.import_module(The.logicalPathModuleSourceAlgorithm)
271
- dispatcherCallable = getattr(moduleImported, The.sourceCallableDispatcher)
272
- return dispatcherCallable
273
-
274
- @pytest.fixture
275
- def useAlgorithmSourceDispatcher(useThisDispatcher: Callable[..., Any]) -> Generator[None, None, None]:
276
- """Temporarily patches getDispatcherCallable to return the algorithm dispatcher."""
277
- useThisDispatcher(importLogicalPath2Callable(The.logicalPathModuleSourceAlgorithm, The.sourceCallableDispatcher))
278
- yield
279
-
280
- @pytest.fixture
281
- def syntheticDispatcherFixture(useThisDispatcher: Callable[..., Any], pathTmpTesting: Path) -> Callable[..., Any]:
282
- """Generate synthetic Numba-optimized dispatcher module and patch the dispatcher"""
283
- from mapFolding.someAssemblyRequired.toolkitNumba import makeNumbaFlow
284
-
285
- TESTINGrecipeFlow = RecipeSynthesizeFlow(
286
- pathPackage=PurePosixPath(pathTmpTesting.absolute()),
287
- logicalPathFlowRoot=None,
288
- moduleDispatcher="test_dispatcher",
289
- # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
290
- # dispatcherCallable="dispatcherSynthetic",
291
- )
292
-
293
- # Generate optimized module in test directory
294
- makeNumbaFlow(TESTINGrecipeFlow)
295
-
296
- # Import synthesized dispatcher
297
- importlibSpecificationDispatcher = importlib.util.spec_from_file_location(
298
- TESTINGrecipeFlow.moduleDispatcher,
299
- Path(TESTINGrecipeFlow.pathFilenameDispatcher),
300
- )
301
- if importlibSpecificationDispatcher is None or importlibSpecificationDispatcher.loader is None:
302
- raise ImportError("Failed to load synthetic dispatcher module")
303
-
304
- moduleSpecificationDispatcher = importlib.util.module_from_spec(importlibSpecificationDispatcher)
305
- importlibSpecificationDispatcher.loader.exec_module(moduleSpecificationDispatcher)
306
- callableDispatcherSynthetic = getattr(moduleSpecificationDispatcher, TESTINGrecipeFlow.callableDispatcher)
307
-
308
- # Patch dispatcher and return callable
309
- useThisDispatcher(callableDispatcherSynthetic)
310
- return callableDispatcherSynthetic
311
-
312
237
  def uniformTestMessage(expected: Any, actual: Any, functionName: str, *arguments: Any) -> str:
313
238
  """Format assertion message for any test comparison."""
314
239
  return (f"\nTesting: `{functionName}({', '.join(str(parameter) for parameter in arguments)})`\n"
@@ -85,13 +85,14 @@ All tests leverage standardized utilities like `standardizedEqualToCallableRetur
85
85
  that provide consistent, informative error messages and simplify test validation.
86
86
  """
87
87
 
88
- from typing import Literal
89
88
  from mapFolding import countFolds, getFoldsTotalKnown, oeisIDfor_n
89
+ from mapFolding.dataBaskets import MapFoldingState
90
90
  from mapFolding.oeis import settingsOEIS
91
- from mapFolding.someAssemblyRequired.RecipeJob import RecipeJob
92
- from mapFolding.someAssemblyRequired.transformationTools import makeInitializedComputationState
91
+ from mapFolding.someAssemblyRequired.RecipeJob import RecipeJobTheorem2Numba
92
+ from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
93
93
  from pathlib import Path, PurePosixPath
94
94
  from tests.conftest import standardizedEqualToCallableReturn, registrarRecordsTmpObject
95
+ from typing import Literal
95
96
  import importlib.util
96
97
  import multiprocessing
97
98
  import pytest
@@ -99,41 +100,33 @@ import pytest
99
100
  if __name__ == '__main__':
100
101
  multiprocessing.set_start_method('spawn')
101
102
 
102
- def test_algorithmSourceParallel(mapShapeTestParallelization: tuple[int, ...], useAlgorithmSourceDispatcher: None) -> None:
103
- standardizedEqualToCallableReturn(getFoldsTotalKnown(mapShapeTestParallelization), countFolds, mapShapeTestParallelization, None, 'maximum', None)
103
+ # TODO test synthesis
104
104
 
105
105
  @pytest.mark.parametrize('flow', ['daoOfMapFolding', 'theorem2', 'theorem2Trimmed', 'theorem2numba'])
106
106
  def test_flowControl(mapShapeTestCountFolds: tuple[int, ...], flow: Literal['daoOfMapFolding'] | Literal['theorem2'] | Literal['theorem2numba']) -> None:
107
107
  standardizedEqualToCallableReturn(getFoldsTotalKnown(mapShapeTestCountFolds), countFolds, None, None, None, None, mapShapeTestCountFolds, None, None, flow)
108
108
 
109
- def test_algorithmSourceSequential(mapShapeTestCountFolds: tuple[int, ...], useAlgorithmSourceDispatcher: None) -> None:
110
- standardizedEqualToCallableReturn(getFoldsTotalKnown(mapShapeTestCountFolds), countFolds, mapShapeTestCountFolds)
111
-
112
109
  def test_aOFn_calculate_value(oeisID: str) -> None:
113
110
  for n in settingsOEIS[oeisID]['valuesTestValidation']:
114
111
  standardizedEqualToCallableReturn(settingsOEIS[oeisID]['valuesKnown'][n], oeisIDfor_n, oeisID, n)
115
112
 
116
- def test_syntheticParallel(syntheticDispatcherFixture: None, mapShapeTestParallelization: tuple[int, ...]) -> None:
117
- standardizedEqualToCallableReturn(getFoldsTotalKnown(mapShapeTestParallelization), countFolds, mapShapeTestParallelization, None, 'maximum')
118
-
119
- def test_syntheticSequential(syntheticDispatcherFixture: None, mapShapeTestCountFolds: tuple[int, ...]) -> None:
120
- standardizedEqualToCallableReturn(getFoldsTotalKnown(mapShapeTestCountFolds), countFolds, mapShapeTestCountFolds)
121
-
122
113
  @pytest.mark.parametrize('pathFilenameTmpTesting', ['.py'], indirect=True)
123
114
  def test_writeJobNumba(oneTestCuzTestsOverwritingTests: tuple[int, ...], pathFilenameTmpTesting: Path) -> None:
124
115
  from mapFolding.someAssemblyRequired.toolkitNumba import SpicesJobNumba
125
- from mapFolding.someAssemblyRequired.synthesizeNumbaJob import makeJobNumba
126
- state = makeInitializedComputationState(oneTestCuzTestsOverwritingTests)
116
+ from mapFolding.someAssemblyRequired.makeJobTheorem2Numba import makeJobNumba
117
+ mapShape = oneTestCuzTestsOverwritingTests
118
+ state = MapFoldingState(mapShape)
119
+ state = initializeGroupsOfFolds(state)
127
120
 
128
121
  pathFilenameModule = pathFilenameTmpTesting.absolute()
129
122
  pathFilenameFoldsTotal = pathFilenameModule.with_suffix('.foldsTotalTesting')
130
123
  registrarRecordsTmpObject(pathFilenameFoldsTotal)
131
124
 
132
- jobTest = RecipeJob(state
125
+ jobTest = RecipeJobTheorem2Numba(state
133
126
  , pathModule=PurePosixPath(pathFilenameModule.parent)
134
127
  , moduleIdentifier=pathFilenameModule.stem
135
128
  , pathFilenameFoldsTotal=PurePosixPath(pathFilenameFoldsTotal))
136
- spices = SpicesJobNumba()
129
+ spices = SpicesJobNumba(useNumbaProgressBar=False)
137
130
  makeJobNumba(jobTest, spices)
138
131
 
139
132
  Don_Lapre_Road_to_Self_Improvement = importlib.util.spec_from_file_location("__main__", pathFilenameModule)
tests/test_tasks.py CHANGED
@@ -6,7 +6,8 @@ from Z0Z_tools.pytestForYourUse import PytestFor_defineConcurrencyLimit
6
6
  import multiprocessing
7
7
  import pytest
8
8
 
9
- # When to use multiprocessing.set_start_method https://github.com/hunterhogan/mapFolding/issues/6
9
+ # When to use multiprocessing.set_start_method
10
+ # https://github.com/hunterhogan/mapFolding/issues/6
10
11
  if __name__ == '__main__':
11
12
  multiprocessing.set_start_method('spawn')
12
13
 
@@ -1,315 +0,0 @@
1
- """
2
- Job-specific Numba Code Generation for Map Folding Calculations
3
-
4
- This module specializes in generating highly-optimized, single-purpose Numba modules
5
- for specific map folding calculation jobs. Unlike the general-purpose transformation
6
- in toolboxNumba.py, this module creates standalone Python modules optimized for a
7
- single map shape with statically-encoded parameters.
8
-
9
- The code generation assembly line focuses on:
10
-
11
- 1. Converting function parameters to initialized variables with concrete values.
12
- 2. Replacing dynamic computations with statically-known values.
13
- 3. Eliminating unused code paths and variables.
14
- 4. Adding progress tracking for long-running calculations.
15
- 5. Applying appropriate Numba optimizations for the specific calculation.
16
-
17
- This creates extremely fast, specialized implementations that can be run directly
18
- as Python scripts or further compiled into standalone executables.
19
- """
20
-
21
- from astToolkit import ClassIsAndAttribute
22
- from mapFolding import getPathFilenameFoldsTotal, raiseIfNoneGitHubIssueNumber3, The
23
- from mapFolding.someAssemblyRequired import (
24
- ast_Identifier,
25
- Be,
26
- extractFunctionDef,
27
- IfThis,
28
- IngredientsFunction,
29
- IngredientsModule,
30
- LedgerOfImports,
31
- Make,
32
- NodeChanger,
33
- NodeTourist,
34
- str_nameDOTname,
35
- Then,
36
- write_astModule,
37
- )
38
- from mapFolding.someAssemblyRequired.RecipeJob import RecipeJob
39
- from mapFolding.someAssemblyRequired.toolkitNumba import parametersNumbaLight, SpicesJobNumba, decorateCallableWithNumba
40
- from mapFolding.someAssemblyRequired.transformationTools import dictionaryEstimates, makeInitializedComputationState
41
- from pathlib import PurePosixPath
42
- from typing import cast, NamedTuple
43
- from Z0Z_tools import autoDecodingRLE
44
- import ast
45
- """Synthesize one file to compute `foldsTotal` of `mapShape`."""
46
-
47
- list_IdentifiersNotUsedAllHARDCODED = ['concurrencyLimit', 'foldsTotal', 'mapShape',]
48
- list_IdentifiersNotUsedParallelSequentialHARDCODED = ['indexLeaf']
49
- list_IdentifiersNotUsedSequentialHARDCODED = ['foldGroups', 'taskDivisions', 'taskIndex',]
50
-
51
- list_IdentifiersReplacedHARDCODED = ['groupsOfFolds',]
52
-
53
- list_IdentifiersStaticValuesHARDCODED = ['dimensionsTotal', 'leavesTotal',]
54
-
55
- list_IdentifiersNotUsedHARDCODED = list_IdentifiersStaticValuesHARDCODED + list_IdentifiersReplacedHARDCODED + list_IdentifiersNotUsedAllHARDCODED + list_IdentifiersNotUsedParallelSequentialHARDCODED + list_IdentifiersNotUsedSequentialHARDCODED
56
-
57
- def addLauncherNumbaProgress(ingredientsModule: IngredientsModule, ingredientsFunction: IngredientsFunction, job: RecipeJob, spices: SpicesJobNumba) -> tuple[IngredientsModule, IngredientsFunction]:
58
- """
59
- Add progress tracking capabilities to a Numba-optimized function.
60
-
61
- This function modifies both the module and the function to integrate Numba-compatible
62
- progress tracking for long-running calculations. It performs several key transformations:
63
-
64
- 1. Adds a progress bar parameter to the function signature
65
- 2. Replaces counting increments with progress bar updates
66
- 3. Creates a launcher section that displays and updates progress
67
- 4. Configures file output to save results upon completion
68
-
69
- The progress tracking is particularly important for map folding calculations
70
- which can take hours or days to complete, providing visual feedback and
71
- estimated completion times.
72
-
73
- Parameters:
74
- ingredientsModule: The module where the function is defined.
75
- ingredientsFunction: The function to modify with progress tracking.
76
- job: Configuration specifying shape details and output paths.
77
- spices: Configuration specifying progress bar details.
78
-
79
- Returns:
80
- A tuple containing the modified module and function with progress tracking.
81
- """
82
- linesLaunch: str = f"""
83
- if __name__ == '__main__':
84
- with ProgressBar(total={job.foldsTotalEstimated}, update_interval=2) as statusUpdate:
85
- {job.countCallable}(statusUpdate)
86
- foldsTotal = statusUpdate.n * {job.state.leavesTotal}
87
- print('\\nmap {job.state.mapShape} =', foldsTotal)
88
- writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
89
- writeStream.write(str(foldsTotal))
90
- writeStream.close()
91
- """
92
- numba_progressPythonClass: ast_Identifier = 'ProgressBar'
93
- numba_progressNumbaType: ast_Identifier = 'ProgressBarType'
94
- ingredientsModule.imports.addImportFrom_asStr('numba_progress', numba_progressPythonClass)
95
- ingredientsModule.imports.addImportFrom_asStr('numba_progress', numba_progressNumbaType)
96
-
97
- ast_argNumbaProgress = ast.arg(arg=spices.numbaProgressBarIdentifier, annotation=ast.Name(id=numba_progressPythonClass, ctx=ast.Load()))
98
- ingredientsFunction.astFunctionDef.args.args.append(ast_argNumbaProgress)
99
-
100
- findThis = ClassIsAndAttribute.targetIs(ast.AugAssign, IfThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id)) # type: ignore
101
- doThat = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(spices.numbaProgressBarIdentifier),'update'),[Make.Constant(1)])))
102
- countWithProgressBar = NodeChanger(findThis, doThat)
103
- countWithProgressBar.visit(ingredientsFunction.astFunctionDef)
104
-
105
- removeReturnStatement = NodeChanger(Be.Return, Then.removeIt)
106
- removeReturnStatement.visit(ingredientsFunction.astFunctionDef)
107
- ingredientsFunction.astFunctionDef.returns = Make.Constant(value=None)
108
-
109
- ingredientsModule.appendLauncher(ast.parse(linesLaunch))
110
-
111
- return ingredientsModule, ingredientsFunction
112
-
113
- def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: IngredientsFunction, job: RecipeJob) -> IngredientsFunction:
114
- """
115
- Convert function parameters into initialized variables with concrete values.
116
-
117
- This function implements a critical transformation that converts function parameters
118
- into statically initialized variables in the function body. This enables several
119
- optimizations:
120
-
121
- 1. Eliminating parameter passing overhead.
122
- 2. Embedding concrete values directly in the code.
123
- 3. Allowing Numba to optimize based on known value characteristics.
124
- 4. Simplifying function signatures for specialized use cases.
125
-
126
- The function handles different data types (scalars, arrays, custom types) appropriately,
127
- replacing abstract parameter references with concrete values from the computation state.
128
- It also removes unused parameters and variables to eliminate dead code.
129
-
130
- Parameters:
131
- ingredientsFunction: The function to transform.
132
- job: Recipe containing concrete values for parameters and field metadata.
133
-
134
- Returns:
135
- The modified function with parameters converted to initialized variables.
136
- """
137
- ingredientsFunction.imports.update(job.shatteredDataclass.imports)
138
-
139
- list_argCuzMyBrainRefusesToThink = ingredientsFunction.astFunctionDef.args.args + ingredientsFunction.astFunctionDef.args.posonlyargs + ingredientsFunction.astFunctionDef.args.kwonlyargs
140
- list_arg_arg: list[ast_Identifier] = [ast_arg.arg for ast_arg in list_argCuzMyBrainRefusesToThink]
141
- listName: list[ast.Name] = []
142
- NodeTourist(Be.Name, Then.appendTo(listName)).visit(ingredientsFunction.astFunctionDef)
143
- list_Identifiers: list[ast_Identifier] = [astName.id for astName in listName]
144
- list_IdentifiersNotUsed: list[ast_Identifier] = list(set(list_arg_arg) - set(list_Identifiers))
145
-
146
- for ast_arg in list_argCuzMyBrainRefusesToThink:
147
- if ast_arg.arg in job.shatteredDataclass.field2AnnAssign:
148
- if ast_arg.arg in list_IdentifiersNotUsed:
149
- pass
150
- else:
151
- ImaAnnAssign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[ast_arg.arg]
152
- match elementConstructor:
153
- case 'scalar':
154
- cast(ast.Constant, cast(ast.Call, ImaAnnAssign.value).args[0]).value = int(job.state.__dict__[ast_arg.arg])
155
- case 'array':
156
- dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[ast_arg.arg], True)
157
- dataAs_astExpr: ast.expr = cast(ast.Expr, ast.parse(dataAsStrRLE).body[0]).value
158
- cast(ast.Call, ImaAnnAssign.value).args = [dataAs_astExpr]
159
- case _:
160
- list_exprDOTannotation: list[ast.expr] = []
161
- list_exprDOTvalue: list[ast.expr] = []
162
- for dimension in job.state.mapShape:
163
- list_exprDOTannotation.append(Make.Name(elementConstructor))
164
- list_exprDOTvalue.append(Make.Call(Make.Name(elementConstructor), [Make.Constant(dimension)]))
165
- cast(ast.Tuple, cast(ast.Subscript, cast(ast.AnnAssign, ImaAnnAssign).annotation).slice).elts = list_exprDOTannotation
166
- cast(ast.Tuple, ImaAnnAssign.value).elts = list_exprDOTvalue
167
-
168
- ingredientsFunction.astFunctionDef.body.insert(0, ImaAnnAssign)
169
-
170
- findThis = IfThis.is_arg_Identifier(ast_arg.arg)
171
- remove_arg = NodeChanger(findThis, Then.removeIt)
172
- remove_arg.visit(ingredientsFunction.astFunctionDef)
173
-
174
- ast.fix_missing_locations(ingredientsFunction.astFunctionDef)
175
- return ingredientsFunction
176
-
177
- def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba) -> None:
178
- """
179
- Generate a highly-optimized, single-purpose Numba module for a specific map shape.
180
-
181
- This function implements the complete transformation assembly line for creating a
182
- standalone, specialized implementation for calculating map folding solutions for
183
- a specific shape. The process includes:
184
-
185
- 1. Extracting the counting function from the source module
186
- 2. Removing unused code paths based on static analysis
187
- 3. Replacing dynamic variables with concrete values
188
- 4. Converting parameters to initialized variables
189
- 5. Adding progress tracking if requested
190
- 6. Applying Numba optimizations and type specifications
191
- 7. Writing the final module to the filesystem
192
-
193
- The resulting Python module is both human-readable and extraordinarily efficient,
194
- with all shape-specific optimizations statically encoded. This creates specialized
195
- implementations that can be orders of magnitude faster than general-purpose code.
196
-
197
- Parameters:
198
- job: Configuration specifying the target shape, paths, and computation state.
199
- spices: Configuration specifying Numba and progress tracking options.
200
- """
201
- astFunctionDef = extractFunctionDef(job.source_astModule, job.countCallable)
202
- if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
203
- ingredientsCount: IngredientsFunction = IngredientsFunction(astFunctionDef, LedgerOfImports())
204
-
205
- # Remove `foldGroups` and any other unused statements, so you can dynamically determine which variables are not used
206
- findThis = IfThis.isAssignAndTargets0Is(IfThis.isSubscript_Identifier('foldGroups'))
207
- doThat = Then.removeIt
208
- remove_foldGroups = NodeChanger(findThis, doThat)
209
- remove_foldGroups.visit(ingredientsCount.astFunctionDef)
210
-
211
- # replace identifiers with static values with their values, so you can dynamically determine which variables are not used
212
- list_IdentifiersStaticValues = list_IdentifiersStaticValuesHARDCODED
213
- for identifier in list_IdentifiersStaticValues:
214
- findThis = IfThis.isName_Identifier(identifier)
215
- doThat = Then.replaceWith(Make.Constant(int(job.state.__dict__[identifier])))
216
- NodeChanger(findThis, doThat).visit(ingredientsCount.astFunctionDef)
217
-
218
- ingredientsModule = IngredientsModule()
219
- # This launcher eliminates the use of one identifier, so run it now and you can dynamically determine which variables are not used
220
- if spices.useNumbaProgressBar:
221
- ingredientsModule, ingredientsCount = addLauncherNumbaProgress(ingredientsModule, ingredientsCount, job, spices)
222
- spices.parametersNumba['nogil'] = True
223
- else:
224
- linesLaunch: str = f"""
225
- if __name__ == '__main__':
226
- import time
227
- timeStart = time.perf_counter()
228
- foldsTotal = {job.countCallable}() * {job.state.leavesTotal}
229
- print(time.perf_counter() - timeStart)
230
- print('\\nmap {job.state.mapShape} =', foldsTotal)
231
- writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
232
- writeStream.write(str(foldsTotal))
233
- writeStream.close()
234
- """
235
- # from mapFolding.oeis import getFoldsTotalKnown
236
- # print(foldsTotal == getFoldsTotalKnown({job.state.mapShape}))
237
- ingredientsModule.appendLauncher(ast.parse(linesLaunch))
238
- changeReturnParallelCallable = NodeChanger(Be.Return, Then.replaceWith(Make.Return(job.shatteredDataclass.countingVariableName)))
239
- changeReturnParallelCallable.visit(ingredientsCount.astFunctionDef)
240
- ingredientsCount.astFunctionDef.returns = job.shatteredDataclass.countingVariableAnnotation
241
-
242
- ingredientsCount = move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsCount, job)
243
-
244
- class DatatypeConfig(NamedTuple):
245
- Z0Z_module: str_nameDOTname
246
- fml: ast_Identifier
247
- Z0Z_type_name: ast_Identifier
248
- Z0Z_asname: ast_Identifier | None = None
249
-
250
- listDatatypeConfigs = [
251
- DatatypeConfig(fml='DatatypeLeavesTotal', Z0Z_module='numba', Z0Z_type_name='uint8'),
252
- DatatypeConfig(fml='DatatypeElephino', Z0Z_module='numba', Z0Z_type_name='uint16'),
253
- DatatypeConfig(fml='DatatypeFoldsTotal', Z0Z_module='numba', Z0Z_type_name='uint64'),
254
- ]
255
-
256
- for datatypeConfig in listDatatypeConfigs:
257
- ingredientsModule.imports.addImportFrom_asStr(datatypeConfig.Z0Z_module, datatypeConfig.Z0Z_type_name)
258
- statement = Make.Assign(
259
- [Make.Name(datatypeConfig.fml, ast.Store())],
260
- Make.Name(datatypeConfig.Z0Z_type_name)
261
- )
262
- ingredientsModule.appendPrologue(statement=statement)
263
-
264
- ingredientsCount.imports.removeImportFromModule('mapFolding.theSSOT')
265
-
266
- listNumPyTypeConfigs = [
267
- DatatypeConfig(fml='Array1DLeavesTotal', Z0Z_module='numpy', Z0Z_type_name='uint8', Z0Z_asname='Array1DLeavesTotal'),
268
- DatatypeConfig(fml='Array1DElephino', Z0Z_module='numpy', Z0Z_type_name='uint16', Z0Z_asname='Array1DElephino'),
269
- DatatypeConfig(fml='Array3D', Z0Z_module='numpy', Z0Z_type_name='uint8', Z0Z_asname='Array3D'),
270
- ]
271
-
272
- for typeConfig in listNumPyTypeConfigs:
273
- ingredientsCount.imports.removeImportFrom(typeConfig.Z0Z_module, None, typeConfig.fml)
274
- ingredientsCount.imports.addImportFrom_asStr(typeConfig.Z0Z_module, typeConfig.Z0Z_type_name, typeConfig.Z0Z_asname)
275
-
276
- ingredientsCount.astFunctionDef.decorator_list = [] # TODO low-priority, handle this more elegantly
277
- # TODO when I add the function signature in numba style back to the decorator, the logic needs to handle `ProgressBarType:`
278
- ingredientsCount = decorateCallableWithNumba(ingredientsCount, spices.parametersNumba)
279
-
280
- ingredientsModule.appendIngredientsFunction(ingredientsCount)
281
- write_astModule(ingredientsModule, job.pathFilenameModule, job.packageIdentifier)
282
-
283
- """
284
- Overview
285
- - the code starts life in theDao.py, which has many optimizations;
286
- - `makeNumbaOptimizedFlow` increase optimization especially by using numba;
287
- - `makeJobNumba` increases optimization especially by limiting its capabilities to just one set of parameters
288
- - the synthesized module must run well as a standalone interpreted-Python script
289
- - the next major optimization step will (probably) be to use the module synthesized by `makeJobNumba` to compile a standalone executable
290
- - Nevertheless, at each major optimization step, the code is constantly being improved and optimized, so everything must be well organized (read: semantic) and able to handle a range of arbitrary upstream and not disrupt downstream transformations
291
-
292
- Necessary
293
- - Move the function's parameters to the function body,
294
- - initialize identifiers with their state types and values,
295
-
296
- Optimizations
297
- - replace static-valued identifiers with their values
298
- - narrowly focused imports
299
-
300
- Minutia
301
- - do not use `with` statement inside numba jitted code, except to use numba's obj mode
302
- """
303
-
304
- if __name__ == '__main__':
305
- mapShape = (1,46)
306
- state = makeInitializedComputationState(mapShape)
307
- # foldsTotalEstimated = getFoldsTotalKnown(state.mapShape) // state.leavesTotal
308
- # foldsTotalEstimated = dictionaryEstimates[state.mapShape] // state.leavesTotal
309
- foldsTotalEstimated = 0
310
- pathModule = PurePosixPath(The.pathPackage, 'jobs')
311
- pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
312
- aJob = RecipeJob(state, foldsTotalEstimated, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
313
- spices = SpicesJobNumba(useNumbaProgressBar=False, parametersNumba=parametersNumbaLight)
314
- # spices = SpicesJobNumba()
315
- makeJobNumba(aJob, spices)