mapFolding 0.9.0__tar.gz → 0.9.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. {mapfolding-0.9.0 → mapfolding-0.9.1}/PKG-INFO +1 -1
  2. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/beDRY.py +1 -2
  3. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/oeis.py +20 -14
  4. mapfolding-0.9.1/mapFolding/someAssemblyRequired/RecipeJob.py +103 -0
  5. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/someAssemblyRequired/__init__.py +29 -29
  6. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/someAssemblyRequired/_tool_Make.py +1 -1
  7. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/someAssemblyRequired/_toolboxAntecedents.py +12 -0
  8. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/someAssemblyRequired/_toolboxContainers.py +27 -27
  9. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/someAssemblyRequired/_toolboxPython.py +3 -0
  10. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +58 -26
  11. mapfolding-0.9.1/mapFolding/someAssemblyRequired/toolboxNumba.py +206 -0
  12. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/someAssemblyRequired/transformationTools.py +154 -7
  13. mapfolding-0.9.0/mapFolding/syntheticModules/numbaCount_doTheNeedful.py → mapfolding-0.9.1/mapFolding/syntheticModules/numbaCount.py +7 -4
  14. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/theDao.py +19 -16
  15. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/theSSOT.py +19 -9
  16. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding.egg-info/PKG-INFO +1 -1
  17. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding.egg-info/SOURCES.txt +2 -1
  18. {mapfolding-0.9.0 → mapfolding-0.9.1}/pyproject.toml +1 -1
  19. {mapfolding-0.9.0 → mapfolding-0.9.1}/tests/test_computations.py +2 -1
  20. mapfolding-0.9.0/mapFolding/someAssemblyRequired/toolboxNumba.py +0 -399
  21. {mapfolding-0.9.0 → mapfolding-0.9.1}/LICENSE +0 -0
  22. {mapfolding-0.9.0 → mapfolding-0.9.1}/README.md +0 -0
  23. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/__init__.py +0 -0
  24. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/basecamp.py +0 -0
  25. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/py.typed +0 -0
  26. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/__init__.py +0 -0
  27. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/flattened.py +0 -0
  28. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/hunterNumba.py +0 -0
  29. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/irvineJavaPort.py +0 -0
  30. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/jaxCount.py +0 -0
  31. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/jobsCompleted/[2x19]/p2x19.py +0 -0
  32. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/jobsCompleted/__init__.py +0 -0
  33. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/jobsCompleted/p2x19/p2x19.py +0 -0
  34. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/lunnanNumpy.py +0 -0
  35. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/lunnanWhile.py +0 -0
  36. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/rotatedEntryPoint.py +0 -0
  37. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/reference/total_countPlus1vsPlusN.py +0 -0
  38. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/someAssemblyRequired/_theTypes.py +0 -0
  39. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/someAssemblyRequired/_tool_Then.py +0 -0
  40. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/someAssemblyRequired/getLLVMforNoReason.py +0 -0
  41. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/syntheticModules/__init__.py +0 -0
  42. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding/toolboxFilesystem.py +0 -0
  43. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding.egg-info/dependency_links.txt +0 -0
  44. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding.egg-info/entry_points.txt +0 -0
  45. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding.egg-info/requires.txt +0 -0
  46. {mapfolding-0.9.0 → mapfolding-0.9.1}/mapFolding.egg-info/top_level.txt +0 -0
  47. {mapfolding-0.9.0 → mapfolding-0.9.1}/setup.cfg +0 -0
  48. {mapfolding-0.9.0 → mapfolding-0.9.1}/tests/__init__.py +0 -0
  49. {mapfolding-0.9.0 → mapfolding-0.9.1}/tests/conftest.py +0 -0
  50. {mapfolding-0.9.0 → mapfolding-0.9.1}/tests/test_filesystem.py +0 -0
  51. {mapfolding-0.9.0 → mapfolding-0.9.1}/tests/test_oeis.py +0 -0
  52. {mapfolding-0.9.0 → mapfolding-0.9.1}/tests/test_other.py +0 -0
  53. {mapfolding-0.9.0 → mapfolding-0.9.1}/tests/test_tasks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapFolding
3
- Version: 0.9.0
3
+ Version: 0.9.1
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
@@ -331,8 +331,7 @@ def validateListDimensions(listDimensions: Sequence[int]) -> tuple[int, ...]:
331
331
  ValueError
332
332
  If the input is empty or contains negative values.
333
333
  NotImplementedError
