mapFolding 0.5.0__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. mapFolding/__init__.py +96 -58
  2. mapFolding/basecamp.py +5 -7
  3. mapFolding/beDRY.py +11 -41
  4. mapFolding/oeis.py +71 -74
  5. mapFolding/theConfiguration.py +58 -0
  6. mapFolding/theDao.py +1 -1
  7. mapFolding/theSSOT.py +14 -48
  8. mapFolding/theSSOTdatatypes.py +25 -36
  9. mapFolding/theWrongWay.py +7 -0
  10. {mapFolding-0.5.0.dist-info → mapfolding-0.6.0.dist-info}/METADATA +6 -4
  11. mapfolding-0.6.0.dist-info/RECORD +16 -0
  12. {mapFolding-0.5.0.dist-info → mapfolding-0.6.0.dist-info}/WHEEL +1 -1
  13. {mapFolding-0.5.0.dist-info → mapfolding-0.6.0.dist-info}/top_level.txt +0 -1
  14. mapFolding/reference/flattened.py +0 -377
  15. mapFolding/reference/hunterNumba.py +0 -132
  16. mapFolding/reference/irvineJavaPort.py +0 -120
  17. mapFolding/reference/jax.py +0 -208
  18. mapFolding/reference/lunnan.py +0 -153
  19. mapFolding/reference/lunnanNumpy.py +0 -123
  20. mapFolding/reference/lunnanWhile.py +0 -121
  21. mapFolding/reference/rotatedEntryPoint.py +0 -240
  22. mapFolding/reference/total_countPlus1vsPlusN.py +0 -211
  23. mapFolding/someAssemblyRequired/__init__.py +0 -5
  24. mapFolding/someAssemblyRequired/getLLVMforNoReason.py +0 -19
  25. mapFolding/someAssemblyRequired/makeJob.py +0 -56
  26. mapFolding/someAssemblyRequired/synthesizeModuleJAX.py +0 -27
  27. mapFolding/someAssemblyRequired/synthesizeNumba.py +0 -345
  28. mapFolding/someAssemblyRequired/synthesizeNumbaGeneralized.py +0 -397
  29. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +0 -155
  30. mapFolding/someAssemblyRequired/synthesizeNumbaModules.py +0 -123
  31. mapFolding/syntheticModules/numbaCount.py +0 -158
  32. mapFolding/syntheticModules/numba_doTheNeedful.py +0 -13
  33. mapFolding-0.5.0.dist-info/RECORD +0 -39
  34. tests/__init__.py +0 -1
  35. tests/conftest.py +0 -335
  36. tests/test_computations.py +0 -42
  37. tests/test_oeis.py +0 -128
  38. tests/test_other.py +0 -175
  39. tests/test_tasks.py +0 -40
  40. /mapFolding/{syntheticModules/__init__.py → py.typed} +0 -0
  41. {mapFolding-0.5.0.dist-info → mapfolding-0.6.0.dist-info}/LICENSE +0 -0
  42. {mapFolding-0.5.0.dist-info → mapfolding-0.6.0.dist-info}/entry_points.txt +0 -0
mapFolding/__init__.py CHANGED
@@ -1,69 +1,107 @@
1
+ from collections import defaultdict
2
+ from types import ModuleType
3
+ import importlib
4
+
5
+ _dictionaryListsImportFrom: dict[str, list[str]] = defaultdict(list)
6
+
7
+ def __getattr__(name: str):
8
+ if name not in _mapSymbolToModule:
9
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
10
+
11
+ try:
12
+ moduleAsStr: str = _mapSymbolToModule[name]
13
+ module: ModuleType = importlib.import_module(moduleAsStr)
14
+ blankSymbol = getattr(module, name)
15
+ except (ImportError, ModuleNotFoundError, AttributeError):
16
+ raise
17
+
18
+ # The need to inject into globals tells us that the symbol has not actually been imported
19
+ globals()[name] = blankSymbol
20
+ return blankSymbol
21
+
22
+ _dictionaryListsImportFrom['mapFolding.basecamp'].extend([
23
+ 'countFolds',
24
+ ])
25
+
26
+ _dictionaryListsImportFrom['mapFolding.beDRY'].extend([
27
+ 'getFilenameFoldsTotal',
28
+ 'getPathFilenameFoldsTotal',
29
+ 'outfitCountFolds',
30
+ 'saveFoldsTotal',
31
+ ])
32
+
33
+ _dictionaryListsImportFrom['mapFolding.oeis'].extend([
34
+ 'clearOEIScache',
35
+ 'getOEISids',
36
+ 'oeisIDfor_n',
37
+ ])
38
+
1
39
  # fundamentals
