mapFolding 0.2.3__py3-none-any.whl → 0.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  from .theSSOT import *
2
2
  from Z0Z_tools import defineConcurrencyLimit, intInnit, oopsieKwargsie
3
- from .beDRY import getFilenameFoldsTotal, outfitCountFolds
3
+ from .beDRY import getFilenameFoldsTotal, getPathFilenameFoldsTotal, outfitCountFolds, saveFoldsTotal
4
4
  from .startHere import countFolds
5
5
  from .oeis import oeisIDfor_n, getOEISids, clearOEIScache
6
6
 
mapFolding/babbage.py CHANGED
@@ -1,4 +1,5 @@
1
- from mapFolding.lovelace import countFoldsCompiled
1
+ from mapFolding.importSelector import countSequential, countParallel, countInitialize
2
+ from mapFolding import indexThe
2
3
  from numpy import integer
3
4
  from numpy.typing import NDArray
4
5
  from typing import Any, Tuple
@@ -25,6 +26,10 @@ def _countFolds(connectionGraph: NDArray[integer[Any]], foldsSubTotals: NDArray[
25
26
  - and just a few dozen-jillion other things.
26
27
 
27
28
  """
28
- # TODO learn if I really must change this jitted function to get the super jit to recompile
29
- # print('babbage')
30
- countFoldsCompiled(connectionGraph=connectionGraph, foldsSubTotals=foldsSubTotals, gapsWhere=gapsWhere, my=my, the=the, track=track)
29
+ # print("babbage")
30
+ countInitialize(connectionGraph=connectionGraph, gapsWhere=gapsWhere, my=my, the=the, track=track)
31
+
32
+ if the[indexThe.taskDivisions.value] > 0:
33
+ countParallel(connectionGraph=connectionGraph, foldsSubTotals=foldsSubTotals, gapsWherePARALLEL=gapsWhere, myPARALLEL=my, the=the, trackPARALLEL=track)
34
+ else:
35
+ countSequential(connectionGraph=connectionGraph, foldsSubTotals=foldsSubTotals, gapsWhere=gapsWhere, my=my, the=the, track=track)
mapFolding/beDRY.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """A relatively stable API for oft-needed functionality."""
2
- from mapFolding import dtypeDefault, dtypeLarge
2
+ from mapFolding import dtypeDefault, dtypeLarge, pathJobDEFAULT
3
3
  from mapFolding import indexMy, indexThe, indexTrack, computationState
4
4
  from mapFolding import intInnit, defineConcurrencyLimit, oopsieKwargsie
5
5
  from numpy import integer
@@ -7,10 +7,12 @@ from numpy.typing import NDArray
7
7
  from typing import Any, List, Optional, Sequence, Type, Union
8
8
  import numba
9
9
  import numpy
10
+ import os
11
+ import pathlib
10
12
  import sys
11
13
 
12
14
  def getFilenameFoldsTotal(listDimensions: Sequence[int]) -> str:
13
- return str(sorted(listDimensions)).replace(' ', '') + '.foldsTotal'
15
+ return str(sorted(listDimensions)).replace(', ', 'x') + '.foldsTotal'
14
16
 
15
17
  def getLeavesTotal(listDimensions: Sequence[int]) -> int:
16
18
  """
@@ -36,6 +38,14 @@ def getLeavesTotal(listDimensions: Sequence[int]) -> int:
36
38
 
37
39
  return productDimensions
38
40
 
41
+ def getPathFilenameFoldsTotal(listDimensions: Sequence[int], pathishWriteFoldsTotal: Optional[Union[str, os.PathLike[str]]] = None) -> pathlib.Path:
42
+ pathFilenameFoldsTotal = pathlib.Path(pathishWriteFoldsTotal) if pathishWriteFoldsTotal is not None else pathJobDEFAULT
43
+ if pathFilenameFoldsTotal.is_dir():
44
+ filenameFoldsTotalDEFAULT = getFilenameFoldsTotal(listDimensions)
45
+ pathFilenameFoldsTotal = pathFilenameFoldsTotal / filenameFoldsTotalDEFAULT
46
+ pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
47
+ return pathFilenameFoldsTotal
48
+
39
49
  def getTaskDivisions(computationDivisions: Optional[Union[int, str]], concurrencyLimit: int, CPUlimit: Optional[Union[bool, float, int]], listDimensions: Sequence[int]):
40
50
  """
41
51
  Determines whether or how to divide the computation into tasks.
@@ -148,7 +158,7 @@ def makeDataContainer(shape, datatype: Optional[Type] = None):
148
158
  datatype = dtypeDefault
149
159
  return numpy.zeros(shape, dtype=datatype)
150
160
 
151
- def outfitCountFolds(listDimensions: Sequence[int], computationDivisions: Optional[Union[int, str]] = None, CPUlimit: Optional[Union[bool, float, int]] = None, **keywordArguments: Optional[Type]) -> computationState:
161
+ def outfitCountFolds(listDimensions: Sequence[int], computationDivisions: Optional[Union[int, str]] = None, CPUlimit: Optional[Union[bool, float, int]] = None, **keywordArguments: Optional[Type[Any]]) -> computationState:
152
162
  """
153
163
  Initializes and configures the computation state for map folding computations.
154
164
 
@@ -230,11 +240,42 @@ def parseDimensions(dimensions: Sequence[int], parameterName: str = 'unnamed par
230
240
  raise ValueError(f"Dimension {dimension} must be non-negative")
231
241
  listNonNegative.append(dimension)
232
242
 
233
- if not listNonNegative:
234
- raise ValueError("At least one dimension must be non-negative")
235
-
236
243
  return listNonNegative
237
244
 
245
+ import tempfile
246
+ import shutil
247
+ import logging
248
+ import os
249
+ def saveFoldsTotal(pathFilename: Union[str, os.PathLike[str]], foldsTotal: int) -> None:
250
+ """
251
+ Save foldsTotal with multiple fallback mechanisms.
252
+
253
+ Parameters:
254
+ pathFilename: Target save location
255
+ foldsTotal: Critical computed value to save
256
+ """
257
+ """Thoughts
258
+ Everything in a try block
259
+ Save it multiple times with multiple packages
260
+ no need for context managers, especially because they can cause errors"""
261
+ try:
262
+ pathFilenameFoldsTotal = pathlib.Path(pathFilename)
263
+ pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
264
+ pathFilenameFoldsTotal.write_text(str(foldsTotal))
265
+ except Exception as ERRORmessage:
266
+ try:
267
+ print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
268
+ print(ERRORmessage)
269
+ print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
270
+ randomnessPlanB = (int(str(foldsTotal).strip()[-1]) + 1) * ['YO_']
271
+ filenameInfixUnique = ''.join(randomnessPlanB)
272
+ import os
273
+ pathFilenamePlanB = os.path.join(os.getcwd(), 'foldsTotal' + filenameInfixUnique + '.txt')
274
+ open(pathFilenamePlanB, 'w').write(str(foldsTotal))
275
+ print(str(pathFilenamePlanB))
276
+ except:
277
+ print(foldsTotal)
278
+
238
279
  def setCPUlimit(CPUlimit: Union[bool, float, int, None]) -> int:
239
280
  """Sets CPU limit for Numba concurrent operations. Note that it can only affect Numba-jitted functions that have not yet been imported.
240
281
 
@@ -1,5 +1,6 @@
1
- import multiprocessing
1
+ """An incompetent benchmarking module for mapFolding."""
2
2
  from typing import Callable
3
+ import multiprocessing
3
4
  import numpy
4
5
  import pathlib
5
6
  import time
@@ -57,7 +58,7 @@ def runBenchmarks(benchmarkIterations: int = 30) -> None:
57
58
  listCartesianProduct = list(itertools.product(listParametersOEIS, range(benchmarkIterations)))
58
59
  with ProcessPoolExecutor(max_workers) as concurrencyManager:
59
60
  listConcurrency = [concurrencyManager.submit(oeisIDfor_n, *parameters[0]) for parameters in listCartesianProduct]
60
- for complete in tqdm(as_completed(listConcurrency), total=len(listCartesianProduct)):
61
+ for _complete in tqdm(as_completed(listConcurrency), total=len(listCartesianProduct)):
61
62
  pass
62
63
 
63
64
  if __name__ == '__main__':
@@ -0,0 +1,7 @@
1
+ from mapFolding.lovelace import countSequential
2
+ from mapFolding.lovelace import countParallel
3
+ from mapFolding.lovelace import countInitialize
4
+
5
+ # from mapFolding.countSequential import countSequential
6
+ # from mapFolding.countParallel import countParallel
7
+ # from mapFolding.countInitialize import countInitialize
mapFolding/lovelace.py CHANGED
@@ -1,100 +1,118 @@
1
1
  from mapFolding import indexMy, indexThe, indexTrack
2
- from numpy import integer
3
- from numpy.typing import NDArray
4
- from typing import Any
5
2
  import numba
6
- import numpy
7
3
 
8
- def activeGapIncrement(my: NDArray[integer[Any]]):
4
+ @numba.jit((numba.int64[::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
5
+ def activeGapIncrement(my):
9
6
  my[indexMy.gap1ndex.value] += 1
10
7
 
11
- def activeLeafGreaterThan0Condition(my: NDArray[integer[Any]]):
8
+ @numba.jit((numba.int64[::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
9
+ def activeLeafGreaterThan0Condition(my):
12
10
  return my[indexMy.leaf1ndex.value] > 0
13
11
 
14
- def activeLeafGreaterThanLeavesTotalCondition(my: NDArray[integer[Any]], the: NDArray[integer[Any]]):
12
+ @numba.jit((numba.int64[::1],numba.int64[::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
13
+ def activeLeafGreaterThanLeavesTotalCondition(my, the):
15
14
  return my[indexMy.leaf1ndex.value] > the[indexThe.leavesTotal.value]
16
15
 
17
- def activeLeafIsTheFirstLeafCondition(my: NDArray[integer[Any]]):
16
+ @numba.jit((numba.int64[::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
17
+ def activeLeafIsTheFirstLeafCondition(my):
18
18
  return my[indexMy.leaf1ndex.value] <= 1
19
19
 
20
- def activeLeafNotEqualToTaskDivisionsCondition(my: NDArray[integer[Any]], the: NDArray[integer[Any]]):
21
- return my[indexMy.leaf1ndex.value] != the[indexThe.taskDivisions.value]
22
-
23
- def allDimensionsAreUnconstrained(my: NDArray[integer[Any]], the: NDArray[integer[Any]]):
20
+ @numba.jit((numba.int64[::1],numba.int64[::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
21
+ def allDimensionsAreUnconstrained(my, the):
24
22
  return my[indexMy.dimensionsUnconstrained.value] == the[indexThe.dimensionsTotal.value]
25
23
 
26
- def backtrack(my: NDArray[integer[Any]], track: NDArray[integer[Any]]):
24
+ @numba.jit((numba.int64[::1],numba.int64[:,::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
25
+ def backtrack(my, track):
27
26
  my[indexMy.leaf1ndex.value] -= 1
28
27
  track[indexTrack.leafBelow.value, track[indexTrack.leafAbove.value, my[indexMy.leaf1ndex.value]]] = track[indexTrack.leafBelow.value, my[indexMy.leaf1ndex.value]]
29
28
  track[indexTrack.leafAbove.value, track[indexTrack.leafBelow.value, my[indexMy.leaf1ndex.value]]] = track[indexTrack.leafAbove.value, my[indexMy.leaf1ndex.value]]
30
29
 
31
- def backtrackCondition(my: NDArray[integer[Any]], track: NDArray[integer[Any]]):
30
+ @numba.jit((numba.int64[::1],numba.int64[:,::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
31
+ def backtrackCondition(my, track):
32
32
  return my[indexMy.leaf1ndex.value] > 0 and my[indexMy.gap1ndex.value] == track[indexTrack.gapRangeStart.value, my[indexMy.leaf1ndex.value] - 1]
33
33
 
34
- def countGaps(gapsWhere: NDArray[integer[Any]], my: NDArray[integer[Any]], track: NDArray[integer[Any]]):
34
+ @numba.jit((numba.int64[::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
35
+ def gap1ndexCeilingIncrement(my):
36
+ my[indexMy.gap1ndexCeiling.value] += 1
37
+
38
+ @numba.jit((numba.int64[::1],numba.int64[::1],numba.int64[:,::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
39
+ def countGaps(gapsWhere, my, track):
35
40
  gapsWhere[my[indexMy.gap1ndexCeiling.value]] = my[indexMy.leafConnectee.value]
36
41
  if track[indexTrack.countDimensionsGapped.value, my[indexMy.leafConnectee.value]] == 0:
37
42
  gap1ndexCeilingIncrement(my=my)
38
43
  track[indexTrack.countDimensionsGapped.value, my[indexMy.leafConnectee.value]] += 1
39
44
 
40
- def dimension1ndexIncrement(my: NDArray[integer[Any]]):
45
+ @numba.jit((numba.int64[::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
46
+ def dimension1ndexIncrement(my):
41
47
  my[indexMy.dimension1ndex.value] += 1
42
48
 
43
- def dimensionsUnconstrainedCondition(connectionGraph: NDArray[integer[Any]], my: NDArray[integer[Any]]):
49
+ @numba.jit((numba.int64[:,:,::1], numba.int64[::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
50
+ def dimensionsUnconstrainedCondition(connectionGraph, my):
44
51
  return connectionGraph[my[indexMy.dimension1ndex.value], my[indexMy.leaf1ndex.value], my[indexMy.leaf1ndex.value]] == my[indexMy.leaf1ndex.value]
45
52
 
46
- def dimensionsUnconstrainedIncrement(my: NDArray[integer[Any]]):
53
+ @numba.jit((numba.int64[::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
54
+ def dimensionsUnconstrainedIncrement(my):
47
55
  my[indexMy.dimensionsUnconstrained.value] += 1
48
56
 
49
- def filterCommonGaps(gapsWhere: NDArray[integer[Any]], my: NDArray[integer[Any]], the: NDArray[integer[Any]], track: NDArray[integer[Any]]):
57
+ @numba.jit((numba.int64[::1],numba.int64[::1],numba.int64[::1],numba.int64[:,::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
58
+ def filterCommonGaps(gapsWhere, my, the, track):
50
59
  gapsWhere[my[indexMy.gap1ndex.value]] = gapsWhere[my[indexMy.indexMiniGap.value]]
51
60
  if track[indexTrack.countDimensionsGapped.value, gapsWhere[my[indexMy.indexMiniGap.value]]] == the[indexThe.dimensionsTotal.value] - my[indexMy.dimensionsUnconstrained.value]:
52
61
  activeGapIncrement(my=my)
53
62
  track[indexTrack.countDimensionsGapped.value, gapsWhere[my[indexMy.indexMiniGap.value]]] = 0
54
63
 
55
- def findGapsInitializeVariables(my: NDArray[integer[Any]], track: NDArray[integer[Any]]):
64
+ @numba.jit((numba.int64[::1],numba.int64[:,::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
65
+ def findGapsInitializeVariables(my, track):
56
66
  my[indexMy.dimensionsUnconstrained.value] = 0
57
67
  my[indexMy.gap1ndexCeiling.value] = track[indexTrack.gapRangeStart.value, my[indexMy.leaf1ndex.value] - 1]
58
68
  my[indexMy.dimension1ndex.value] = 1
59
69
 
60
- def foldsSubTotalIncrement(foldsSubTotals: NDArray[integer[Any]], my: NDArray[integer[Any]], the: NDArray[integer[Any]]):
70
+ @numba.jit((numba.int64[::1],numba.int64[::1],numba.int64[::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
71
+ def foldsSubTotalIncrement(foldsSubTotals, my, the):
61
72
  foldsSubTotals[my[indexMy.taskIndex.value]] += the[indexThe.leavesTotal.value]
62
73
 
63
- def gap1ndexCeilingIncrement(my: NDArray[integer[Any]]):
64
- my[indexMy.gap1ndexCeiling.value] += 1
65
-
66
- def indexMiniGapIncrement(my: NDArray[integer[Any]]):
74
+ @numba.jit((numba.int64[::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
75
+ def indexMiniGapIncrement(my):
67
76
  my[indexMy.indexMiniGap.value] += 1
68
77
 
69
- def indexMiniGapInitialization(my: NDArray[integer[Any]]):
78
+ @numba.jit((numba.int64[::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
79
+ def indexMiniGapInitialization(my):
70
80
  my[indexMy.indexMiniGap.value] = my[indexMy.gap1ndex.value]
71
81
 
72
- def insertUnconstrainedLeaf(gapsWhere: NDArray[integer[Any]], my: NDArray[integer[Any]]):
82
+ @numba.jit((numba.int64[::1],numba.int64[::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
83
+ def insertUnconstrainedLeaf(gapsWhere, my):
73
84
  my[indexMy.indexLeaf.value] = 0
74
85
  while my[indexMy.indexLeaf.value] < my[indexMy.leaf1ndex.value]:
75
86
  gapsWhere[my[indexMy.gap1ndexCeiling.value]] = my[indexMy.indexLeaf.value]
76
87
  my[indexMy.gap1ndexCeiling.value] += 1
77
88
  my[indexMy.indexLeaf.value] += 1
78
89
 
79
- def leafBelowSentinelIs1Condition(track: NDArray[integer[Any]]):
90
+ @numba.jit((numba.int64[:,::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
91
+ def leafBelowSentinelIs1Condition(track):
80
92
  return track[indexTrack.leafBelow.value, 0] == 1
81
93
 
82
- def leafConnecteeInitialization(connectionGraph: NDArray[integer[Any]], my: NDArray[integer[Any]]):
94
+ @numba.jit((numba.int64[:,:,::1], numba.int64[::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
95
+ def leafConnecteeInitialization(connectionGraph, my):
83
96
  my[indexMy.leafConnectee.value] = connectionGraph[my[indexMy.dimension1ndex.value], my[indexMy.leaf1ndex.value], my[indexMy.leaf1ndex.value]]
84
97
 
85
- def leafConnecteeUpdate(connectionGraph: NDArray[integer[Any]], my: NDArray[integer[Any]], track: NDArray[integer[Any]]):
98
+ @numba.jit((numba.int64[:,:,::1], numba.int64[::1],numba.int64[:,::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
99
+ def leafConnecteeUpdate(connectionGraph, my, track):
86
100
  my[indexMy.leafConnectee.value] = connectionGraph[my[indexMy.dimension1ndex.value], my[indexMy.leaf1ndex.value], track[indexTrack.leafBelow.value, my[indexMy.leafConnectee.value]]]
87
101
 
88
- def loopingLeavesConnectedToActiveLeaf(my: NDArray[integer[Any]]):
102
+ @numba.jit((numba.int64[::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
103
+ def loopingLeavesConnectedToActiveLeaf(my):
89
104
  return my[indexMy.leafConnectee.value] != my[indexMy.leaf1ndex.value]
90
105
 
91
- def loopingTheDimensions(my: NDArray[integer[Any]], the: NDArray[integer[Any]]):
106
+ @numba.jit((numba.int64[::1],numba.int64[::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
107
+ def loopingTheDimensions(my, the):
92
108
  return my[indexMy.dimension1ndex.value] <= the[indexThe.dimensionsTotal.value]
93
109
 
94
- def loopingToActiveGapCeiling(my: NDArray[integer[Any]]):
110
+ @numba.jit((numba.int64[::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
111
+ def loopingToActiveGapCeiling(my):
95
112
  return my[indexMy.indexMiniGap.value] < my[indexMy.gap1ndexCeiling.value]
96
113
 
97
- def placeLeaf(gapsWhere: NDArray[integer[Any]], my: NDArray[integer[Any]], track: NDArray[integer[Any]]):
114
+ @numba.jit((numba.int64[::1],numba.int64[::1],numba.int64[:,::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
115
+ def placeLeaf(gapsWhere, my, track):
98
116
  my[indexMy.gap1ndex.value] -= 1
99
117
  track[indexTrack.leafAbove.value, my[indexMy.leaf1ndex.value]] = gapsWhere[my[indexMy.gap1ndex.value]]
100
118
  track[indexTrack.leafBelow.value, my[indexMy.leaf1ndex.value]] = track[indexTrack.leafBelow.value, track[indexTrack.leafAbove.value, my[indexMy.leaf1ndex.value]]]
@@ -103,20 +121,16 @@ def placeLeaf(gapsWhere: NDArray[integer[Any]], my: NDArray[integer[Any]], track
103
121
  track[indexTrack.gapRangeStart.value, my[indexMy.leaf1ndex.value]] = my[indexMy.gap1ndex.value]
104
122
  my[indexMy.leaf1ndex.value] += 1
105
123
 
106
- def placeLeafCondition(my: NDArray[integer[Any]]):
124
+ @numba.jit((numba.int64[::1],), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
125
+ def placeLeafCondition(my):
107
126
  return my[indexMy.leaf1ndex.value] > 0
108
127
 
109
- def taskIndexCondition(my: NDArray[integer[Any]], the: NDArray[integer[Any]]):
110
- return my[indexMy.leafConnectee.value] % the[indexThe.taskDivisions.value] == my[indexMy.taskIndex.value]
128
+ @numba.jit((numba.int64[::1],numba.int64[::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
129
+ def thereAreComputationDivisionsYouMightSkip(my, the):
130
+ return my[indexMy.leaf1ndex.value] != the[indexThe.taskDivisions.value] or my[indexMy.leafConnectee.value] % the[indexThe.taskDivisions.value] == my[indexMy.taskIndex.value]
111
131
 
112
- def thereAreComputationDivisionsYouMightSkip(my: NDArray[integer[Any]], the: NDArray[integer[Any]]):
113
- if activeLeafNotEqualToTaskDivisionsCondition(my=my, the=the):
114
- return True
115
- if taskIndexCondition(my=my, the=the):
116
- return True
117
- return False
118
-
119
- def initialize(connectionGraph: NDArray[integer[Any]], gapsWhere: NDArray[integer[Any]], my: NDArray[integer[Any]], the: NDArray[integer[Any]], track: NDArray[integer[Any]]):
132
+ @numba.jit((numba.int64[:,:,::1], numba.int64[::1], numba.int64[::1], numba.int64[::1], numba.int64[:,::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
133
+ def countInitialize(connectionGraph, gapsWhere, my, the, track):
120
134
  while activeLeafGreaterThan0Condition(my=my):
121
135
  if activeLeafIsTheFirstLeafCondition(my=my) or leafBelowSentinelIs1Condition(track=track):
122
136
  findGapsInitializeVariables(my=my, track=track)
@@ -138,35 +152,10 @@ def initialize(connectionGraph: NDArray[integer[Any]], gapsWhere: NDArray[intege
138
152
  if placeLeafCondition(my=my):
139
153
  placeLeaf(gapsWhere=gapsWhere, my=my, track=track)
140
154
  if my[indexMy.gap1ndex.value] > 0:
141
- break
155
+ return
142
156
 
143
- def countParallel(connectionGraph: NDArray[integer[Any]], foldsSubTotals: NDArray[integer[Any]], gapsWhere: NDArray[integer[Any]], my: NDArray[integer[Any]], the: NDArray[integer[Any]], track: NDArray[integer[Any]]):
144
- while activeLeafGreaterThan0Condition(my=my):
145
- if activeLeafIsTheFirstLeafCondition(my=my) or leafBelowSentinelIs1Condition(track=track):
146
- if activeLeafGreaterThanLeavesTotalCondition(my=my, the=the):
147
- foldsSubTotalIncrement(foldsSubTotals=foldsSubTotals, my=my, the=the)
148
- else:
149
- findGapsInitializeVariables(my=my, track=track)
150
- while loopingTheDimensions(my=my, the=the):
151
- if dimensionsUnconstrainedCondition(connectionGraph=connectionGraph, my=my):
152
- dimensionsUnconstrainedIncrement(my=my)
153
- else:
154
- leafConnecteeInitialization(connectionGraph=connectionGraph, my=my)
155
- while loopingLeavesConnectedToActiveLeaf(my=my):
156
- if thereAreComputationDivisionsYouMightSkip(my=my, the=the):
157
- countGaps(gapsWhere=gapsWhere, my=my, track=track)
158
- leafConnecteeUpdate(connectionGraph=connectionGraph, my=my, track=track)
159
- dimension1ndexIncrement(my=my)
160
- indexMiniGapInitialization(my=my)
161
- while loopingToActiveGapCeiling(my=my):
162
- filterCommonGaps(gapsWhere=gapsWhere, my=my, the=the, track=track)
163
- indexMiniGapIncrement(my=my)
164
- while backtrackCondition(my=my, track=track):
165
- backtrack(my=my, track=track)
166
- if placeLeafCondition(my=my):
167
- placeLeaf(gapsWhere=gapsWhere, my=my, track=track)
168
-
169
- def countSequential(connectionGraph: NDArray[integer[Any]], foldsSubTotals: NDArray[integer[Any]], gapsWhere: NDArray[integer[Any]], my: NDArray[integer[Any]], the: NDArray[integer[Any]], track: NDArray[integer[Any]]):
157
+ @numba.jit((numba.int64[:,:,::1], numba.int64[::1], numba.int64[::1], numba.int64[::1], numba.int64[::1], numba.int64[:,::1]), parallel=False, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
158
+ def countSequential(connectionGraph, foldsSubTotals, gapsWhere, my, the, track):
170
159
  while activeLeafGreaterThan0Condition(my=my):
171
160
  if activeLeafIsTheFirstLeafCondition(my=my) or leafBelowSentinelIs1Condition(track=track):
172
161
  if activeLeafGreaterThanLeavesTotalCondition(my=my, the=the):
@@ -191,27 +180,34 @@ def countSequential(connectionGraph: NDArray[integer[Any]], foldsSubTotals: NDAr
191
180
  if placeLeafCondition(my=my):
192
181
  placeLeaf(gapsWhere=gapsWhere, my=my, track=track)
193
182
 
194
- @numba.jit(parallel=True, _nrt=True, boundscheck=False, error_model='numpy', fastmath=True, forceinline=True, looplift=False, no_cfunc_wrapper=True, no_cpython_wrapper=True, nogil=True, nopython=True)
195
- def doTaskIndices(connectionGraph: NDArray[integer[Any]], foldsSubTotals: NDArray[integer[Any]], gapsWhere: NDArray[integer[Any]], my: NDArray[integer[Any]], the: NDArray[integer[Any]], track: NDArray[integer[Any]]):
196
-
197
- stateGapsWhere = gapsWhere.copy()
198
- stateMy = my.copy()
199
- stateTrack = track.copy()
200
-
183
+ @numba.jit((numba.int64[:,:,::1], numba.int64[::1], numba.int64[::1],numba.int64[::1],numba.int64[::1],numba.int64[:,::1]), parallel=True, boundscheck=False, error_model='numpy', fastmath=True, looplift=False, nogil=True, nopython=True)
184
+ def countParallel(connectionGraph, foldsSubTotals, gapsWherePARALLEL, myPARALLEL, the, trackPARALLEL):
201
185
  for indexSherpa in numba.prange(the[indexThe.taskDivisions.value]):
202
- mySherpa = stateMy.copy()
203
- mySherpa[indexMy.taskIndex.value] = indexSherpa
204
- countParallel(connectionGraph=connectionGraph, foldsSubTotals=foldsSubTotals, gapsWhere=stateGapsWhere.copy(), my=mySherpa, the=the, track=stateTrack.copy())
205
-
206
- return foldsSubTotals
207
-
208
- def countFoldsCompiled(connectionGraph: NDArray[integer[Any]], foldsSubTotals: NDArray[integer[Any]], gapsWhere: NDArray[integer[Any]], my: NDArray[integer[Any]], the: NDArray[integer[Any]], track: NDArray[integer[Any]]):
209
-
210
- initialize(connectionGraph=connectionGraph, gapsWhere=gapsWhere, my=my, the=the, track=track)
211
-
212
- if the[indexThe.taskDivisions.value] > 0:
213
- doTaskIndices(connectionGraph=connectionGraph, foldsSubTotals=foldsSubTotals, gapsWhere=gapsWhere, my=my, the=the, track=track)
214
- else:
215
- countSequential(connectionGraph=connectionGraph, foldsSubTotals=foldsSubTotals, gapsWhere=gapsWhere, my=my, the=the, track=track)
216
-
217
- numba.jit_module(parallel=False, _nrt=True, boundscheck=False, error_model='numpy', fastmath=True, forceinline=True, looplift=False, no_cfunc_wrapper=True, no_cpython_wrapper=True, nogil=True, nopython=True)
186
+ gapsWhere = gapsWherePARALLEL.copy()
187
+ my = myPARALLEL.copy()
188
+ my[indexMy.taskIndex.value] = indexSherpa
189
+ track = trackPARALLEL.copy()
190
+ while activeLeafGreaterThan0Condition(my=my):
191
+ if activeLeafIsTheFirstLeafCondition(my=my) or leafBelowSentinelIs1Condition(track=track):
192
+ if activeLeafGreaterThanLeavesTotalCondition(my=my, the=the):
193
+ foldsSubTotalIncrement(foldsSubTotals=foldsSubTotals, my=my, the=the)
194
+ else:
195
+ findGapsInitializeVariables(my=my, track=track)
196
+ while loopingTheDimensions(my=my, the=the):
197
+ if dimensionsUnconstrainedCondition(connectionGraph=connectionGraph, my=my):
198
+ dimensionsUnconstrainedIncrement(my=my)
199
+ else:
200
+ leafConnecteeInitialization(connectionGraph=connectionGraph, my=my)
201
+ while loopingLeavesConnectedToActiveLeaf(my=my):
202
+ if thereAreComputationDivisionsYouMightSkip(my=my, the=the):
203
+ countGaps(gapsWhere=gapsWhere, my=my, track=track)
204
+ leafConnecteeUpdate(connectionGraph=connectionGraph, my=my, track=track)
205
+ dimension1ndexIncrement(my=my)
206
+ indexMiniGapInitialization(my=my)
207
+ while loopingToActiveGapCeiling(my=my):
208
+ filterCommonGaps(gapsWhere=gapsWhere, my=my, the=the, track=track)
209
+ indexMiniGapIncrement(my=my)
210
+ while backtrackCondition(my=my, track=track):
211
+ backtrack(my=my, track=track)
212
+ if placeLeafCondition(my=my):
213
+ placeLeaf(gapsWhere=gapsWhere, my=my, track=track)
@@ -1,3 +1,5 @@
1
+ """I was able to implement the algorithm with JAX, but I didn't see an advantage and it's a pain in the ass.
2
+ I don't maintain this module."""
1
3
  from mapFolding import validateListDimensions, getLeavesTotal, makeConnectionGraph
2
4
  from typing import List, Tuple
3
5
  import jax
@@ -0,0 +1,152 @@
1
+ from mapFolding import indexMy, indexThe, indexTrack
2
+ import ast
3
+ import copy
4
+ import pathlib
5
+
6
+ def getDictionaryEnumValues():
7
+ dictionaryEnumValues = {}
8
+ for enumIndex in [indexMy, indexThe, indexTrack]:
9
+ for memberName, memberValue in enumIndex._member_map_.items():
10
+ dictionaryEnumValues[f"{enumIndex.__name__}.{memberName}.value"] = memberValue.value
11
+ return dictionaryEnumValues
12
+
13
+ class RecursiveInlinerWithEnum(ast.NodeTransformer):
14
+ def __init__(self, dictionaryFunctions, dictionaryEnumValues):
15
+ self.dictionaryFunctions = dictionaryFunctions
16
+ self.dictionaryEnumValues = dictionaryEnumValues
17
+ self.processed = set() # Track processed functions to avoid infinite recursion
18
+
19
+ def inlineFunctionBody(self, functionName):
20
+ if functionName in self.processed:
21
+ return None
22
+
23
+ self.processed.add(functionName)
24
+ inlineDefinition = self.dictionaryFunctions[functionName]
25
+ # Recursively process the function body
26
+ for node in ast.walk(inlineDefinition):
27
+ self.visit(node)
28
+ return inlineDefinition
29
+
30
+ def visit_Attribute(self, node):
31
+ # Substitute enum identifiers (e.g., indexMy.leaf1ndex.value)
32
+ if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name):
33
+ enumPath = f"{node.value.value.id}.{node.value.attr}.{node.attr}"
34
+ if enumPath in self.dictionaryEnumValues:
35
+ return ast.Constant(value=self.dictionaryEnumValues[enumPath])
36
+ return self.generic_visit(node)
37
+
38
+ def visit_Call(self, node):
39
+ callNode = self.generic_visit(node)
40
+ if isinstance(callNode, ast.Call) and isinstance(callNode.func, ast.Name) and callNode.func.id in self.dictionaryFunctions:
41
+ inlineDefinition = self.inlineFunctionBody(callNode.func.id)
42
+ if inlineDefinition and inlineDefinition.body:
43
+ lastStmt = inlineDefinition.body[-1]
44
+ if isinstance(lastStmt, ast.Return) and lastStmt.value is not None:
45
+ return self.visit(lastStmt.value)
46
+ elif isinstance(lastStmt, ast.Expr) and lastStmt.value is not None:
47
+ return self.visit(lastStmt.value)
48
+ return None
49
+ return callNode
50
+
51
+ def visit_Expr(self, node):
52
+ if isinstance(node.value, ast.Call):
53
+ if isinstance(node.value.func, ast.Name) and node.value.func.id in self.dictionaryFunctions:
54
+ inlineDefinition = self.inlineFunctionBody(node.value.func.id)
55
+ if inlineDefinition:
56
+ return [self.visit(stmt) for stmt in inlineDefinition.body]
57
+ return self.generic_visit(node)
58
+
59
+ def findRequiredImports(node):
60
+ """Find all modules that need to be imported based on AST analysis.
61
+ NOTE: due to hardcoding, this is a glorified regex. No, wait, this is less versatile than regex."""
62
+ requiredImports = set()
63
+
64
+ class ImportFinder(ast.NodeVisitor):
65
+ def visit_Name(self, node):
66
+ if node.id in {'numba'}:
67
+ requiredImports.add(node.id)
68
+ self.generic_visit(node)
69
+
70
+ def visitDecorator(self, node):
71
+ if isinstance(node, ast.Call) and isinstance(node.func, ast.Name):
72
+ if node.func.id == 'jit':
73
+ requiredImports.add('numba')
74
+ self.generic_visit(node)
75
+
76
+ ImportFinder().visit(node)
77
+ return requiredImports
78
+
79
+ def generateImports(requiredImports):
80
+ """Generate import statements based on required modules."""
81
+ importStatements = []
82
+
83
+ # Map of module names to their import statements
84
+ importMapping = {
85
+ 'numba': 'import numba',
86
+ }
87
+
88
+ for moduleName in sorted(requiredImports):
89
+ if moduleName in importMapping:
90
+ importStatements.append(importMapping[moduleName])
91
+
92
+ return '\n'.join(importStatements)
93
+
94
+ def inlineFunctions(sourceCode, targetFunctionName, dictionaryEnumValues):
95
+ dictionaryParsed = ast.parse(sourceCode)
96
+ dictionaryFunctions = {
97
+ element.name: element
98
+ for element in dictionaryParsed.body
99
+ if isinstance(element, ast.FunctionDef)
100
+ }
101
+ nodeTarget = dictionaryFunctions[targetFunctionName]
102
+ nodeInliner = RecursiveInlinerWithEnum(dictionaryFunctions, dictionaryEnumValues)
103
+ nodeInlined = nodeInliner.visit(nodeTarget)
104
+ ast.fix_missing_locations(nodeInlined)
105
+
106
+ # Generate imports
107
+ requiredImports = findRequiredImports(nodeInlined)
108
+ importStatements = generateImports(requiredImports)
109
+
110
+ # Combine imports with inlined code
111
+ inlinedCode = importStatements + '\n\n' + ast.unparse(ast.Module(body=[nodeInlined], type_ignores=[]))
112
+ return inlinedCode
113
+
114
+ def Z0Z_inlineMapFolding():
115
+ dictionaryEnumValues = getDictionaryEnumValues()
116
+
117
+ pathFilenameSource = pathlib.Path("/apps/mapFolding/mapFolding/lovelace.py")
118
+ codeSource = pathFilenameSource.read_text()
119
+
120
+ listCallables = [
121
+ 'countInitialize',
122
+ 'countParallel',
123
+ 'countSequential',
124
+ ]
125
+
126
+ listPathFilenamesDestination: list[pathlib.Path] = []
127
+ for callableTarget in listCallables:
128
+ pathFilenameDestination = pathFilenameSource.with_stem(callableTarget)
129
+ codeInlined = inlineFunctions(codeSource, callableTarget, dictionaryEnumValues)
130
+ pathFilenameDestination.write_text(codeInlined)
131
+ listPathFilenamesDestination.append(pathFilenameDestination)
132
+
133
+ listNoNumba = [
134
+ 'countInitialize',
135
+ 'countSequential',
136
+ ]
137
+
138
+ listPathFilenamesNoNumba = []
139
+ for pathFilename in listPathFilenamesDestination:
140
+ if pathFilename.stem in listNoNumba:
141
+ pathFilenameNoNumba = pathFilename.with_name(pathFilename.stem + 'NoNumba' + pathFilename.suffix)
142
+ else:
143
+ continue
144
+ codeNoNumba = pathFilename.read_text()
145
+ for codeLine in copy.copy(codeNoNumba.splitlines()):
146
+ if 'numba' in codeLine:
147
+ codeNoNumba = codeNoNumba.replace(codeLine, '')
148
+ pathFilenameNoNumba.write_text(codeNoNumba)
149
+ listPathFilenamesNoNumba.append(pathFilenameNoNumba)
150
+
151
+ if __name__ == '__main__':
152
+ Z0Z_inlineMapFolding()
@@ -0,0 +1,47 @@
1
+ from typing import Any, Optional, Sequence, Type, Union
2
+
3
+ def Z0Z_makeJob(listDimensions: Sequence[int], **keywordArguments: Optional[Type[Any]]):
4
+ from mapFolding import outfitCountFolds
5
+ stateUniversal = outfitCountFolds(listDimensions, computationDivisions=None, CPUlimit=None, **keywordArguments)
6
+ from mapFolding.countInitialize import countInitialize
7
+ countInitialize(stateUniversal['connectionGraph'], stateUniversal['gapsWhere'], stateUniversal['my'], stateUniversal['the'], stateUniversal['track'])
8
+ from mapFolding import getPathFilenameFoldsTotal
9
+ pathFilenameChopChop = getPathFilenameFoldsTotal(stateUniversal['mapShape'])
10
+ import pathlib
11
+ suffix = pathFilenameChopChop.suffix
12
+ pathJob = pathlib.Path(str(pathFilenameChopChop)[0:-len(suffix)])
13
+ pathJob.mkdir(parents=True, exist_ok=True)
14
+ pathFilenameJob = pathJob / 'stateJob.pkl'
15
+
16
+ pathFilenameFoldsTotal = getPathFilenameFoldsTotal(stateUniversal['mapShape'], pathFilenameJob.parent)
17
+ stateJob = {**stateUniversal, 'pathFilenameFoldsTotal': pathFilenameFoldsTotal}
18
+
19
+ del stateJob['mapShape']
20
+
21
+ import pickle
22
+ pathFilenameJob.write_bytes(pickle.dumps(stateJob))
23
+ return pathFilenameJob
24
+
25
+ def runJob(pathFilename):
26
+ from typing import Final
27
+ import numpy
28
+ from pathlib import Path
29
+ pathFilenameJob = Path(pathFilename)
30
+ from pickle import loads
31
+ stateJob = loads(pathFilenameJob.read_bytes())
32
+
33
+ connectionGraph: numpy.ndarray = stateJob['connectionGraph']
34
+ foldsSubTotals: numpy.ndarray = stateJob['foldsSubTotals']
35
+ gapsWhere: numpy.ndarray = stateJob['gapsWhere']
36
+ my: numpy.ndarray = stateJob['my']
37
+ pathFilenameFoldsTotal: Final[Path] = stateJob['pathFilenameFoldsTotal']
38
+ the: Final[numpy.ndarray] = stateJob['the']
39
+ track: numpy.ndarray = stateJob['track']
40
+
41
+ from mapFolding.countSequentialNoNumba import countSequential
42
+ countSequential(connectionGraph, foldsSubTotals, gapsWhere, my, the, track)
43
+
44
+ print(foldsSubTotals.sum().item())
45
+ Path(pathFilenameFoldsTotal).parent.mkdir(parents=True, exist_ok=True)
46
+ Path(pathFilenameFoldsTotal).write_text(str(foldsSubTotals.sum().item()))
47
+ print(pathFilenameFoldsTotal)