334
- If fewer than two positive dimensions are provided, as this would not
335
- represent a valid map folding problem.
334
+ If fewer than two positive dimensions are provided.
336
335
  """
337
336
  if not listDimensions:
338
337
  raise ValueError("`listDimensions` is a required parameter.")
@@ -59,14 +59,20 @@ class SettingsOEIShardcodedValues(TypedDict):
59
59
  valuesTestValidation: list[int]
60
60
 
61
61
  settingsOEIShardcodedValues: dict[str, SettingsOEIShardcodedValues] = {
62
+ 'A000136': {
63
+ 'getMapShape': lambda n: tuple(sorted([1, n])),
64
+ 'valuesBenchmark': [14],
65
+ 'valuesTestParallelization': [*range(3, 7)],
66
+ 'valuesTestValidation': [random.randint(2, 9)],
67
+ },
62
68
  'A001415': {
63
- 'getMapShape': lambda n: (2, n) if n >= 2 else (n, 2),
69
+ 'getMapShape': lambda n: tuple(sorted([2, n])),
64
70
  'valuesBenchmark': [14],
65
71
  'valuesTestParallelization': [*range(3, 7)],
66
72
  'valuesTestValidation': [random.randint(2, 9)],
67
73
  },
68
74
  'A001416': {
69
- 'getMapShape': lambda n: (3, n) if n >= 3 else (n, 3),
75
+ 'getMapShape': lambda n: tuple(sorted([3, n])),
70
76
  'valuesBenchmark': [9],
71
77
  'valuesTestParallelization': [*range(3, 5)],
72
78
  'valuesTestValidation': [random.randint(2, 6)],
@@ -148,9 +154,9 @@ def _parseBFileOEIS(OEISbFile: str, oeisID: str) -> dict[int, int]:
148
154
  sequence ID or if the content format is invalid.
149
155
  """
150
156
  bFileLines: list[str] = OEISbFile.strip().splitlines()
151
- if not bFileLines.pop(0).startswith(f"# {oeisID}"):
152
- warnings.warn(f"Content does not match sequence {oeisID}")
153
- return {-1: -1}
157
+ # if not bFileLines.pop(0).startswith(f"# {oeisID}"):
158
+ # warnings.warn(f"Content does not match sequence {oeisID}")
159
+ # return {-1: -1}
154
160
 
155
161
  OEISsequence: dict[int, int] = {}
156
162
  for line in bFileLines:
@@ -287,20 +293,20 @@ def getOEISidInformation(oeisID: str) -> tuple[str, int]:
287
293
  def makeSettingsOEIS() -> dict[str, SettingsOEIS]:
288
294
  """
289
295
  Construct the comprehensive settings dictionary for all implemented OEIS sequences.
290
-
291
- This function builds a complete configuration dictionary for all supported OEIS
296
+
297
+ This function builds a complete configuration dictionary for all supported OEIS
292
298
  sequences by retrieving and combining:
293
299
  1. Sequence values from OEIS b-files
294
300
  2. Sequence metadata (descriptions and offsets)
295
301
  3. Hardcoded mapping functions and test values
296
-
297
- The resulting dictionary provides a single authoritative source for all OEIS-related
302
+
303
+ The resulting dictionary provides a single authoritative source for all OEIS-related
298
304
  configurations used throughout the package, including:
299
305
  - Mathematical descriptions of each sequence
300
306
  - Functions to convert between sequence indices and map dimensions
301
307
  - Known sequence values retrieved from OEIS
302
308
  - Testing and benchmarking reference values
303
-
309
+
304
310
  Returns:
305
311
  A dictionary mapping OEIS sequence IDs to their complete settings objects,
306
312
  containing all metadata and known values needed for computation and validation.
@@ -341,18 +347,18 @@ def makeDictionaryFoldsTotalKnown() -> dict[tuple[int, ...], int]:
341
347
  def getFoldsTotalKnown(mapShape: tuple[int, ...]) -> int:
342
348
  """
343
349
  Retrieve the known total number of foldings for a given map shape.
344
-
350
+
345
351
  This function looks up precalculated folding totals for specific map dimensions
346
352
  from OEIS sequences. It serves as a rapid reference for known values without
347
353
  requiring computation, and can be used to validate algorithm results.
348
-
354
+
349
355
  Parameters:
350
356
  mapShape: A tuple of integers representing the dimensions of the map.
351
-
357
+
352
358
  Returns:
353
359
  foldingsTotal: The known total number of foldings for the given map shape,
354
360
  or -1 if the map shape doesn't match any known values in the OEIS sequences.
355
-
361
+
356
362
  Notes:
357
363
  The function uses a cached dictionary (via makeDictionaryFoldsTotalKnown) to
358
364
  efficiently retrieve values without repeatedly parsing OEIS data. Map shape