2
- from mapFolding.theSSOT import (
3
- computationState,
4
- EnumIndices,
5
- getDispatcherCallable,
6
- getPathPackage,
7
- indexMy,
8
- indexTrack,
9
- myPackageNameIs,
10
- )
40
+ _dictionaryListsImportFrom['mapFolding.theSSOT'].extend([
41
+ 'computationState',
42
+ 'EnumIndices',
43
+ 'getDispatcherCallable',
44
+ 'indexMy',
45
+ 'indexTrack',
46
+ 'myPackageNameIs',
47
+ 'pathPackage',
48
+ ])
11
49
 
12
50
  # Datatype management
13
- from mapFolding.theSSOT import (
14
- getDatatypeModule,
15
- hackSSOTdatatype,
16
- hackSSOTdtype,
17
- setDatatypeElephino,
18
- setDatatypeFoldsTotal,
19
- setDatatypeLeavesTotal,
20
- setDatatypeModule,
21
- )
51
+ _dictionaryListsImportFrom['mapFolding.theSSOT'].extend([
52
+ 'getDatatypeModule',
53
+ 'hackSSOTdatatype',
54
+ 'hackSSOTdtype',
55
+ 'setDatatypeElephino',
56
+ 'setDatatypeFoldsTotal',
57
+ 'setDatatypeLeavesTotal',
58
+ 'setDatatypeModule',
59
+ ])
22
60
 
23
61
  # Synthesize modules
24
- from mapFolding.theSSOT import (
25
- formatFilenameModuleDEFAULT,
26
- getAlgorithmDispatcher,
27
- getAlgorithmSource,
28
- getPathJobRootDEFAULT,
29
- getPathSyntheticModules,
30
- moduleOfSyntheticModules,
31
- Z0Z_getDatatypeModuleScalar,
32
- Z0Z_getDecoratorCallable,
33
- Z0Z_setDatatypeModuleScalar,
34
- Z0Z_setDecoratorCallable,
35
- Z0Z_identifierCountFolds,
36
- )
62
+ _dictionaryListsImportFrom['mapFolding.theSSOT'].extend([
63
+ 'additional_importsHARDCODED',
64
+ 'formatFilenameModule',
65
+ 'getAlgorithmDispatcher',
66
+ 'getAlgorithmSource',
67
+ 'getPathJobRootDEFAULT',
68
+ 'getPathSyntheticModules',
69
+ 'listCallablesDispatchees',
70
+ 'moduleOfSyntheticModules',
71
+ 'Z0Z_filenameModuleWrite',
72
+ 'Z0Z_filenameWriteElseCallableTarget',
73
+ 'Z0Z_getDatatypeModuleScalar',
74
+ 'Z0Z_getDecoratorCallable',
75
+ 'Z0Z_identifierCountFolds',
76
+ 'Z0Z_setDatatypeModuleScalar',
77
+ 'Z0Z_setDecoratorCallable',
78
+ ])
37
79
 
38
80
  # Parameters for the prima donna
39
- from mapFolding.theSSOT import (
40
- ParametersNumba,
41
- parametersNumbaDEFAULT,
42
- parametersNumbaFailEarly,
43
- parametersNumbaMinimum,
44
- parametersNumbaParallelDEFAULT,
45
- parametersNumbaSuperJit,
46
- parametersNumbaSuperJitParallel,
47
- )
81
+ _dictionaryListsImportFrom['mapFolding.theSSOT'].extend([
82
+ 'ParametersNumba',
83
+ 'parametersNumbaDEFAULT',
84
+ 'parametersNumbaFailEarly',
85
+ 'parametersNumbaMinimum',
86
+ 'parametersNumbaParallelDEFAULT',
87
+ 'parametersNumbaSuperJit',
88
+ 'parametersNumbaSuperJitParallel',
89
+ ])
48
90
 
49
91
  # Coping
50
- from mapFolding.theSSOT import (
51
- FREAKOUT,
52
- )
53
-
54
- from mapFolding.beDRY import (
55
- getFilenameFoldsTotal,
56
- getPathFilenameFoldsTotal,
57
- outfitCountFolds,
58
- saveFoldsTotal,
59
- )
92
+ _dictionaryListsImportFrom['mapFolding.theSSOT'].extend([
93
+ 'FREAKOUT',
94
+ ])
60
95
 
61
- from mapFolding.basecamp import countFolds
62
- from mapFolding.oeis import clearOEIScache, getOEISids, oeisIDfor_n
96
+ _mapSymbolToModule: dict[str, str] = {}
97
+ for moduleAsStr, listSymbolsAsStr in _dictionaryListsImportFrom.items():
98
+ for symbolAsStr in listSymbolsAsStr:
99
+ _mapSymbolToModule[symbolAsStr] = moduleAsStr
63
100
 
