mapFolding 0.8.3__py3-none-any.whl → 0.8.5__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.
- mapFolding/__init__.py +6 -3
- mapFolding/basecamp.py +13 -7
- mapFolding/beDRY.py +241 -68
- mapFolding/oeis.py +4 -4
- mapFolding/reference/hunterNumba.py +1 -1
- mapFolding/someAssemblyRequired/__init__.py +40 -20
- mapFolding/someAssemblyRequired/_theTypes.py +53 -0
- mapFolding/someAssemblyRequired/_tool_Make.py +99 -0
- mapFolding/someAssemblyRequired/_tool_Then.py +72 -0
- mapFolding/someAssemblyRequired/_toolboxAntecedents.py +358 -0
- mapFolding/someAssemblyRequired/_toolboxContainers.py +334 -0
- mapFolding/someAssemblyRequired/_toolboxPython.py +62 -0
- mapFolding/someAssemblyRequired/getLLVMforNoReason.py +2 -2
- mapFolding/someAssemblyRequired/newInliner.py +22 -0
- mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +158 -0
- mapFolding/someAssemblyRequired/toolboxNumba.py +358 -0
- mapFolding/someAssemblyRequired/transformationTools.py +289 -698
- mapFolding/syntheticModules/numbaCount_doTheNeedful.py +36 -33
- mapFolding/theDao.py +13 -11
- mapFolding/theSSOT.py +83 -128
- mapFolding/toolboxFilesystem.py +219 -0
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.5.dist-info}/METADATA +4 -2
- mapfolding-0.8.5.dist-info/RECORD +48 -0
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.5.dist-info}/WHEEL +1 -1
- tests/conftest.py +56 -52
- tests/test_computations.py +42 -32
- tests/test_filesystem.py +4 -4
- tests/test_other.py +2 -2
- tests/test_tasks.py +2 -2
- mapFolding/filesystem.py +0 -129
- mapFolding/someAssemblyRequired/ingredientsNumba.py +0 -206
- mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +0 -211
- mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py +0 -413
- mapFolding/someAssemblyRequired/transformDataStructures.py +0 -168
- mapfolding-0.8.3.dist-info/RECORD +0 -43
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.5.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.5.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.5.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mapFolding
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.5
|
|
4
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
|
|
@@ -35,6 +35,7 @@ Requires-Dist: more_itertools
|
|
|
35
35
|
Requires-Dist: numba_progress
|
|
36
36
|
Requires-Dist: numba
|
|
37
37
|
Requires-Dist: numpy
|
|
38
|
+
Requires-Dist: platformdirs
|
|
38
39
|
Requires-Dist: python_minifier
|
|
39
40
|
Requires-Dist: tomli
|
|
40
41
|
Requires-Dist: Z0Z_tools
|
|
@@ -45,6 +46,7 @@ Requires-Dist: pytest-cov; extra == "testing"
|
|
|
45
46
|
Requires-Dist: pytest-env; extra == "testing"
|
|
46
47
|
Requires-Dist: pytest-xdist; extra == "testing"
|
|
47
48
|
Requires-Dist: pyupgrade; extra == "testing"
|
|
49
|
+
Requires-Dist: ruff; extra == "testing"
|
|
48
50
|
Dynamic: license-file
|
|
49
51
|
|
|
50
52
|
# mapFolding: Algorithms for enumerating distinct map/stamp folding patterns 🗺️
|
|
@@ -131,7 +133,7 @@ The package provides a sophisticated transformation framework that bridges the g
|
|
|
131
133
|
- Study the functional state-transformation approach in `theDao.py` with clear, isolated functions
|
|
132
134
|
- Explore the semantic decomposition in `reference/flattened.py` to understand algorithm sections
|
|
133
135
|
|
|
134
|
-
- **Code Transformation
|
|
136
|
+
- **Code Transformation Assembly-line**:
|
|
135
137
|
- **AST Manipulation**: Analyzes and transforms the algorithm's abstract syntax tree
|
|
136
138
|
- **Dataclass "Shattering"**: Decomposes complex state objects into primitive components
|
|
137
139
|
- **Optimization Applications**: Applies domain-specific optimizations for numerical computation
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
mapFolding/__init__.py,sha256=LBgk-iW95pzqkFGY8PbcnU0oHy0AXwJGo18mM0g8wEw,2227
|
|
2
|
+
mapFolding/basecamp.py,sha256=-__EJ2to84ssS4Fm0CAuQjRnghI9VA4cXZoWGYud1r0,4782
|
|
3
|
+
mapFolding/beDRY.py,sha256=2GPO4A8XcxoEJXB_3sro4ZFQ5gcU7ywc1-c8HLEvEv0,15280
|
|
4
|
+
mapFolding/noHomeYet.py,sha256=UKZeWlyn0SKlF9dhYoud7E6gWXpiSEekZOOoJp88WeI,1362
|
|
5
|
+
mapFolding/oeis.py,sha256=EzEnbRi_4qt8Na2tiMcvL23FXpcJEkXTwuXDYDFH_XI,12631
|
|
6
|
+
mapFolding/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
mapFolding/theDao.py,sha256=MVopt1LzhdIQYA97SEoq9bdzct6hbK0lEyPxBAAlVTc,9934
|
|
8
|
+
mapFolding/theSSOT.py,sha256=i3R_G702U7VQOil61ky60JGGsSEOk_x1555rg8yI0Tc,11978
|
|
9
|
+
mapFolding/toolboxFilesystem.py,sha256=WoqRjXqTXy5GYNmbfzWtzv1uufm7vYcgT4zJ9ffhRYY,9982
|
|
10
|
+
mapFolding/reference/__init__.py,sha256=UIEU8BJR_YDzjFQcLel3XtHzOCJiOUGlGiWzOzbvhik,2206
|
|
11
|
+
mapFolding/reference/flattened.py,sha256=QK1xG9SllqCoi68e86Hyl9d9ATUAAFNpTQI-3zmcp5I,16072
|
|
12
|
+
mapFolding/reference/hunterNumba.py,sha256=iLfyqwGdAh6c5GbapnKsWhAsNsR3O-fyGGHAdohluLw,7258
|
|
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/reference/jobsCompleted/__init__.py,sha256=TU93ZGUW1xEkT6d9mQFn_rp5DvRy0ZslEB2Q6MF5ZDc,2596
|
|
20
|
+
mapFolding/reference/jobsCompleted/[2x19]/p2x19.py,sha256=_tvYtfzMWVo2VtUbIAieoscb4N8FFflgTdW4-ljBUuA,19626
|
|
21
|
+
mapFolding/reference/jobsCompleted/p2x19/p2x19.py,sha256=eZEw4Me4ocTt6VXoK2-Sbd5SowZtxRIbN9dZmc7OCVg,6395
|
|
22
|
+
mapFolding/someAssemblyRequired/__init__.py,sha256=c2GFI2HSId2_R_aoJWBID-P9AMF3zoHJzOc10XS6DHc,2669
|
|
23
|
+
mapFolding/someAssemblyRequired/_theTypes.py,sha256=SG82WTtQy83BmInlHZHY8Nh3Kp161NcEFSA6-UU5wuE,4623
|
|
24
|
+
mapFolding/someAssemblyRequired/_tool_Make.py,sha256=8ezrMDAdUY6m1raFp-G8vNXrHEr8IGfnZJ-aMVKzGf0,7092
|
|
25
|
+
mapFolding/someAssemblyRequired/_tool_Then.py,sha256=QxuoBqj4iOeKWITjV3DcV8c25fLx3Q6mhUORD7-mCzc,2758
|
|
26
|
+
mapFolding/someAssemblyRequired/_toolboxAntecedents.py,sha256=GEAuniYRj6yOtrJO_6sGZMzsVARdejts8NXhR_0np_c,21914
|
|
27
|
+
mapFolding/someAssemblyRequired/_toolboxContainers.py,sha256=iPLZbFcGB6dKtX3WkopnM-2OtMcVuxXQT46iFhzpdfY,17815
|
|
28
|
+
mapFolding/someAssemblyRequired/_toolboxPython.py,sha256=za30092eT00tj5ctqUCRrEuq5DGeJZN-vV9T4Dro-1w,3483
|
|
29
|
+
mapFolding/someAssemblyRequired/getLLVMforNoReason.py,sha256=9RPU6vK_eUg64GtVFI_nZnvUryXw8gfHJs9NyDYHIvg,2745
|
|
30
|
+
mapFolding/someAssemblyRequired/newInliner.py,sha256=Tm9PSzt66oIXPVrN9VdQwEYBba2iEOF5X3aEsOOF-FE,946
|
|
31
|
+
mapFolding/someAssemblyRequired/synthesizeNumbaJob.py,sha256=0L5ccqBusof6MzKatKnpUmFUNkAtbapzl_Fxmofi4DE,8684
|
|
32
|
+
mapFolding/someAssemblyRequired/toolboxNumba.py,sha256=rluEmsSJOQCl2L6LlJzIc3AfeRxU6cp-sCf-rQFW-og,22613
|
|
33
|
+
mapFolding/someAssemblyRequired/transformationTools.py,sha256=iIvRxSL45qTyl0d0ztHa9BP1MrOikfXE4HBqLlNMENc,20081
|
|
34
|
+
mapFolding/syntheticModules/__init__.py,sha256=evVFqhCGa-WZKDiLcnQWjs-Bj34eRnfSLqz_d7dFYZY,83
|
|
35
|
+
mapFolding/syntheticModules/numbaCount_doTheNeedful.py,sha256=3thXThbv2Xo0t_cRGzMbHPFXTBmLClmKejR_Ibu_jOo,15697
|
|
36
|
+
mapfolding-0.8.5.dist-info/licenses/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
|
|
37
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
+
tests/conftest.py,sha256=LfogHLu7PULSECwhLQgGCgqSvDMBc5b9RGWBls3YBrM,11364
|
|
39
|
+
tests/test_computations.py,sha256=XjCej6M6lesfKB_ulWq3O-ryXBsJuuwnJ6_XjKOvgDY,3552
|
|
40
|
+
tests/test_filesystem.py,sha256=YEHNU6tUCTj9C65cKs3ETgt3OZTGVnNjxgu4aH6C9uU,3164
|
|
41
|
+
tests/test_oeis.py,sha256=uxvwmgbnylSDdsVJfuAT0LuYLbIVFwSgdLxHm-xUGBM,5043
|
|
42
|
+
tests/test_other.py,sha256=O05PFAK70Skf-k99Wcg4ASLpMpBH-WkELtk6MnynDx0,4293
|
|
43
|
+
tests/test_tasks.py,sha256=S-6PNfM__Npw0zVojgzn5M-6ODBKDyRH5ccMTqQF9C4,2865
|
|
44
|
+
mapfolding-0.8.5.dist-info/METADATA,sha256=vrusTb9uu8FQ3UksfFkVZ3txtYPNufYa3db-Rk6H1y0,9359
|
|
45
|
+
mapfolding-0.8.5.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
46
|
+
mapfolding-0.8.5.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
|
|
47
|
+
mapfolding-0.8.5.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
|
|
48
|
+
mapfolding-0.8.5.dist-info/RECORD,,
|
tests/conftest.py
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
from importlib import import_module as importlib_import_module
|
|
2
1
|
from collections.abc import Callable, Generator, Sequence
|
|
3
|
-
from types import ModuleType
|
|
4
|
-
|
|
5
|
-
import numpy
|
|
6
|
-
from mapFolding.theSSOT import ComputationState, The, getPackageDispatcher
|
|
7
2
|
from mapFolding.beDRY import getLeavesTotal, validateListDimensions, makeDataContainer
|
|
8
3
|
from mapFolding.oeis import oeisIDsImplemented, settingsOEIS
|
|
9
|
-
from mapFolding.someAssemblyRequired import RecipeSynthesizeFlow
|
|
10
|
-
from mapFolding.
|
|
4
|
+
from mapFolding.someAssemblyRequired import importLogicalPath2Callable, RecipeSynthesizeFlow
|
|
5
|
+
from mapFolding.theSSOT import ComputationState, The, getPackageDispatcher
|
|
11
6
|
from pathlib import Path, PurePosixPath
|
|
12
|
-
from
|
|
7
|
+
from types import ModuleType
|
|
8
|
+
from typing import Any
|
|
9
|
+
import importlib
|
|
13
10
|
import importlib.util
|
|
11
|
+
import numpy
|
|
14
12
|
import pytest
|
|
15
13
|
import random
|
|
16
14
|
import shutil
|
|
@@ -18,8 +16,9 @@ import unittest.mock
|
|
|
18
16
|
import uuid
|
|
19
17
|
|
|
20
18
|
# SSOT for test data paths and filenames
|
|
21
|
-
pathDataSamples = Path("tests/dataSamples")
|
|
19
|
+
pathDataSamples = Path("tests/dataSamples").absolute()
|
|
22
20
|
pathTmpRoot: Path = pathDataSamples / "tmp"
|
|
21
|
+
pathTmpRoot.mkdir(parents=True, exist_ok=True)
|
|
23
22
|
|
|
24
23
|
# The registrar maintains the register of temp files
|
|
25
24
|
registerOfTemporaryFilesystemObjects: set[Path] = set()
|
|
@@ -100,7 +99,22 @@ def setupWarningsAsErrors() -> Generator[None, Any, None]:
|
|
|
100
99
|
warnings.resetwarnings()
|
|
101
100
|
|
|
102
101
|
@pytest.fixture
|
|
103
|
-
def
|
|
102
|
+
def oneTestCuzTestsOverwritingTests(oeisID_1random: str) -> tuple[int, ...]:
|
|
103
|
+
"""For each `oeisID_1random` from the `pytest.fixture`, returns `listDimensions` from `valuesTestValidation`
|
|
104
|
+
if `validateListDimensions` approves. Each `listDimensions` is suitable for testing counts."""
|
|
105
|
+
while True:
|
|
106
|
+
n = random.choice(settingsOEIS[oeisID_1random]['valuesTestValidation'])
|
|
107
|
+
if n < 2:
|
|
108
|
+
continue
|
|
109
|
+
listDimensionsCandidate = list(settingsOEIS[oeisID_1random]['getMapShape'](n))
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
return validateListDimensions(listDimensionsCandidate)
|
|
113
|
+
except (ValueError, NotImplementedError):
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
@pytest.fixture
|
|
117
|
+
def listDimensionsTestCountFolds(oeisID: str) -> tuple[int, ...]:
|
|
104
118
|
"""For each `oeisID` from the `pytest.fixture`, returns `listDimensions` from `valuesTestValidation`
|
|
105
119
|
if `validateListDimensions` approves. Each `listDimensions` is suitable for testing counts."""
|
|
106
120
|
while True:
|
|
@@ -115,7 +129,7 @@ def listDimensionsTestCountFolds(oeisID: str):
|
|
|
115
129
|
pass
|
|
116
130
|
|
|
117
131
|
@pytest.fixture
|
|
118
|
-
def mapShapeTestFunctionality(oeisID_1random: str):
|
|
132
|
+
def mapShapeTestFunctionality(oeisID_1random: str) -> tuple[int, ...]:
|
|
119
133
|
"""To test functionality, get one `listDimensions` from `valuesTestValidation` if
|
|
120
134
|
`validateListDimensions` approves. The algorithm can count the folds of the returned
|
|
121
135
|
`listDimensions` in a short enough time suitable for testing."""
|
|
@@ -159,17 +173,6 @@ def mockFoldingFunction() -> Callable[..., Callable[..., None]]:
|
|
|
159
173
|
return mock_countFolds
|
|
160
174
|
return make_mock
|
|
161
175
|
|
|
162
|
-
@pytest.fixture
|
|
163
|
-
def mockDispatcher() -> Callable[[Any], ContextManager[Any]]:
|
|
164
|
-
"""Context manager for mocking dispatcher callable."""
|
|
165
|
-
def wrapper(mockFunction: Any) -> ContextManager[Any]:
|
|
166
|
-
dispatcherCallable = getPackageDispatcher()
|
|
167
|
-
return unittest.mock.patch(
|
|
168
|
-
f"{dispatcherCallable.__module__}.{dispatcherCallable.__name__}",
|
|
169
|
-
side_effect=mockFunction
|
|
170
|
-
)
|
|
171
|
-
return wrapper
|
|
172
|
-
|
|
173
176
|
@pytest.fixture(params=oeisIDsImplemented)
|
|
174
177
|
def oeisID(request: pytest.FixtureRequest) -> Any:
|
|
175
178
|
return request.param
|
|
@@ -198,46 +201,47 @@ def useThisDispatcher() -> Generator[Callable[..., None], Any, None]:
|
|
|
198
201
|
basecamp.getPackageDispatcher = dispatcherOriginal
|
|
199
202
|
|
|
200
203
|
def getAlgorithmDispatcher() -> Callable[[ComputationState], ComputationState]:
|
|
201
|
-
moduleImported: ModuleType =
|
|
202
|
-
dispatcherCallable = getattr(moduleImported, The.
|
|
204
|
+
moduleImported: ModuleType = importlib.import_module(The.logicalPathModuleSourceAlgorithm)
|
|
205
|
+
dispatcherCallable = getattr(moduleImported, The.sourceCallableDispatcher)
|
|
203
206
|
return dispatcherCallable
|
|
204
207
|
|
|
205
208
|
@pytest.fixture
|
|
206
209
|
def useAlgorithmSourceDispatcher(useThisDispatcher: Callable[..., Any]) -> Generator[None, None, None]:
|
|
207
210
|
"""Temporarily patches getDispatcherCallable to return the algorithm dispatcher."""
|
|
208
|
-
useThisDispatcher(
|
|
211
|
+
useThisDispatcher(importLogicalPath2Callable(The.logicalPathModuleSourceAlgorithm, The.sourceCallableDispatcher))
|
|
209
212
|
yield
|
|
210
213
|
|
|
211
214
|
@pytest.fixture
|
|
212
215
|
def syntheticDispatcherFixture(useThisDispatcher: Callable[..., Any], pathTmpTesting: Path) -> Callable[..., Any]:
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
"""Generate synthetic Numba-optimized dispatcher module and patch the dispatcher"""
|
|
217
|
+
from mapFolding.someAssemblyRequired.toolboxNumba import makeNumbaFlow
|
|
218
|
+
|
|
219
|
+
TESTINGrecipeFlow = RecipeSynthesizeFlow(
|
|
220
|
+
pathPackage=PurePosixPath(pathTmpTesting.absolute()),
|
|
221
|
+
logicalPathFlowRoot=None,
|
|
222
|
+
moduleDispatcher="test_dispatcher",
|
|
219
223
|
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
224
|
+
# dispatcherCallable="dispatcherSynthetic",
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Generate optimized module in test directory
|
|
228
|
+
makeNumbaFlow(TESTINGrecipeFlow)
|
|
229
|
+
|
|
230
|
+
# Import synthesized dispatcher
|
|
231
|
+
importlibSpecificationDispatcher = importlib.util.spec_from_file_location(
|
|
232
|
+
TESTINGrecipeFlow.moduleDispatcher,
|
|
233
|
+
Path(TESTINGrecipeFlow.pathFilenameDispatcher),
|
|
234
|
+
)
|
|
235
|
+
if importlibSpecificationDispatcher is None or importlibSpecificationDispatcher.loader is None:
|
|
236
|
+
raise ImportError("Failed to load synthetic dispatcher module")
|
|
237
|
+
|
|
238
|
+
moduleSpecificationDispatcher = importlib.util.module_from_spec(importlibSpecificationDispatcher)
|
|
239
|
+
importlibSpecificationDispatcher.loader.exec_module(moduleSpecificationDispatcher)
|
|
240
|
+
callableDispatcherSynthetic = getattr(moduleSpecificationDispatcher, TESTINGrecipeFlow.callableDispatcher)
|
|
241
|
+
|
|
242
|
+
# Patch dispatcher and return callable
|
|
243
|
+
useThisDispatcher(callableDispatcherSynthetic)
|
|
244
|
+
return callableDispatcherSynthetic
|
|
241
245
|
|
|
242
246
|
def uniformTestMessage(expected: Any, actual: Any, functionName: str, *arguments: Any) -> str:
|
|
243
247
|
"""Format assertion message for any test comparison."""
|
tests/test_computations.py
CHANGED
|
@@ -1,53 +1,63 @@
|
|
|
1
1
|
from mapFolding.basecamp import countFolds
|
|
2
|
-
from mapFolding.
|
|
2
|
+
from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal
|
|
3
|
+
from mapFolding.beDRY import validateListDimensions
|
|
3
4
|
from mapFolding.noHomeYet import getFoldsTotalKnown
|
|
4
5
|
from mapFolding.oeis import settingsOEIS, oeisIDfor_n
|
|
5
|
-
|
|
6
|
-
from pathlib import Path
|
|
6
|
+
from mapFolding.someAssemblyRequired.transformationTools import makeInitializedComputationState
|
|
7
|
+
from pathlib import Path, PurePosixPath
|
|
7
8
|
from tests.conftest import standardizedEqualToCallableReturn, registrarRecordsTmpObject
|
|
8
9
|
from types import ModuleType
|
|
9
10
|
import importlib.util
|
|
10
11
|
import multiprocessing
|
|
12
|
+
import threading
|
|
13
|
+
from copy import deepcopy
|
|
11
14
|
import pytest
|
|
12
15
|
|
|
13
16
|
if __name__ == '__main__':
|
|
14
17
|
multiprocessing.set_start_method('spawn')
|
|
15
18
|
|
|
16
19
|
def test_algorithmSourceParallel(listDimensionsTestParallelization: list[int], useAlgorithmSourceDispatcher: None) -> None:
|
|
17
|
-
|
|
20
|
+
standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestParallelization)), countFolds, listDimensionsTestParallelization, None, 'maximum', None)
|
|
18
21
|
|
|
19
22
|
def test_algorithmSourceSequential(listDimensionsTestCountFolds: tuple[int, ...], useAlgorithmSourceDispatcher: None) -> None:
|
|
20
|
-
|
|
23
|
+
standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestCountFolds)), countFolds, listDimensionsTestCountFolds)
|
|
21
24
|
|
|
22
25
|
def test_aOFn_calculate_value(oeisID: str) -> None:
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
for n in settingsOEIS[oeisID]['valuesTestValidation']:
|
|
27
|
+
standardizedEqualToCallableReturn(settingsOEIS[oeisID]['valuesKnown'][n], oeisIDfor_n, oeisID, n)
|
|
25
28
|
|
|
26
29
|
def test_syntheticParallel(syntheticDispatcherFixture: None, listDimensionsTestParallelization: list[int]):
|
|
27
|
-
|
|
30
|
+
standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestParallelization)), countFolds, listDimensionsTestParallelization, None, 'maximum')
|
|
28
31
|
|
|
29
32
|
def test_syntheticSequential(syntheticDispatcherFixture: None, listDimensionsTestCountFolds: list[int]) -> None:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
33
|
+
standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestCountFolds)), countFolds, listDimensionsTestCountFolds)
|
|
34
|
+
|
|
35
|
+
@pytest.mark.parametrize('pathFilenameTmpTesting', ['.py'], indirect=True)
|
|
36
|
+
def test_writeJobNumba(oneTestCuzTestsOverwritingTests: list[int], pathFilenameTmpTesting: Path) -> None:
|
|
37
|
+
from mapFolding.someAssemblyRequired.toolboxNumba import RecipeJob, SpicesJobNumba
|
|
38
|
+
from mapFolding.someAssemblyRequired.synthesizeNumbaJob import makeJobNumba
|
|
39
|
+
mapShape = validateListDimensions(oneTestCuzTestsOverwritingTests)
|
|
40
|
+
state = makeInitializedComputationState(mapShape)
|
|
41
|
+
|
|
42
|
+
pathFilenameModule = pathFilenameTmpTesting.absolute()
|
|
43
|
+
pathFilenameFoldsTotal = pathFilenameModule.with_suffix('.foldsTotalTesting')
|
|
44
|
+
registrarRecordsTmpObject(pathFilenameFoldsTotal)
|
|
45
|
+
|
|
46
|
+
jobTest = RecipeJob(state
|
|
47
|
+
, pathModule=PurePosixPath(pathFilenameModule.parent)
|
|
48
|
+
, moduleIdentifier=pathFilenameModule.stem
|
|
49
|
+
, pathFilenameFoldsTotal=PurePosixPath(pathFilenameFoldsTotal))
|
|
50
|
+
spices = SpicesJobNumba()
|
|
51
|
+
makeJobNumba(jobTest, spices)
|
|
52
|
+
|
|
53
|
+
Don_Lapre_Road_to_Self_Improvement = importlib.util.spec_from_file_location("__main__", pathFilenameModule)
|
|
54
|
+
if Don_Lapre_Road_to_Self_Improvement is None:
|
|
55
|
+
raise ImportError(f"Failed to create module specification from {pathFilenameModule}")
|
|
56
|
+
if Don_Lapre_Road_to_Self_Improvement.loader is None:
|
|
57
|
+
raise ImportError(f"Failed to get loader for module {pathFilenameModule}")
|
|
58
|
+
module = importlib.util.module_from_spec(Don_Lapre_Road_to_Self_Improvement)
|
|
59
|
+
|
|
60
|
+
module.__name__ = "__main__"
|
|
61
|
+
Don_Lapre_Road_to_Self_Improvement.loader.exec_module(module)
|
|
62
|
+
|
|
63
|
+
standardizedEqualToCallableReturn(str(getFoldsTotalKnown(mapShape)), pathFilenameFoldsTotal.read_text().strip)
|
tests/test_filesystem.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from contextlib import redirect_stdout
|
|
2
|
-
from mapFolding.
|
|
2
|
+
from mapFolding.toolboxFilesystem import getFilenameFoldsTotal, getPathFilenameFoldsTotal, saveFoldsTotal
|
|
3
3
|
from mapFolding.beDRY import validateListDimensions
|
|
4
|
-
from mapFolding.
|
|
4
|
+
from mapFolding.toolboxFilesystem import getPathRootJobDEFAULT
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
import io
|
|
7
7
|
import pytest
|
|
@@ -33,14 +33,14 @@ def test_getPathFilenameFoldsTotal_defaultPath(mapShapeTestFunctionality: tuple[
|
|
|
33
33
|
pathFilenameFoldsTotal = getPathFilenameFoldsTotal(mapShapeTestFunctionality)
|
|
34
34
|
assert pathFilenameFoldsTotal.is_absolute(), "Path should be absolute"
|
|
35
35
|
assert pathFilenameFoldsTotal.name == getFilenameFoldsTotal(mapShapeTestFunctionality), "Filename should match getFilenameFoldsTotal output"
|
|
36
|
-
assert pathFilenameFoldsTotal.parent ==
|
|
36
|
+
assert pathFilenameFoldsTotal.parent == getPathRootJobDEFAULT(), "Parent directory should match default job root"
|
|
37
37
|
|
|
38
38
|
def test_getPathFilenameFoldsTotal_relativeFilename(mapShapeTestFunctionality: tuple[int, ...]) -> None:
|
|
39
39
|
"""Test getPathFilenameFoldsTotal with relative filename."""
|
|
40
40
|
relativeFilename = Path("custom/path/test.foldsTotal")
|
|
41
41
|
pathFilenameFoldsTotal = getPathFilenameFoldsTotal(mapShapeTestFunctionality, relativeFilename)
|
|
42
42
|
assert pathFilenameFoldsTotal.is_absolute(), "Path should be absolute"
|
|
43
|
-
assert pathFilenameFoldsTotal ==
|
|
43
|
+
assert pathFilenameFoldsTotal == getPathRootJobDEFAULT() / relativeFilename, "Relative path should be appended to default job root"
|
|
44
44
|
|
|
45
45
|
def test_getPathFilenameFoldsTotal_createsDirs(pathTmpTesting: Path, mapShapeTestFunctionality: tuple[int, ...]) -> None:
|
|
46
46
|
"""Test that getPathFilenameFoldsTotal creates necessary directories."""
|
tests/test_other.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from collections.abc import Callable
|
|
2
|
-
from mapFolding.beDRY import getLeavesTotal,
|
|
2
|
+
from mapFolding.beDRY import getLeavesTotal, setProcessorLimit, validateListDimensions
|
|
3
3
|
from mapFolding.theSSOT import The
|
|
4
4
|
from tests.conftest import standardizedEqualToCallableReturn
|
|
5
5
|
from typing import Any, Literal
|
|
@@ -81,4 +81,4 @@ def testOopsieKwargsie(nameOfTest: str, callablePytest: Callable[[], None]) -> N
|
|
|
81
81
|
])
|
|
82
82
|
def test_setCPUlimitNumba(CPUlimit: None | float | bool | Literal[4] | Literal[-2] | Literal[0] | Literal[1], expectedLimit: Any | int) -> None:
|
|
83
83
|
numba.set_num_threads(multiprocessing.cpu_count())
|
|
84
|
-
standardizedEqualToCallableReturn(expectedLimit,
|
|
84
|
+
standardizedEqualToCallableReturn(expectedLimit, setProcessorLimit, CPUlimit, 'numba')
|
tests/test_tasks.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from collections.abc import Callable
|
|
2
2
|
from mapFolding.basecamp import countFolds
|
|
3
|
-
from mapFolding.beDRY import getTaskDivisions,
|
|
3
|
+
from mapFolding.beDRY import getTaskDivisions, setProcessorLimit, validateListDimensions, getLeavesTotal
|
|
4
4
|
from mapFolding.noHomeYet import getFoldsTotalKnown
|
|
5
5
|
from tests.conftest import standardizedEqualToCallableReturn
|
|
6
6
|
from typing import Literal
|
|
@@ -49,4 +49,4 @@ def test_getTaskDivisions(computationDivisions: None | list[str] | Literal['maxi
|
|
|
49
49
|
])
|
|
50
50
|
def test_setCPUlimitMalformedParameter(expected: type[ValueError] | Literal[2], parameter: list[int] | tuple[int] | set[int] | dict[str, int] | Literal['2']) -> None:
|
|
51
51
|
"""Test that invalid CPUlimit types are properly handled."""
|
|
52
|
-
standardizedEqualToCallableReturn(expected,
|
|
52
|
+
standardizedEqualToCallableReturn(expected, setProcessorLimit, parameter)
|
mapFolding/filesystem.py
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Filesystem utilities for managing map folding computation results.
|
|
3
|
-
|
|
4
|
-
This module provides functions for standardized handling of files related to the mapFolding
|
|
5
|
-
package, with a focus on saving, retrieving, and naming computation results. It implements
|
|
6
|
-
consistent naming conventions and path resolution strategies to ensure that:
|
|
7
|
-
|
|
8
|
-
1. Computation results are stored in a predictable location
|
|
9
|
-
2. Filenames follow a consistent pattern based on map dimensions
|
|
10
|
-
3. Results can be reliably retrieved for future reference
|
|
11
|
-
4. The system handles file operations safely with appropriate error handling
|
|
12
|
-
|
|
13
|
-
The module serves as the interface between the computational components of the package
|
|
14
|
-
and the filesystem, abstracting away the details of file operations and path management.
|
|
15
|
-
"""
|
|
16
|
-
from pathlib import Path, PurePath
|
|
17
|
-
from typing import Any
|
|
18
|
-
from os import PathLike
|
|
19
|
-
import os
|
|
20
|
-
|
|
21
|
-
def getFilenameFoldsTotal(mapShape: tuple[int, ...]) -> str:
|
|
22
|
-
"""
|
|
23
|
-
Create a standardized filename for a computed `foldsTotal` value.
|
|
24
|
-
|
|
25
|
-
This function generates a consistent, filesystem-safe filename based on map dimensions.
|
|
26
|
-
Standardizing filenames ensures that results can be reliably stored and retrieved,
|
|
27
|
-
avoiding potential filesystem incompatibilities or Python naming restrictions.
|
|
28
|
-
|
|
29
|
-
Parameters:
|
|
30
|
-
mapShape: A sequence of integers representing the dimensions of the map.
|
|
31
|
-
|
|
32
|
-
Returns:
|
|
33
|
-
filenameFoldsTotal: A filename string in format 'pMxN.foldsTotal' where M,N are sorted dimensions.
|
|
34
|
-
|
|
35
|
-
Notes:
|
|
36
|
-
The filename format ensures:
|
|
37
|
-
- No spaces in the filename
|
|
38
|
-
- Safe filesystem characters
|
|
39
|
-
- Unique extension (.foldsTotal)
|
|
40
|
-
- Python-safe strings (no starting with numbers, no reserved words)
|
|
41
|
-
- The 'p' prefix preserves compatibility with Lunnan's original code.
|
|
42
|
-
"""
|
|
43
|
-
return 'p' + 'x'.join(str(dimension) for dimension in sorted(mapShape)) + '.foldsTotal'
|
|
44
|
-
|
|
45
|
-
def getPathFilenameFoldsTotal(mapShape: tuple[int, ...], pathLikeWriteFoldsTotal: str | PathLike[str] | None = None) -> Path:
|
|
46
|
-
"""
|
|
47
|
-
Get a standardized path and filename for the computed foldsTotal value.
|
|
48
|
-
|
|
49
|
-
This function resolves paths for storing computation results, handling different
|
|
50
|
-
input types including directories, absolute paths, or relative paths. It ensures
|
|
51
|
-
that all parent directories exist in the resulting path.
|
|
52
|
-
|
|
53
|
-
Parameters:
|
|
54
|
-
mapShape: List of dimensions for the map folding problem.
|
|
55
|
-
pathLikeWriteFoldsTotal (getPathJobRootDEFAULT): Path, filename, or relative path and filename.
|
|
56
|
-
If None, uses default path. If a directory, appends standardized filename.
|
|
57
|
-
|
|
58
|
-
Returns:
|
|
59
|
-
pathFilenameFoldsTotal: Absolute path and filename for storing the foldsTotal value.
|
|
60
|
-
|
|
61
|
-
Notes:
|
|
62
|
-
The function creates any necessary directories in the path if they don't exist.
|
|
63
|
-
"""
|
|
64
|
-
from mapFolding.theSSOT import getPathJobRootDEFAULT
|
|
65
|
-
|
|
66
|
-
if pathLikeWriteFoldsTotal is None:
|
|
67
|
-
pathFilenameFoldsTotal = getPathJobRootDEFAULT() / getFilenameFoldsTotal(mapShape)
|
|
68
|
-
else:
|
|
69
|
-
pathLikeSherpa = Path(pathLikeWriteFoldsTotal)
|
|
70
|
-
if pathLikeSherpa.is_dir():
|
|
71
|
-
pathFilenameFoldsTotal = pathLikeSherpa / getFilenameFoldsTotal(mapShape)
|
|
72
|
-
elif pathLikeSherpa.is_file() and pathLikeSherpa.is_absolute():
|
|
73
|
-
pathFilenameFoldsTotal = pathLikeSherpa
|
|
74
|
-
else:
|
|
75
|
-
pathFilenameFoldsTotal = getPathJobRootDEFAULT() / pathLikeSherpa
|
|
76
|
-
|
|
77
|
-
pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
|
|
78
|
-
return pathFilenameFoldsTotal
|
|
79
|
-
|
|
80
|
-
def saveFoldsTotal(pathFilename: str | PathLike[str], foldsTotal: int) -> None:
|
|
81
|
-
"""
|
|
82
|
-
Save `foldsTotal` value to disk with multiple fallback mechanisms.
|
|
83
|
-
|
|
84
|
-
This function attempts to save the computed `foldsTotal` value to the specified
|
|
85
|
-
location, with backup strategies in case the primary save attempt fails.
|
|
86
|
-
The robustness is critical since these computations may take days to complete.
|
|
87
|
-
|
|
88
|
-
Parameters:
|
|
89
|
-
pathFilename: Target save location for the `foldsTotal` value
|
|
90
|
-
foldsTotal: The computed value to save
|
|
91
|
-
|
|
92
|
-
Notes:
|
|
93
|
-
If the primary save fails, the function will attempt alternative save methods:
|
|
94
|
-
1. Print the value prominently to stdout
|
|
95
|
-
2. Create a fallback file in the current working directory
|
|
96
|
-
3. As a last resort, simply print the value
|
|
97
|
-
"""
|
|
98
|
-
try:
|
|
99
|
-
pathFilenameFoldsTotal = Path(pathFilename)
|
|
100
|
-
pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
|
|
101
|
-
pathFilenameFoldsTotal.write_text(str(foldsTotal))
|
|
102
|
-
except Exception as ERRORmessage:
|
|
103
|
-
try:
|
|
104
|
-
print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
|
|
105
|
-
print(ERRORmessage)
|
|
106
|
-
print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
|
|
107
|
-
randomnessPlanB = (int(str(foldsTotal).strip()[-1]) + 1) * ['YO_']
|
|
108
|
-
filenameInfixUnique = ''.join(randomnessPlanB)
|
|
109
|
-
pathFilenamePlanB = os.path.join(os.getcwd(), 'foldsTotal' + filenameInfixUnique + '.txt')
|
|
110
|
-
writeStreamFallback = open(pathFilenamePlanB, 'w')
|
|
111
|
-
writeStreamFallback.write(str(foldsTotal))
|
|
112
|
-
writeStreamFallback.close()
|
|
113
|
-
print(str(pathFilenamePlanB))
|
|
114
|
-
except Exception:
|
|
115
|
-
print(foldsTotal)
|
|
116
|
-
return None
|
|
117
|
-
|
|
118
|
-
def writeStringToHere(this: str, pathFilename: str | PathLike[Any] | PurePath) -> None:
|
|
119
|
-
"""
|
|
120
|
-
Write a string to a file, creating parent directories if needed.
|
|
121
|
-
|
|
122
|
-
Parameters:
|
|
123
|
-
this: The string content to write to the file
|
|
124
|
-
pathFilename: The target file path where the string should be written
|
|
125
|
-
"""
|
|
126
|
-
pathFilename = Path(pathFilename)
|
|
127
|
-
pathFilename.parent.mkdir(parents=True, exist_ok=True)
|
|
128
|
-
pathFilename.write_text(str(this))
|
|
129
|
-
return None
|