@@ -0,0 +1,103 @@
1
+ from mapFolding.someAssemblyRequired import ShatteredDataclass, ast_Identifier, parsePathFilename2astModule, str_nameDOTname
2
+ from mapFolding.someAssemblyRequired.toolboxNumba import theNumbaFlow
3
+ from mapFolding.someAssemblyRequired.transformationTools import shatter_dataclassesDOTdataclass
4
+ from mapFolding.theSSOT import ComputationState, DatatypeElephino as TheDatatypeElephino, DatatypeFoldsTotal as TheDatatypeFoldsTotal, DatatypeLeavesTotal as TheDatatypeLeavesTotal
5
+ from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal, getPathRootJobDEFAULT
6
+
7
+ import dataclasses
8
+ from pathlib import Path, PurePosixPath
9
+ from typing import TypeAlias
10
+
11
+ @dataclasses.dataclass
12
+ class RecipeJob:
13
+ state: ComputationState
14
+ # TODO create function to calculate `foldsTotalEstimated`
15
+ foldsTotalEstimated: int = 0
16
+ shatteredDataclass: ShatteredDataclass = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType]
17
+
18
+ # ========================================
19
+ # Source
20
+ source_astModule = parsePathFilename2astModule(theNumbaFlow.pathFilenameSequential)
21
+ sourceCountCallable: ast_Identifier = theNumbaFlow.callableSequential
22
+
23
+ sourceLogicalPathModuleDataclass: str_nameDOTname = theNumbaFlow.logicalPathModuleDataclass
24
+ sourceDataclassIdentifier: ast_Identifier = theNumbaFlow.dataclassIdentifier
25
+ sourceDataclassInstance: ast_Identifier = theNumbaFlow.dataclassInstance
26
+
27
+ sourcePathPackage: PurePosixPath | None = theNumbaFlow.pathPackage
28
+ sourcePackageIdentifier: ast_Identifier | None = theNumbaFlow.packageIdentifier
29
+
30
+ # ========================================
31
+ # Filesystem (names of physical objects)
32
+ pathPackage: PurePosixPath | None = None
33
+ pathModule: PurePosixPath | None = PurePosixPath(getPathRootJobDEFAULT())
34
+ """ `pathModule` will override `pathPackage` and `logicalPathRoot`."""
35
+ fileExtension: str = theNumbaFlow.fileExtension
36
+ pathFilenameFoldsTotal: PurePosixPath = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType]
37
+
38
+ # ========================================
39
+ # Logical identifiers (as opposed to physical identifiers)
40
+ packageIdentifier: ast_Identifier | None = None
41
+ logicalPathRoot: str_nameDOTname | None = None
42
+ """ `logicalPathRoot` likely corresponds to a physical filesystem directory."""
43
+ moduleIdentifier: ast_Identifier = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType]
44
+ countCallable: ast_Identifier = sourceCountCallable
45
+ dataclassIdentifier: ast_Identifier | None = sourceDataclassIdentifier
46
+ dataclassInstance: ast_Identifier | None = sourceDataclassInstance
47
+ logicalPathModuleDataclass: str_nameDOTname | None = sourceLogicalPathModuleDataclass
48
+
49
+ # ========================================
50
+ # Datatypes
51
+ DatatypeFoldsTotal: TypeAlias = TheDatatypeFoldsTotal
52
+ DatatypeElephino: TypeAlias = TheDatatypeElephino
53
+ DatatypeLeavesTotal: TypeAlias = TheDatatypeLeavesTotal
54
+
55
+ def _makePathFilename(self,
56
+ pathRoot: PurePosixPath | None = None,
57
+ logicalPathINFIX: str_nameDOTname | None = None,
58
+ filenameStem: str | None = None,
59
+ fileExtension: str | None = None,
60
+ ) -> PurePosixPath:
61
+ if pathRoot is None:
62
+ pathRoot = self.pathPackage or PurePosixPath(Path.cwd())
63
+ if logicalPathINFIX:
64
+ whyIsThisStillAThing: list[str] = logicalPathINFIX.split('.')
65
+ pathRoot = pathRoot.joinpath(*whyIsThisStillAThing)
66
+ if filenameStem is None:
67
+ filenameStem = self.moduleIdentifier
68
+ if fileExtension is None:
69
+ fileExtension = self.fileExtension
70
+ filename: str = filenameStem + fileExtension
71
+ return pathRoot.joinpath(filename)
72
+
73
+ @property
74
+ def pathFilenameModule(self) -> PurePosixPath:
75
+ if self.pathModule is None:
76
+ return self._makePathFilename()
77
+ else:
78
+ return self._makePathFilename(pathRoot=self.pathModule, logicalPathINFIX=None)
79
+
80
+ def __post_init__(self):
81
+ pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(self.state.mapShape))
82
+
83
+ if self.moduleIdentifier is None: # pyright: ignore[reportUnnecessaryComparison]
84
+ self.moduleIdentifier = pathFilenameFoldsTotal.stem
85
+
86
+ if self.pathFilenameFoldsTotal is None: # pyright: ignore[reportUnnecessaryComparison]
87
+ self.pathFilenameFoldsTotal = pathFilenameFoldsTotal
88
+
89
+ if self.shatteredDataclass is None and self.logicalPathModuleDataclass and self.dataclassIdentifier and self.dataclassInstance: # pyright: ignore[reportUnnecessaryComparison]
90
+ self.shatteredDataclass = shatter_dataclassesDOTdataclass(self.logicalPathModuleDataclass, self.dataclassIdentifier, self.dataclassInstance)
91
+
92
+ # ========================================
93
+ # Fields you probably don't need =================================
94
+ # Dispatcher =================================
95
+ sourceDispatcherCallable: ast_Identifier = theNumbaFlow.callableDispatcher
96
+ dispatcherCallable: ast_Identifier = sourceDispatcherCallable
97
+ # Parallel counting =================================
98
+ sourceDataclassInstanceTaskDistribution: ast_Identifier = theNumbaFlow.dataclassInstanceTaskDistribution
99
+ sourceConcurrencyManagerNamespace: ast_Identifier = theNumbaFlow.concurrencyManagerNamespace
100
+ sourceConcurrencyManagerIdentifier: ast_Identifier = theNumbaFlow.concurrencyManagerIdentifier
101
+ dataclassInstanceTaskDistribution: ast_Identifier = sourceDataclassInstanceTaskDistribution
102
+ concurrencyManagerNamespace: ast_Identifier = sourceConcurrencyManagerNamespace
103
+ concurrencyManagerIdentifier: ast_Identifier = sourceConcurrencyManagerIdentifier
@@ -48,40 +48,40 @@ to verify correctness at each transformation stage through the integrated test s
48
48
  """
49
49
 
50
50
  from mapFolding.someAssemblyRequired._theTypes import (
51
- ast_expr_Slice,
52
- ast_Identifier,
53
- astClassHasDOTnameNotName,
54
- astClassHasDOTtarget,
55
- astClassHasDOTvalue_expr,
56
- astClassHasDOTvalue_exprNone,
57
- astClassHasDOTtargetAttributeNameSubscript,
58
- astClassHasDOTtarget_expr,
59
- astClassHasDOTvalue,
60
- astClassOptionallyHasDOTnameNotName,
61
- intORlist_ast_type_paramORstr_orNone,
62
- intORstr_orNone,
63
- list_ast_type_paramORstr_orNone,
64
- str_nameDOTname,
65
- 个,
51
+ ast_expr_Slice as ast_expr_Slice,
52
+ ast_Identifier as ast_Identifier,
53
+ astClassHasDOTnameNotName as astClassHasDOTnameNotName,
54
+ astClassHasDOTtarget as astClassHasDOTtarget,
55
+ astClassHasDOTvalue_expr as astClassHasDOTvalue_expr,
56
+ astClassHasDOTvalue_exprNone as astClassHasDOTvalue_exprNone,
57
+ astClassHasDOTtargetAttributeNameSubscript as astClassHasDOTtargetAttributeNameSubscript,
58
+ astClassHasDOTtarget_expr as astClassHasDOTtarget_expr,
59
+ astClassHasDOTvalue as astClassHasDOTvalue,
60
+ astClassOptionallyHasDOTnameNotName as astClassOptionallyHasDOTnameNotName,
61
+ intORlist_ast_type_paramORstr_orNone as intORlist_ast_type_paramORstr_orNone,
62
+ intORstr_orNone as intORstr_orNone,
63
+ list_ast_type_paramORstr_orNone as list_ast_type_paramORstr_orNone,
64
+ str_nameDOTname as str_nameDOTname,
65
+ 个 as 个,
66
66
  )
67
67
 
68
68
  from mapFolding.someAssemblyRequired._toolboxPython import (
69
- importLogicalPath2Callable,
70
- importPathFilename2Callable,
71
- NodeChanger,
72
- NodeTourist,
73
- parseLogicalPath2astModule,
74
- parsePathFilename2astModule,
69
+ importLogicalPath2Callable as importLogicalPath2Callable,
70
+ importPathFilename2Callable as importPathFilename2Callable,
71
+ NodeChanger as NodeChanger,
72
+ NodeTourist as NodeTourist,
73
+ parseLogicalPath2astModule as parseLogicalPath2astModule,
74
+ parsePathFilename2astModule as parsePathFilename2astModule,
75
75
  )
76
76
 
77
- from mapFolding.someAssemblyRequired._toolboxAntecedents import DOT, ifThis
78
- from mapFolding.someAssemblyRequired._tool_Make import Make
79
- from mapFolding.someAssemblyRequired._tool_Then import grab, Then
77
+ from mapFolding.someAssemblyRequired._toolboxAntecedents import be as be, DOT as DOT, ifThis as ifThis
78
+ from mapFolding.someAssemblyRequired._tool_Make import Make as Make
79
+ from mapFolding.someAssemblyRequired._tool_Then import grab as grab, Then as Then
80
80
 
81
81
  from mapFolding.someAssemblyRequired._toolboxContainers import (
82
- IngredientsFunction,
83
- IngredientsModule,
84
- LedgerOfImports,
85
- RecipeSynthesizeFlow,
86
- ShatteredDataclass,
82
+ IngredientsFunction as IngredientsFunction,
83
+ IngredientsModule as IngredientsModule,
84
+ LedgerOfImports as LedgerOfImports,
85
+ RecipeSynthesizeFlow as RecipeSynthesizeFlow,
86
+ ShatteredDataclass as ShatteredDataclass,
87
87
  )
@@ -56,7 +56,7 @@ class Make:
56
56
  return ast.arguments(posonlyargs, args, vararg, kwonlyargs, kw_defaults, kwarg, defaults)
57
57
 
58
58
  @staticmethod
59
- def Assign(listTargets: Any, value: ast.expr, **keywordArguments: intORstr_orNone) -> ast.Assign:
59
+ def Assign(listTargets: list[ast.expr], value: ast.expr, **keywordArguments: intORstr_orNone) -> ast.Assign:
60
60
  return ast.Assign(listTargets, value, **keywordArguments)
61
61
 
62
62
  @staticmethod
@@ -231,3 +231,15 @@ class ifThis:
231
231
  def Z0Z_unparseIs(astAST: ast.AST) -> Callable[[ast.AST], bool]:
232
232
  def workhorse(node: ast.AST) -> bool: return ast.unparse(node) == ast.unparse(astAST)
233
233
  return workhorse
234
+
235
+
236
+ class be:
237
+ @staticmethod
238
+ def Call(node: ast.AST) -> TypeGuard[ast.Call]:
239
+ return isinstance(node, ast.Call)
240
+ @staticmethod
241
+ def Name(node: ast.AST) -> TypeGuard[ast.Name]:
242
+ return isinstance(node, ast.Name)
243
+ @staticmethod
244
+ def Return(node: ast.AST) -> TypeGuard[ast.Return]:
245
+ return isinstance(node, ast.Return)
@@ -29,7 +29,6 @@ from Z0Z_tools import updateExtendPolishDictionaryLists
29
29
  import ast
30
30
  import dataclasses
31
31
 
32
- # Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
33
32
  class LedgerOfImports:
34
33
  """