64
- __all__: list[str] = [
65
- 'clearOEIScache',
66
- 'countFolds',
67
- 'getOEISids',
68
- 'oeisIDfor_n',
69
- ]
101
+ from typing import TYPE_CHECKING
102
+ if TYPE_CHECKING:
103
+ from basecamp import *
104
+ from beDRY import *
105
+ from oeis import *
106
+ from theDao import *
107
+ from theSSOT import *
mapFolding/basecamp.py CHANGED
@@ -3,11 +3,10 @@ from mapFolding import computationState, getDispatcherCallable, getPathFilenameF
3
3
  from os import PathLike
4
4
  from pathlib import Path
5
5
 
6
- def countFolds(listDimensions: Sequence[int],
7
- pathLikeWriteFoldsTotal: str | PathLike[str] | None = None,
8
- computationDivisions: int | str | None = None,
9
- CPUlimit: int | float | bool | None = None,
10
- **keywordArguments: str | bool
6
+ def countFolds(listDimensions: Sequence[int]
7
+ , pathLikeWriteFoldsTotal: str | PathLike[str] | None = None
8
+ , computationDivisions: int | str | None = None
9
+ , CPUlimit: int | float | bool | None = None
11
10
  ) -> int:
12
11
  """Count the total number of possible foldings for a given map dimensions.
13
12
 
@@ -18,7 +17,6 @@ def countFolds(listDimensions: Sequence[int],
18
17
  computationDivisions (None):
19
18
  Whether and how to divide the computational work. See notes for details.
20
19
  CPUlimit (None): This is only relevant if there are `computationDivisions`: whether and how to limit the CPU usage. See notes for details.
21
- **keywordArguments: Datatype management. See `outfitCountFolds` for details.
22
20
  Returns:
23
21
  foldsTotal: Total number of distinct ways to fold a map of the given dimensions.
24
22
 
@@ -39,7 +37,7 @@ def countFolds(listDimensions: Sequence[int],
39
37
  N.B.: You probably don't want to divide the computation into tasks.
40
38
  If you want to compute a large `foldsTotal`, dividing the computation into tasks is usually a bad idea. Dividing the algorithm into tasks is inherently inefficient: efficient division into tasks means there would be no overlap in the work performed by each task. When dividing this algorithm, the amount of overlap is between 50% and 90% by all tasks: at least 50% of the work done by every task must be done by _all_ tasks. If you improve the computation time, it will only change by -10 to -50% depending on (at the very least) the ratio of the map dimensions and the number of leaves. If an undivided computation would take 10 hours on your computer, for example, the computation will still take at least 5 hours but you might reduce the time to 9 hours. Most of the time, however, you will increase the computation time. If logicalCores >= leavesTotal, it will probably be faster. If logicalCores <= 2 * leavesTotal, it will almost certainly be slower for all map dimensions.
41
39
  """
42
- stateUniversal: computationState = outfitCountFolds(listDimensions, computationDivisions=computationDivisions, CPUlimit=CPUlimit, **keywordArguments)
40
+ stateUniversal: computationState = outfitCountFolds(listDimensions, computationDivisions=computationDivisions, CPUlimit=CPUlimit)
43
41
 
44
42
  dispatcher = getDispatcherCallable()
45
43
  dispatcher(**stateUniversal)
mapFolding/beDRY.py CHANGED
@@ -7,13 +7,10 @@ from mapFolding import (
7
7
  hackSSOTdtype,
8
8
  indexMy,
9
9
  indexTrack,
10
- setDatatypeElephino,
11
- setDatatypeFoldsTotal,
12
10
  setDatatypeLeavesTotal,
13
- setDatatypeModule,
14
11
  )
15
12
  from collections.abc import Sequence
16
- from numba import get_num_threads, set_num_threads
13
+ from numba import get_num_threads, set_num_threads
17
14
  from numpy import dtype, integer, ndarray
18
15
  from numpy.typing import DTypeLike, NDArray
19
16
  from pathlib import Path
@@ -24,7 +21,7 @@ import numpy
24
21
  import os
25
22
 
26
23
  def getFilenameFoldsTotal(mapShape: Sequence[int] | ndarray[tuple[int], dtype[integer[Any]]]) -> str:
27
- """Imagine your computer has been counting folds for 70 hours, and when it tries to save your newly discovered value,
24
+ """Imagine your computer has been counting folds for 9 days, and when it tries to save your newly discovered value,
28
25
  the filename is invalid. I bet you think this function is more important after that thought experiment.
29
26
 
30
27
  Make a standardized filename for the computed value `foldsTotal`.
@@ -45,7 +42,7 @@ def getFilenameFoldsTotal(mapShape: Sequence[int] | ndarray[tuple[int], dtype[in
45
42
  mapShape: A sequence of integers representing the dimensions of the map.
46
43
 
47
44
  Returns:
48
- filenameFoldsTotal: A filename string in format 'pNxM.foldsTotal' where N,M are sorted dimensions
45
+ filenameFoldsTotal: A filename string in format 'pMxN.foldsTotal' where M,N are sorted dimensions
49
46
  """
50
47
  return 'p' + 'x'.join(str(dimension) for dimension in sorted(mapShape)) + '.foldsTotal'
51
48
 
@@ -139,7 +136,7 @@ def getTaskDivisions(computationDivisions: int | str | None, concurrencyLimit: i
139
136
  pass
140
137
  elif isinstance(computationDivisions, int):
141
138
  taskDivisions = computationDivisions
142
- elif isinstance(computationDivisions, str):
139
+ elif isinstance(computationDivisions, str): # type: ignore 'Unnecessary isinstance call; "str" is always an instance of "str", so sayeth Pylance'. Yeah, well "User is not always an instance of "correct input" so sayeth the programmer.
143
140
  computationDivisions = computationDivisions.lower()
144
141
  if computationDivisions == 'maximum':
145
142
  taskDivisions = leavesTotal
@@ -220,7 +217,10 @@ def makeDataContainer(shape: int | tuple[int, ...], datatype: DTypeLike | None =
220
217
  else:
221
218
  raise NotImplementedError("Somebody done broke it.")
222
219
 
223
- def outfitCountFolds(listDimensions: Sequence[int], computationDivisions: int | str | None = None, CPUlimit: bool | float | int | None = None, **keywordArguments: str | bool | None) -> computationState:
220
+ def outfitCountFolds(listDimensions: Sequence[int]
221
+ , computationDivisions: int | str | None = None
222
+ , CPUlimit: bool | float | int | None = None
223
+ ) -> computationState:
224
224
  """
225
225
  Initializes and configures the computation state for map folding computations.
226
226
 
@@ -228,40 +228,10 @@ def outfitCountFolds(listDimensions: Sequence[int], computationDivisions: int |
228
228
  listDimensions: The dimensions of the map to be folded
229
229
  computationDivisions (None): see `getTaskDivisions`
230
230
  CPUlimit (None): see `setCPUlimit`
231
- **keywordArguments: Datatype management, it's complicated: see the code below.
232
231
 
233
232
  Returns:
234
233
  stateInitialized: The initialized computation state
235
234
  """
236
- # keywordArguments START
237
- kwourGrapes = keywordArguments.get('sourGrapes', None)
238
- if kwourGrapes:
239
- sourGrapes = True
240
- else:
241
- sourGrapes = False
242
-
243
- ImaSetTheDatatype = keywordArguments.get('datatypeElephino', None)
244
- if ImaSetTheDatatype:
245
- ImaSetTheDatatype = str(ImaSetTheDatatype)
246
- setDatatypeElephino(ImaSetTheDatatype, sourGrapes)
247
-
248
- ImaSetTheDatatype = keywordArguments.get('datatypeFoldsTotal', None)
249
- if ImaSetTheDatatype:
250
- ImaSetTheDatatype = str(ImaSetTheDatatype)
251
- setDatatypeFoldsTotal(ImaSetTheDatatype, sourGrapes)
252
-
253
- ImaSetTheDatatype = keywordArguments.get('datatypeLeavesTotal', None)
254
- if ImaSetTheDatatype:
255
- ImaSetTheDatatype = str(ImaSetTheDatatype)
256
- setDatatypeLeavesTotal(ImaSetTheDatatype, sourGrapes)
257
-
258
- # NOTE well: this might be only hypothetical because as of this writing, `makeDataContainer` only makes numpy.zeros. But it's here in case things change.
259
- ImaSetTheDatatype = keywordArguments.get('datatypeModule', None)
260
- if ImaSetTheDatatype:
261
- ImaSetTheDatatype = str(ImaSetTheDatatype)
262
- setDatatypeModule(ImaSetTheDatatype, sourGrapes)
263
- # keywordArguments END
264
-
265
235
  my = makeDataContainer(len(indexMy), hackSSOTdtype('my'))
266
236
 
267
237
  mapShape = tuple(sorted(validateListDimensions(listDimensions)))
@@ -298,8 +268,8 @@ def parseDimensions(dimensions: Sequence[int], parameterName: str = 'listDimensi
298
268
  ValueError: If any dimension is negative or if the list is empty.
299
269
  TypeError: If any element cannot be converted to integer (raised by `intInnit`).
300
270
  """
301
- listValidated = intInnit(dimensions, parameterName)
302
- listNonNegative = []
271
+ listValidated: list[int] = intInnit(dimensions, parameterName)
272
+ listNonNegative: list[int] = []
303
273
  for dimension in listValidated:
304
274
  if dimension < 0:
305
275
  raise ValueError(f"Dimension {dimension} must be non-negative")
@@ -357,7 +327,7 @@ def setCPUlimit(CPUlimit: Any | None) -> int:
357
327
 
358
328
  concurrencyLimit = int(defineConcurrencyLimit(CPUlimit))
359
329
  set_num_threads(concurrencyLimit)
360
- concurrencyLimit = get_num_threads()
330
+ concurrencyLimit: int = get_num_threads()
361
331
 
362
332
  return concurrencyLimit
363
333
 
mapFolding/oeis.py CHANGED
@@ -1,8 +1,9 @@
1
1
  """Everything implementing the The Online Encyclopedia of Integer Sequences (OEIS); _only_ things that implement _only_ the OEIS."""
2
2
  from collections.abc import Callable
3
3
  from datetime import datetime, timedelta
4
- from mapFolding import countFolds, getPathPackage
5
- from typing import Any, Final, TYPE_CHECKING
4
+ from mapFolding import countFolds, pathPackage
5
+ from pathlib import Path
6
+ from typing import Any, cast, Final, TYPE_CHECKING
6
7
  import argparse
7
8
  import pathlib
8
9
  import random
@@ -22,7 +23,7 @@ cacheDays = 7
22
23
  """
23
24
  Section: make `settingsOEIS`"""
24
25
 
25
- _pathCache = getPathPackage() / ".cache"
26
+ pathCache: Path = pathPackage / ".cache"
26
27
 
27
28
  class SettingsOEIS(TypedDict):
28
29
  description: str
@@ -35,38 +36,37 @@ class SettingsOEIS(TypedDict):
35
36
  valueUnknown: int
36
37
 
37
38
  settingsOEIShardcodedValues: dict[str, dict[str, Any]] = {
38
- 'A001415': {
39
- 'getMapShape': lambda n: sorted([2, n]),
40
- 'valuesBenchmark': [14],
41
- 'valuesTestParallelization': [*range(3, 7)],
42
- 'valuesTestValidation': [random.randint(2, 9)],
43
- },
44
- 'A001416': {
45
- 'getMapShape': lambda n: sorted([3, n]),
46
- 'valuesBenchmark': [9],
47
- 'valuesTestParallelization': [*range(3, 5)],
48
- 'valuesTestValidation': [random.randint(2, 6)],
49
- },
50
- 'A001417': {
51
- 'getMapShape': lambda n: [2] * n,
52
- 'valuesBenchmark': [6],
53
- 'valuesTestParallelization': [*range(2, 4)],
54
- 'valuesTestValidation': [random.randint(2, 4)],
55
- },
56
- 'A195646': {
57
- 'getMapShape': lambda n: [3] * n,
58
- 'valuesBenchmark': [3],
59
- 'valuesTestParallelization': [*range(2, 3)],
60
- 'valuesTestValidation': [2],
61
- },
62
- 'A001418': {
63
- 'getMapShape': lambda n: [n, n],
64
- 'valuesBenchmark': [5],
65
- 'valuesTestParallelization': [*range(2, 4)],
66
- 'valuesTestValidation': [random.randint(2, 4)],
67
- },
39
+ 'A001415': {
40
+ 'getMapShape': cast(Callable[[int], list[int]], lambda n: sorted([2, n])), # type: ignore
41
+ 'valuesBenchmark': [14],
42
+ 'valuesTestParallelization': [*range(3, 7)],
43
+ 'valuesTestValidation': [random.randint(2, 9)],
44
+ },
45
+ 'A001416': {
46
+ 'getMapShape': cast(Callable[[int], list[int]], lambda n: sorted([3, n])), # type: ignore
47
+ 'valuesBenchmark': [9],
48
+ 'valuesTestParallelization': [*range(3, 5)],
49
+ 'valuesTestValidation': [random.randint(2, 6)],
50
+ },
51
+ 'A001417': {
52
+ 'getMapShape': cast(Callable[[int], list[int]], lambda n: [2] * n), # type: ignore
53
+ 'valuesBenchmark': [6],
54
+ 'valuesTestParallelization': [*range(2, 4)],
55
+ 'valuesTestValidation': [random.randint(2, 4)],
56
+ },
57
+ 'A195646': {
58
+ 'getMapShape': cast(Callable[[int], list[int]], lambda n: [3] * n), # type: ignore
59
+ 'valuesBenchmark': [3],
60
+ 'valuesTestParallelization': [*range(2, 3)],
61
+ 'valuesTestValidation': [2],
62
+ },
63
+ 'A001418': {
64
+ 'getMapShape': cast(Callable[[int], list[int]], lambda n: [n, n]), # type: ignore
65
+ 'valuesBenchmark': [5],
66
+ 'valuesTestParallelization': [*range(2, 4)],
67
+ 'valuesTestValidation': [random.randint(2, 4)],
68
+ },
68
69
  }
69
-
70
70
  oeisIDsImplemented: Final[list[str]] = sorted([oeisID.upper().strip() for oeisID in settingsOEIShardcodedValues.keys()])
71
71
  """Directly implemented OEIS IDs; standardized, e.g., 'A001415'."""
72
72
 
@@ -91,7 +91,7 @@ def validateOEISid(oeisIDcandidate: str) -> str:
91
91
  if oeisIDcandidate in oeisIDsImplemented:
92
92
  return oeisIDcandidate
93
93
  else:
94
- oeisIDcleaned = str(oeisIDcandidate).upper().strip()
94
+ oeisIDcleaned: str = str(oeisIDcandidate).upper().strip()
95
95
  if oeisIDcleaned in oeisIDsImplemented:
96
96
  return oeisIDcleaned
97
97
  else:
@@ -123,12 +123,12 @@ def _parseBFileOEIS(OEISbFile: str, oeisID: str) -> dict[int, int]:
123
123
  ValueError: If the first line of the file does not indicate the expected
124
124
  sequence ID or if the content format is invalid.
125
125
  """
126
- bFileLines = OEISbFile.strip().splitlines()
126
+ bFileLines: list[str] = OEISbFile.strip().splitlines()
127
127
  if not bFileLines.pop(0).startswith(f"# {oeisID}"):
128
128
  warnings.warn(f"Content does not match sequence {oeisID}")
129
129
  return {-1: -1}
130
130
 
131
- OEISsequence = {}
131
+ OEISsequence: dict[int, int] = {}
132
132
  for line in bFileLines:
133
133
  if line.startswith('#'):
134
134
  continue
@@ -139,10 +139,10 @@ def _parseBFileOEIS(OEISbFile: str, oeisID: str) -> dict[int, int]:
139
139
  def getOEISofficial(pathFilenameCache: pathlib.Path, url: str) -> None | str:
140
140
  tryCache = False
141
141
  if pathFilenameCache.exists():
142
- fileAge = datetime.now() - datetime.fromtimestamp(pathFilenameCache.stat().st_mtime)
143
- tryCache = fileAge < timedelta(days=cacheDays)
142
+ fileAge: timedelta = datetime.now() - datetime.fromtimestamp(pathFilenameCache.stat().st_mtime)
143
+ tryCache: bool = fileAge < timedelta(days=cacheDays)
144
144
 
145
- oeisInformation = None
145
+ oeisInformation: str | None = None
146
146
  if tryCache:
147
147
  try:
148
148
  oeisInformation = pathFilenameCache.read_text()
@@ -179,10 +179,10 @@ def getOEISidValues(oeisID: str) -> dict[int, int]:
179
179
  IOError: If there is an error reading from or writing to the local cache.
180
180
  """
181
181
 
182
- pathFilenameCache = _pathCache / getFilenameOEISbFile(oeisID)
183
- url = f"https://oeis.org/{oeisID}/{getFilenameOEISbFile(oeisID)}"
182
+ pathFilenameCache: Path = pathCache / getFilenameOEISbFile(oeisID)
183
+ url: str = f"https://oeis.org/{oeisID}/{getFilenameOEISbFile(oeisID)}"
184
184
 
185
- oeisInformation = getOEISofficial(pathFilenameCache, url)
185
+ oeisInformation: None | str = getOEISofficial(pathFilenameCache, url)
186
186
 
187
187
  if oeisInformation:
188
188
  return _parseBFileOEIS(oeisInformation, oeisID)
@@ -190,40 +190,37 @@ def getOEISidValues(oeisID: str) -> dict[int, int]:
190
190
 
191
191
  def getOEISidInformation(oeisID: str) -> tuple[str, int]:
192
192
  oeisID = validateOEISid(oeisID)
193
- pathFilenameCache = _pathCache / f"{oeisID}.txt"
194
- url = f"https://oeis.org/search?q=id:{oeisID}&fmt=text"
193
+ pathFilenameCache: Path = pathCache / f"{oeisID}.txt"
194
+ url: str = f"https://oeis.org/search?q=id:{oeisID}&fmt=text"
195
195
 
196
- oeisInformation = getOEISofficial(pathFilenameCache, url)
196
+ oeisInformation: None | str = getOEISofficial(pathFilenameCache, url)
197
197
 
198
198
  if not oeisInformation:
199
199
  return "Not found", -1
200
200
 
201
- description_parts = []
201
+ listDescriptionDeconstructed: list[str] = []
202
202
  offset = None
203
- for line in oeisInformation.splitlines():
204
- if line.startswith('%N'):
205
- parts = line.split()
206
- if parts[1] == oeisID:
207
- desc_part = ' '.join(parts[2:])
208
- description_parts.append(desc_part)
209
- elif line.startswith('%O'):
210
- parts = line.split()
211
- if parts[1] == oeisID:
212
- offset_str = parts[2].split(',')[0]
213
- offset = int(offset_str)
214
- if not description_parts:
203
+ for ImaStr in oeisInformation.splitlines():
204
+ ImaStr = ImaStr.strip() + "I am writing code to string parse machine readable data because in 2025, people can't even spell enteroperableity."
205
+ secretCode, title, secretData =ImaStr.split(maxsplit=2)
206
+ if secretCode == '%N' and title == oeisID:
207
+ listDescriptionDeconstructed.append(secretData)
208
+ if secretCode == '%O' and title == oeisID:
209
+ offsetAsStr: str = secretData.split(',')[0]
210
+ offset = int(offsetAsStr)
211
+ if not listDescriptionDeconstructed:
215
212
  warnings.warn(f"No description found for {oeisID}")
216
- description_parts.append("No description found")
213
+ listDescriptionDeconstructed.append("No description found")
217
214
  if offset is None:
218
215
  warnings.warn(f"No offset found for {oeisID}")
219
216
  offset = -1
220
- description = ' '.join(description_parts)
217
+ description: str = ' '.join(listDescriptionDeconstructed)
221
218
  return description, offset
222
219
 
223
220
  def makeSettingsOEIS() -> dict[str, SettingsOEIS]:
224
- settingsTarget = {}
221
+ settingsTarget: dict[str, SettingsOEIS] = {}
225
222
  for oeisID in oeisIDsImplemented:
226
- valuesKnownSherpa = getOEISidValues(oeisID)
223
+ valuesKnownSherpa: dict[int, int] = getOEISidValues(oeisID)
227
224
  descriptionSherpa, offsetSherpa = getOEISidInformation(oeisID)
228
225
  settingsTarget[oeisID] = SettingsOEIS(
229
226
  description=descriptionSherpa,
@@ -245,8 +242,8 @@ Section: private functions"""
245
242
 
246
243
  def _formatHelpText() -> str:
247
244
  """Format standardized help text for both CLI and interactive use."""
248
- exampleOEISid = oeisIDsImplemented[0]
249
- exampleN = settingsOEIS[exampleOEISid]['valuesTestValidation'][-1]
245
+ exampleOEISid: str = oeisIDsImplemented[0]
246
+ exampleN: int = settingsOEIS[exampleOEISid]['valuesTestValidation'][-1]
250
247
 
251
248
  return (
252
249
  "\nAvailable OEIS sequences:\n"
@@ -269,7 +266,7 @@ def _formatOEISsequenceInfo() -> str:
269
266
  """
270
267
  Section: public functions"""
271
268
 
272
- def oeisIDfor_n(oeisID: str, n: int) -> int:
269
+ def oeisIDfor_n(oeisID: str, n: int | Any) -> int:
273
270
  """
274
271
  Calculate a(n) of a sequence from "The On-Line Encyclopedia of Integer Sequences" (OEIS).
275
272
 
@@ -292,10 +289,10 @@ def oeisIDfor_n(oeisID: str, n: int) -> int:
292
289
  listDimensions: list[int] = settingsOEIS[oeisID]['getMapShape'](n)
293
290
 
294
291
  if n <= 1 or len(listDimensions) < 2:
295
- offset = settingsOEIS[oeisID]['offset']
292
+ offset: int = settingsOEIS[oeisID]['offset']
296
293
  if n < offset:
297
294
  raise ArithmeticError(f"OEIS sequence {oeisID} is not defined at n={n}.")
298
- foldsTotal = settingsOEIS[oeisID]['valuesKnown'][n]
295
+ foldsTotal: int = settingsOEIS[oeisID]['valuesKnown'][n]
299
296
  return foldsTotal
300
297
 
301
298
  return countFolds(listDimensions)
@@ -320,18 +317,18 @@ def OEIS_for_n() -> None:
320
317
  print(f"Error: {ERRORmessage}", file=sys.stderr)
321
318
  sys.exit(1)
322
319
 
323
- timeElapsed = time.perf_counter() - timeStart
320
+ timeElapsed: float = time.perf_counter() - timeStart
324
321
  print(f"Time elapsed: {timeElapsed:.3f} seconds")
325
322
 
326
323
  def clearOEIScache() -> None:
327
324
  """Delete all cached OEIS sequence files."""
328
- if not _pathCache.exists():
329
- print(f"Cache directory, {_pathCache}, not found - nothing to clear.")
325
+ if not pathCache.exists():
326
+ print(f"Cache directory, {pathCache}, not found - nothing to clear.")
330
327
  return
331
328
  for oeisID in settingsOEIS:
332
- ( _pathCache / f"{oeisID}.txt" ).unlink(missing_ok=True)
333
- ( _pathCache / getFilenameOEISbFile(oeisID) ).unlink(missing_ok=True)
334
- print(f"Cache cleared from {_pathCache}")
329
+ ( pathCache / f"{oeisID}.txt" ).unlink(missing_ok=True)
330
+ ( pathCache / getFilenameOEISbFile(oeisID) ).unlink(missing_ok=True)
331
+ print(f"Cache cleared from {pathCache}")
335
332
 
336
333
  def getOEISids() -> None:
337
334
  """Print all available OEIS sequence IDs that are directly implemented."""
@@ -0,0 +1,58 @@
1
+ from types import ModuleType
2
+ from mapFolding.theWrongWay import *
3
+ from sys import modules as sysModules
4
+ from pathlib import Path
5
+ from importlib import import_module as importlib_import_module
6
+ from inspect import getfile as inspect_getfile
7
+ from typing import Final
8
+ """
9
+ evaluateWhenPACKAGING
10
+ evaluateWhenINSTALLING
11
+ """
12
+ try:
13
+ import tomli
14
+ TRYmyPackageNameIs: str = tomli.load(Path("../pyproject.toml").open('rb'))["project"]["name"]
15
+ except Exception:
16
+ TRYmyPackageNameIs: str = myPackageNameIsPACKAGING
17
+
18
+ myPackageNameIs: Final[str] = TRYmyPackageNameIs
19
+
20
+ def getPathPackageINSTALLING() -> Path:
21
+ pathPackage = Path(inspect_getfile(importlib_import_module(myPackageNameIs)))
22
+ if pathPackage.is_file():
23
+ pathPackage: Path = pathPackage.parent
24
+ return pathPackage
25
+
26
+ pathPackage: Path = getPathPackageINSTALLING()
27
+
28
+ moduleOfSyntheticModules: Final[str] = "syntheticModules"
29
+ formatNameModule = "numba_{callableTarget}"
30
+ formatFilenameModule = formatNameModule + ".py"
31
+ dispatcherCallableName = "doTheNeedful"
32
+ nameModuleDispatcher: str = formatNameModule.format(callableTarget=dispatcherCallableName)
33
+ Z0Z_filenameModuleWrite = 'numbaCount.py'
34
+ Z0Z_filenameWriteElseCallableTarget: str = 'count'
35
+
36
+ def getDispatcherCallable():
37
+ logicalPathModule: str = f"{myPackageNameIs}.{moduleOfSyntheticModules}.{nameModuleDispatcher}"
38
+ moduleImported: ModuleType = importlib_import_module(logicalPathModule)
39
+ return getattr(moduleImported, dispatcherCallableName)
40
+
41
+ def getAlgorithmSource() -> ModuleType:
42
+ logicalPathModule: str = f"{myPackageNameIs}.{algorithmSourcePACKAGING}"
43
+ moduleImported: ModuleType = importlib_import_module(logicalPathModule)
44
+ return moduleImported
45
+ # from mapFolding import theDao
46
+ # return theDao
47
+
48
+ # TODO learn how to see this from the user's perspective
49
+ def getPathJobRootDEFAULT() -> Path:
50
+ if 'google.colab' in sysModules:
51
+ pathJobDEFAULT: Path = Path("/content/drive/MyDrive") / "jobs"
52
+ else:
53
+ pathJobDEFAULT = pathPackage / "jobs"
54
+ return pathJobDEFAULT
55
+
56
+ listCallablesDispatchees: list[str] = listCallablesDispatcheesHARDCODED
57
+
58
+ additional_importsHARDCODED.append(myPackageNameIs)
mapFolding/theDao.py CHANGED
@@ -147,7 +147,7 @@ def countParallel(connectionGraph: ndarray[tuple[int, int, int], dtype[integer[A
147
147
 
148
148
  taskDivisionsPrange = myPARALLEL[indexMy.taskDivisions.value]
149
149
 
150
- for indexSherpa in prange(taskDivisionsPrange):
150
+ for indexSherpa in prange(taskDivisionsPrange): # type: ignore
151
151
  groupsOfFolds: int = 0
152
152
 
153
153
  gapsWhere = gapsWherePARALLEL.copy()