35
34
  Track and manage import statements for programmatically generated code.
@@ -58,23 +57,22 @@ class LedgerOfImports:
58
57
  self.walkThis(startWith)
59
58
 
60
59
  def addAst(self, astImport____: ast.Import | ast.ImportFrom) -> None:
61
- assert isinstance(astImport____, (ast.Import, ast.ImportFrom)), f"I received {type(astImport____) = }, but I can only accept {ast.Import} and {ast.ImportFrom}."
62
- if isinstance(astImport____, ast.Import):
63
- for alias in astImport____.names:
64
- self.listImport.append(alias.name)
65
- elif isinstance(astImport____, ast.ImportFrom): # type: ignore
66
- # TODO fix the mess created by `None` means '.'. I need a `str_nameDOTname` to replace '.'
67
- if astImport____.module is None:
68
- astImport____.module = '.'
69
- for alias in astImport____.names:
70
- self.dictionaryImportFrom[astImport____.module].append((alias.name, alias.asname))
60
+ match astImport____:
61
+ case ast.Import():
62
+ for alias in astImport____.names:
63
+ self.listImport.append(alias.name)
64
+ case ast.ImportFrom():
65
+ # TODO fix the mess created by `None` means '.'. I need a `str_nameDOTname` to replace '.'
66
+ if astImport____.module is None:
67
+ astImport____.module = '.'
68
+ for alias in astImport____.names:
69
+ self.dictionaryImportFrom[astImport____.module].append((alias.name, alias.asname))
70
+ case _:
71
+ raise ValueError(f"I received {type(astImport____) = }, but I can only accept {ast.Import} and {ast.ImportFrom}.")
71
72
 
72
73
  def addImport_asStr(self, moduleWithLogicalPath: str_nameDOTname) -> None:
73
74
  self.listImport.append(moduleWithLogicalPath)
74
75
 
75
- # def addImportFrom_asStr(self, moduleWithLogicalPath: str_nameDOTname, name: ast_Identifier, asname: ast_Identifier | None = None) -> None:
76
- # self.dictionaryImportFrom[moduleWithLogicalPath].append((name, asname))
77
-
78
76
  def addImportFrom_asStr(self, moduleWithLogicalPath: str_nameDOTname, name: ast_Identifier, asname: ast_Identifier | None = None) -> None:
79
77
  if moduleWithLogicalPath not in self.dictionaryImportFrom:
80
78
  self.dictionaryImportFrom[moduleWithLogicalPath] = []
@@ -85,15 +83,14 @@ class LedgerOfImports:
85
83
  self.removeImportFrom(moduleWithLogicalPath, None, None)
86
84
 
87
85
  def removeImportFrom(self, moduleWithLogicalPath: str_nameDOTname, name: ast_Identifier | None, asname: ast_Identifier | None = None) -> None:
88
- assert moduleWithLogicalPath is not None, SyntaxError(f"I received `{moduleWithLogicalPath = }`, but it must be the name of a module.")
86
+ """
87
+ name, asname Action
88
+ None, None : remove all matches for the module
89
+ ast_Identifier, ast_Identifier : remove exact matches
90
+ ast_Identifier, None : remove exact matches
91
+ None, ast_Identifier : remove all matches for asname and if entry_asname is None remove name == ast_Identifier
92
+ """
89
93
  if moduleWithLogicalPath in self.dictionaryImportFrom:
90
- """
91
- name, asname Meaning
92
- ast_Identifier, ast_Identifier : remove exact matches
93
- ast_Identifier, None : remove exact matches
94
- None, ast_Identifier : remove all matches for asname and if entry_asname is None remove name == ast_Identifier
95
- None, None : remove all matches for the module
96
- """
97
94
  if name is None and asname is None:
98
95
  # Remove all entries for the module
99
96
  self.dictionaryImportFrom.pop(moduleWithLogicalPath)
@@ -102,7 +99,6 @@ class LedgerOfImports:
102
99
  self.dictionaryImportFrom[moduleWithLogicalPath] = [(entry_name, entry_asname) for entry_name, entry_asname in self.dictionaryImportFrom[moduleWithLogicalPath]
103
100
  if not (entry_asname == asname) and not (entry_asname is None and entry_name == asname)]
104
101
  else:
105
- # Remove exact matches for the module
106
102
  self.dictionaryImportFrom[moduleWithLogicalPath] = [(entry_name, entry_asname) for entry_name, entry_asname in self.dictionaryImportFrom[moduleWithLogicalPath]
107
103
  if not (entry_name == name and entry_asname == asname)]
108
104
  if not self.dictionaryImportFrom[moduleWithLogicalPath]:
@@ -308,7 +304,7 @@ class IngredientsModule:
308
304
  @dataclasses.dataclass
309
305
  class RecipeSynthesizeFlow:
310
306
  """
311
- Configure the generation of optimized Numba-accelerated code modules.
307
+ Configure the generation of new modules, including Numba-accelerated code modules.
312
308
 
313
309
  RecipeSynthesizeFlow defines the complete blueprint for transforming an original
314
310
  Python algorithm into an optimized, accelerated implementation. It specifies:
@@ -358,7 +354,7 @@ class RecipeSynthesizeFlow:
358
354
  """ `logicalPathFlowRoot` likely corresponds to a physical filesystem directory."""
359
355
 
360
356
  # Module ================================
361
- moduleDispatcher: ast_Identifier = 'numbaCount_doTheNeedful'
357
+ moduleDispatcher: ast_Identifier = 'numbaCount'
362
358
  moduleInitialize: ast_Identifier = moduleDispatcher
363
359
  moduleParallel: ast_Identifier = moduleDispatcher
364
360
  moduleSequential: ast_Identifier = moduleDispatcher
@@ -376,6 +372,10 @@ class RecipeSynthesizeFlow:
376
372
  dataclassInstance: ast_Identifier = sourceDataclassInstance
377
373
  dataclassInstanceTaskDistribution: ast_Identifier = sourceDataclassInstanceTaskDistribution
378
374
 
375
+ removeDataclassDispatcher: bool = False
376
+ removeDataclassInitialize: bool = False
377
+ removeDataclassParallel: bool = True
378
+ removeDataclassSequential: bool = True
379
379
  # ========================================
380
380
  # Computed
381
381
  # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
@@ -432,10 +432,10 @@ class ShatteredDataclass:
432
432
  countingVariableName: ast.Name
433
433
  """AST name node representing the counting variable identifier."""
434
434
 
435
- field2AnnAssign: dict[ast_Identifier, ast.AnnAssign] = dataclasses.field(default_factory=dict)
435
+ field2AnnAssign: dict[ast_Identifier, ast.AnnAssign | ast.Assign] = dataclasses.field(default_factory=dict)
436
436
  """Maps field names to their corresponding AST call expressions."""
437
437
 
438
- Z0Z_field2AnnAssign: dict[ast_Identifier, tuple[ast.AnnAssign, str]] = dataclasses.field(default_factory=dict)
438
+ Z0Z_field2AnnAssign: dict[ast_Identifier, tuple[ast.AnnAssign | ast.Assign, str]] = dataclasses.field(default_factory=dict)
439
439
 
440
440
  fragments4AssignmentOrParameters: ast.Tuple = dummyTuple
441
441
  """AST tuple used as target for assignment to capture returned fragments."""
@@ -107,6 +107,7 @@ def importPathFilename2Callable(pathFilename: PathLike[Any] | PurePath, identifi
107
107
  Load a callable (function, class, etc.) from a Python file.
108
108
  This function imports a specified Python file as a module, extracts a callable object
109
109
  from it by name, and returns that callable.
110
+
110
111
  Parameters
111
112
  ----------
112
113
  pathFilename : Union[PathLike[Any], PurePath]
@@ -115,10 +116,12 @@ def importPathFilename2Callable(pathFilename: PathLike[Any] | PurePath, identifi
115
116
  Name of the callable to extract from the imported module.
116
117
  moduleIdentifier : Optional[str]
117
118
  Name to use for the imported module. If None, the filename stem is used.
119
+
118
120
  Returns
119
121
  -------
120
122
  Callable[..., Any]
121
123
  The callable object extracted from the imported module.
124
+
122
125
  Raises
123
126
  ------
124
127
  ImportError
@@ -19,12 +19,22 @@ as Python scripts or further compiled into standalone executables.
19
19
  """
20
20
 
21
21
  from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal
22
- from mapFolding.someAssemblyRequired import ast_Identifier, ifThis, Make, NodeChanger, Then, IngredientsFunction, IngredientsModule, LedgerOfImports
23
- from mapFolding.someAssemblyRequired.toolboxNumba import RecipeJob, SpicesJobNumba, decorateCallableWithNumba
24
- from mapFolding.someAssemblyRequired.transformationTools import extractFunctionDef, write_astModule
25
- from mapFolding.someAssemblyRequired.transformationTools import makeInitializedComputationState
26
- from mapFolding.theSSOT import The, raiseIfNoneGitHubIssueNumber3
27
- from mapFolding.oeis import getFoldsTotalKnown
22
+ from mapFolding.someAssemblyRequired import (
23
+ ast_Identifier,
24
+ be,
25
+ ifThis,
26
+ IngredientsFunction,
27
+ IngredientsModule,
28
+ LedgerOfImports,
29
+ Make,
30
+ NodeChanger,
31
+ NodeTourist,
32
+ Then,
33
+ )
34
+ from mapFolding.someAssemblyRequired.toolboxNumba import parametersNumbaLight, SpicesJobNumba, decorateCallableWithNumba
35
+ from mapFolding.someAssemblyRequired.transformationTools import extractFunctionDef, write_astModule, makeInitializedComputationState
36
+ from mapFolding.someAssemblyRequired.RecipeJob import RecipeJob
37
+ from mapFolding import The, raiseIfNoneGitHubIssueNumber3, getFoldsTotalKnown
28
38
  from typing import cast
29
39
  from Z0Z_tools import autoDecodingRLE
30
40
  from pathlib import PurePosixPath
@@ -89,6 +99,10 @@ if __name__ == '__main__':
89
99
  countWithProgressBar = NodeChanger(findThis, doThat)
90
100
  countWithProgressBar.visit(ingredientsFunction.astFunctionDef)
91
101
 
102
+ removeReturnStatement = NodeChanger(be.Return, Then.removeIt)
103
+ removeReturnStatement.visit(ingredientsFunction.astFunctionDef)
104
+ ingredientsFunction.astFunctionDef.returns = Make.Constant(value=None)
105
+
92
106
  ingredientsModule.appendLauncher(ast.parse(linesLaunch))
93
107
 
94
108
  return ingredientsModule, ingredientsFunction
@@ -119,9 +133,13 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
119
133
  """
120
134
  ingredientsFunction.imports.update(job.shatteredDataclass.ledger)
121
135
 
122
- list_IdentifiersNotUsed = list_IdentifiersNotUsedHARDCODED
123
-
124
136
  list_argCuzMyBrainRefusesToThink = ingredientsFunction.astFunctionDef.args.args + ingredientsFunction.astFunctionDef.args.posonlyargs + ingredientsFunction.astFunctionDef.args.kwonlyargs
137
+ list_arg_arg: list[ast_Identifier] = [ast_arg.arg for ast_arg in list_argCuzMyBrainRefusesToThink]
138
+ listName: list[ast.Name] = []
139
+ NodeTourist(be.Name, Then.appendTo(listName)).visit(ingredientsFunction.astFunctionDef)
140
+ list_Identifiers: list[ast_Identifier] = [astName.id for astName in listName]
141
+ list_IdentifiersNotUsed: list[ast_Identifier] = list(set(list_arg_arg) - set(list_Identifiers))
142
+
125
143
  for ast_arg in list_argCuzMyBrainRefusesToThink:
126
144
  if ast_arg.arg in job.shatteredDataclass.field2AnnAssign:
127
145
  if ast_arg.arg in list_IdentifiersNotUsed:
@@ -181,11 +199,6 @@ def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba) -> None:
181
199
  if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
182
200
  ingredientsCount: IngredientsFunction = IngredientsFunction(astFunctionDef, LedgerOfImports())
183
201
 
184
- # Change the return so you can dynamically determine which variables are not used
185
- removeReturnStatement = NodeChanger(lambda node: isinstance(node, ast.Return), Then.removeIt) # type: ignore
186
- removeReturnStatement.visit(ingredientsCount.astFunctionDef)
187
- ingredientsCount.astFunctionDef.returns = Make.Constant(value=None)
188
-
189
202
  # Remove `foldGroups` and any other unused statements, so you can dynamically determine which variables are not used
190
203
  findThis = ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier('foldGroups'))
191
204
  doThat = Then.removeIt
@@ -199,30 +212,48 @@ def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba) -> None:
199
212
  doThat = Then.replaceWith(Make.Constant(int(job.state.__dict__[identifier])))
200
213
  NodeChanger(findThis, doThat).visit(ingredientsCount.astFunctionDef)
201
214
 
202
- # This launcher eliminates the use of one identifier, so run it now and you can dynamically determine which variables are not used
203
215
  ingredientsModule = IngredientsModule()
216
+ # This launcher eliminates the use of one identifier, so run it now and you can dynamically determine which variables are not used
204
217
  if spices.useNumbaProgressBar:
205
218
  ingredientsModule, ingredientsCount = addLauncherNumbaProgress(ingredientsModule, ingredientsCount, job, spices)
206
219
  spices.parametersNumba['nogil'] = True
220
+ else:
221
+ linesLaunch: str = f"""
222
+ if __name__ == '__main__':
223
+ import time
224
+ timeStart = time.perf_counter()
225
+ foldsTotal = {job.countCallable}() * {job.state.leavesTotal}
226
+ print(time.perf_counter() - timeStart)
227
+ print('\\nmap {job.state.mapShape} =', foldsTotal)
228
+ writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
229
+ writeStream.write(str(foldsTotal))
230
+ writeStream.close()
231
+ from mapFolding.oeis import getFoldsTotalKnown
232
+ print(foldsTotal == getFoldsTotalKnown({job.state.mapShape}))
233
+ """
234
+ ingredientsModule.appendLauncher(ast.parse(linesLaunch))
235
+ changeReturnParallelCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(job.shatteredDataclass.countingVariableName)))
236
+ changeReturnParallelCallable.visit(ingredientsCount.astFunctionDef)
237
+ ingredientsCount.astFunctionDef.returns = job.shatteredDataclass.countingVariableAnnotation
207
238
 
208
239
  ingredientsCount = move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsCount, job)
209
240
 
210
241
  Z0Z_Identifier = 'DatatypeLeavesTotal'
211
242
  Z0Z_type = 'uint8'
212
243
  ingredientsModule.imports.addImportFrom_asStr('numba', Z0Z_type)
213
- Z0Z_module = 'typing'
214
- Z0Z_annotation = 'TypeAlias'
215
- ingredientsModule.imports.addImportFrom_asStr(Z0Z_module, Z0Z_annotation)
216
- Z0Z_statement = Make.AnnAssign(Make.Name(Z0Z_Identifier, ast.Store()), Make.Name(Z0Z_annotation), Make.Name(Z0Z_type))
244
+ Z0Z_statement = Make.Assign([Make.Name(Z0Z_Identifier, ast.Store())], Make.Name(Z0Z_type))
217
245
  ingredientsModule.appendPrologue(statement=Z0Z_statement)
218
246
 
219
247
  Z0Z_Identifier = 'DatatypeElephino'
220
- Z0Z_type = 'int16'
248
+ Z0Z_type = 'uint8'
249
+ ingredientsModule.imports.addImportFrom_asStr('numba', Z0Z_type)
250
+ Z0Z_statement = Make.Assign([Make.Name(Z0Z_Identifier, ast.Store())], Make.Name(Z0Z_type))
251
+ ingredientsModule.appendPrologue(statement=Z0Z_statement)
252
+
253
+ Z0Z_Identifier = 'DatatypeFoldsTotal'
254
+ Z0Z_type = 'int64'
221
255
  ingredientsModule.imports.addImportFrom_asStr('numba', Z0Z_type)
222
- Z0Z_module = 'typing'
223
- Z0Z_annotation = 'TypeAlias'
224
- ingredientsModule.imports.addImportFrom_asStr(Z0Z_module, Z0Z_annotation)
225
- Z0Z_statement = Make.AnnAssign(Make.Name(Z0Z_Identifier, ast.Store()), Make.Name(Z0Z_annotation), Make.Name(Z0Z_type))
256
+ Z0Z_statement = Make.Assign([Make.Name(Z0Z_Identifier, ast.Store())], Make.Name(Z0Z_type))
226
257
  ingredientsModule.appendPrologue(statement=Z0Z_statement)
227
258
 
228
259
  ingredientsCount.imports.removeImportFromModule('mapFolding.theSSOT')
@@ -233,7 +264,7 @@ def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba) -> None:
233
264
  ingredientsCount.imports.addImportFrom_asStr(Z0Z_module, Z0Z_type_name, Z0Z_asname)
234
265
  Z0Z_asname = 'Array1DElephino'
235
266
  ingredientsCount.imports.removeImportFrom(Z0Z_module, None, Z0Z_asname)
236
- Z0Z_type_name = 'int16'
267
+ Z0Z_type_name = 'uint8'
237
268
  ingredientsCount.imports.addImportFrom_asStr(Z0Z_module, Z0Z_type_name, Z0Z_asname)
238
269
  Z0Z_asname = 'Array3D'
239
270
  ingredientsCount.imports.removeImportFrom(Z0Z_module, None, Z0Z_asname)
@@ -269,11 +300,12 @@ def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba) -> None:
269
300
  """
270
301
 
271
302
  if __name__ == '__main__':
272
- mapShape = (2,4)
303
+ mapShape = (1,24)
273
304
  state = makeInitializedComputationState(mapShape)
274
305
  foldsTotalEstimated = getFoldsTotalKnown(state.mapShape) // state.leavesTotal
275
306
  pathModule = PurePosixPath(The.pathPackage, 'jobs')
276
307
  pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
277
308
  aJob = RecipeJob(state, foldsTotalEstimated, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
278
- spices = SpicesJobNumba()
309
+ spices = SpicesJobNumba(useNumbaProgressBar=False, parametersNumba=parametersNumbaLight)
310
+ # spices = SpicesJobNumba()
279
311
  makeJobNumba(aJob, spices)